/*
Theme Name: BimmerBase
Description: Каталог оригинальных запчастей BMW — тема под концепцию поиска по номеру.
Author: BimmerBase
Version: 1.0
Text Domain: directparts
*/

:root {
  --paper: #F4F3EE;
  --paper-raised: #FFFFFF;
  --ink: #14171B;
  --steel: #585F55;
  --line: #DCDAD0;
  --blueprint: #0E4438;
  --blueprint-ink: #F0F5F1;
  /* One accent, everywhere — a deep wine tried first (to move off the old
     gold, which read as rusty), but it sat too close to the green's own
     darkness to read as a button on the hero/search-card/header. Amber —
     pulled from the headlight glow in the hero photo — is the single
     accent now, on light backgrounds and dark ones alike; --torque-ink is
     plain --ink (not a brown "ink" twin) so it stays crisp rather than
     repeating the muddy gold-on-brown look of the original gold. */
  --torque: #E8AD53;
  --torque-ink: #14171B;
  --ember: var(--torque);
  --stock: #3C8C5C;
  --error: #B3261E;

  --font-display: 'Archivo', sans-serif;
  --font-body: 'IBM Plex Sans', system-ui, sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, monospace;

  --container: 1180px;
  --radius: 4px;
  --header-height: 68px;
  /* Where the sticky header actually lands: 0 for a logged-out visitor, or
     under WordPress's own fixed admin bar for logged-in staff. Every other
     sticky element (filters, checkout summary) offsets from this, not from
     --header-height alone, so they don't end up hidden under the admin bar. */
  --sticky-top: calc(var(--wp-admin--admin-bar--height, 0px) + var(--header-height));
}

* { box-sizing: border-box; }
body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.55;
  margin: 0;
}
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font-family: inherit; font-size: inherit; }
:focus-visible { outline: 2px solid var(--torque); outline-offset: 2px; }

/* width:100% matters wherever .container sits inside a flex parent (the
   hero section does) — a flex item shrinks to its content's width by
   default, so without this max-width+margin:auto never gets the full row
   to center within and the whole block drifts inward like an island. */
.container { width: 100%; max-width: var(--container); margin: 0 auto; padding: 0 24px; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 800;
  font-stretch: expanded;
  line-height: 1.08;
  letter-spacing: -0.01em;
  margin: 0 0 .5em;
  text-wrap: balance;
}
p { margin: 0 0 1em; }

.eyebrow {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--steel);
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: none;
  border-radius: var(--radius);
  padding: 13px 26px;
  font-weight: 600;
  font-size: 14.5px;
  cursor: pointer;
  transition: transform .12s ease, opacity .12s ease;
}
.btn:hover { opacity: .92; }
.btn:active { transform: translateY(1px); }
.btn-torque { background: var(--torque); color: var(--torque-ink); }
.btn-outline { background: transparent; color: var(--ink); border: 1px solid var(--line); }
.btn-outline:hover { border-color: var(--steel); }

/* ---------------- Site header ---------------- */
/* Solid emerald everywhere now (was a plain white bar) — the wordmark image
   is white/amber and needs a dark backing on every template, not just the
   homepage, so the whole header now shares one dark look site-wide. */
.site-header {
  background: var(--blueprint);
  color: var(--blueprint-ink);
  border-bottom: 1px solid rgba(255,255,255,.12);
  position: sticky;
  /* WordPress's own admin bar is position:fixed at the very top for logged-in
     users (staff/admin) — without this offset our sticky header rides up
     underneath it and ends up half-hidden once you scroll. WP exposes its
     own height as this custom property, 0 when there's no admin bar. */
  top: var(--wp-admin--admin-bar--height, 0px);
  z-index: 40;
  /* Hints the browser to keep this on its own compositor layer ahead of
     time, rather than promoting it reactively mid-scroll — cheap, and the
     standard low-risk mitigation for a fixed/sticky bar visibly tearing
     from the scrolling content during a fast scroll. */
  will-change: transform;
}
.site-logo,
.main-nav a,
.header-search-toggle,
.header-account-link,
.lang-switch a,
.currency-switch a,
.cart-link {
  color: var(--blueprint-ink);
}
.main-nav a:hover { color: var(--ember); }
.header-search-toggle:hover,
.header-account-link:hover { background: rgba(255,255,255,.14); }
.lang-switch a.current,
.currency-switch a.current { background: rgba(255,255,255,.18); color: var(--blueprint-ink); }

/* Home page only: instead of the plain solid bar every other page gets from
   the very top, the header floats transparently over the hero photo until
   scrolled — fixed (not sticky) so the hero can occupy the full viewport
   height behind it. :not(.is-scrolled) is the "at rest over the photo"
   look; once scroll.js adds .is-scrolled it just falls through to the same
   solid glass every other page already has. */
body.home .site-header {
  position: fixed;
  left: 0;
  right: 0;
  background: rgba(14,68,56,.92);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  transition: background .25s ease, border-color .25s ease, backdrop-filter .25s ease;
}
body.home .site-header:not(.is-scrolled) {
  background: transparent;
  border-bottom-color: transparent;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.site-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  /* Longhand on purpose: a "16px 0" shorthand here would zero out the
     left/right padding .container already sets, pulling the logo 24px
     past the site's standard left edge. */
  padding-top: 16px;
  padding-bottom: 16px;
}
/* inline-block + line-height:0, not flex — a flex .site-logo stretched its
   img child to match the row's own cross-axis height (~50px) instead of
   the size actually set via the img's width/height attributes (206x24),
   rendering it nearly 2x too big regardless of what those attributes said. */
.site-logo { display: inline-block; line-height: 0; }
.site-logo img { display: block; }
.main-nav { display: flex; align-items: center; gap: 28px; }
.main-nav ul { list-style: none; display: flex; gap: 24px; margin: 0; padding: 0; }
.main-nav a { font-size: 14.5px; font-weight: 500; white-space: nowrap; }

.header-actions { display: flex; align-items: center; gap: 18px; }
.header-search-toggle {
  display: flex; align-items: center; justify-content: center; width: 34px; height: 34px;
  border: none; background: transparent; cursor: pointer; border-radius: 50%;
  transition: background .12s ease;
}
.header-search-toggle svg { width: 19px; height: 19px; }
.header-account-link {
  display: flex; align-items: center; justify-content: center; width: 34px; height: 34px;
  border-radius: 50%; transition: background .12s ease;
}
.header-account-link svg { width: 20px; height: 20px; }
/* Same dark glass as the header it hangs off, everywhere — the input keeps
   its own light pill (same pattern as the search-card lower down), only
   the surrounding panel and its button are dark. */
.header-search-drop {
  position: absolute; top: 100%; left: 0; right: 0;
  border-bottom: 1px solid rgba(255,255,255,.12);
  background: rgba(14,68,56,.92);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 12px 24px -8px rgb(0 0 0 / 0.25);
}
.header-search-drop[hidden] { display: none !important; }
.header-search-form { display: flex; gap: 10px; padding: 16px 0; max-width: 480px; margin: 0 auto; }
.header-search-form input {
  flex: 1; border: 1px solid var(--line); border-radius: var(--radius); padding: 11px 14px;
  font-family: var(--font-mono); font-size: 14px; background: var(--paper);
}
.header-search-form button {
  border: none; background: var(--ember); color: var(--ink); font-weight: 600;
  padding: 0 20px; border-radius: var(--radius); cursor: pointer;
}
/* Mirrors body.home .site-header exactly, state for state — transparent at
   rest over the photo, same solid glass as every other page once scrolled. */
body.home .site-header:not(.is-scrolled) .header-search-drop {
  background: transparent;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border-bottom-color: transparent;
  box-shadow: none;
}
.lang-switch,
.currency-switch { display: flex; gap: 2px; font-family: var(--font-mono); font-size: 12px; }
.lang-switch a,
.currency-switch a {
  padding: 5px 9px;
  border-radius: 3px;
  text-transform: uppercase;
}
/* A thin divider between the two switchers reads as "two related but
   separate choices" rather than one four-option group. */
.currency-switch { margin-left: 2px; padding-left: 8px; border-left: 1px solid rgba(255,255,255,.2); }
.cart-link { position: relative; display: flex; align-items: center; gap: 6px; font-size: 14px; font-weight: 500; }
.cart-count {
  background: var(--ember);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 11px;
  min-width: 18px;
  height: 18px;
  border-radius: 9px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 4px;
}

/* ---------------- Mobile nav drawer ---------------- */
/* The toggle button itself sits in the normal desktop header markup (far
   left, before the logo) but has no reason to show until the desktop nav
   is what's hidden — kept display:none at the base and only switched on
   inside the <760px block below, alongside everything it's replacing. */
.mobile-menu-toggle {
  display: none;
  align-items: center; justify-content: center; width: 34px; height: 34px;
  border: none; background: transparent; color: var(--blueprint-ink); cursor: pointer;
  border-radius: 50%; transition: background .12s ease; flex-shrink: 0;
}
.mobile-menu-toggle svg { width: 22px; height: 22px; }
.mobile-menu-toggle:hover { background: rgba(255,255,255,.14); }

.mobile-drawer-overlay {
  position: fixed; inset: 0; background: rgba(10,20,17,.55);
  opacity: 0; pointer-events: none; transition: opacity .2s ease; z-index: 60;
}
.mobile-drawer-overlay.is-open { opacity: 1; pointer-events: auto; }

.mobile-drawer {
  position: fixed; top: 0; left: 0; bottom: 0; width: min(320px, 84vw);
  background: var(--paper); color: var(--ink);
  box-shadow: 12px 0 32px -12px rgb(0 0 0 / 0.35);
  transform: translateX(-100%); transition: transform .25s ease;
  z-index: 61; overflow-y: auto;
  display: flex; flex-direction: column;
}
.mobile-drawer.is-open { transform: translateX(0); }
body.drawer-open { overflow: hidden; }

/* Dark, matching the main header — the wordmark PNG itself is white/amber
   (see .site-logo elsewhere), so on the drawer's own light background it
   was nearly invisible; this is the same dark backing the real header
   already gives it, just repeated here for this one strip. */
.mobile-drawer-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 18px 16px; background: var(--blueprint);
}
.mobile-drawer-close {
  border: none; background: transparent; font-size: 26px; line-height: 1;
  color: var(--blueprint-ink); cursor: pointer; padding: 4px 8px; opacity: .85;
}
.mobile-drawer-close:hover { opacity: 1; }

.mobile-drawer-search { display: flex; gap: 8px; padding: 16px; border-bottom: 1px solid var(--line); }
.mobile-drawer-search input {
  flex: 1; min-width: 0; border: 1px solid var(--line); border-radius: var(--radius); padding: 10px 12px;
  font-family: var(--font-mono); font-size: 14px; background: var(--paper-raised); color: var(--ink);
}
.mobile-drawer-search button {
  display: flex; align-items: center; justify-content: center; width: 40px; flex-shrink: 0;
  border: none; background: var(--torque); color: var(--torque-ink); border-radius: var(--radius); cursor: pointer;
}
.mobile-drawer-search button svg { width: 18px; height: 18px; }

.mobile-drawer-nav { padding: 8px 0; border-bottom: 1px solid var(--line); }
.mobile-drawer-nav ul { list-style: none; margin: 0; padding: 0; }
.mobile-drawer-nav a { display: block; padding: 14px 16px; font-size: 15.5px; font-weight: 500; color: var(--ink); }
.mobile-drawer-nav a:hover { background: var(--paper-raised); color: var(--torque); }

.mobile-drawer-foot { display: flex; align-items: center; justify-content: space-between; padding: 16px; margin-top: auto; }
.mobile-drawer-foot a { font-size: 14.5px; font-weight: 500; color: var(--ink); }
.mobile-drawer-foot .lang-switch,
.mobile-drawer-foot .currency-switch { font-size: 12px; }
.mobile-drawer-foot .lang-switch a,
.mobile-drawer-foot .currency-switch a { color: var(--steel); }
.mobile-drawer-foot .lang-switch a.current,
.mobile-drawer-foot .currency-switch a.current { background: var(--paper-raised); color: var(--ink); }
.mobile-drawer-foot .currency-switch { border-left-color: var(--line); }

@media (max-width: 760px) {
  /* position: sticky was still visibly detaching from the top during a
     fast scroll on real phones (the homepage's fixed+backdrop-filter combo
     wasn't the actual cause — this happened on plain sticky-header pages
     too), which points at sticky's own mobile-engine behavior rather than
     any one property here. Fixed positioning is the more predictable,
     widely-relied-on pattern for a "stays at the top" mobile header, so
     this makes every page behave like the homepage already did instead of
     chasing sticky-specific fixes further. Removing it from document flow
     needs body's own padding-top to keep content from jumping up under
     it — except on the homepage, which already renders its hero full-bleed
     behind the floating header on purpose. */
  .site-header { position: fixed; left: 0; right: 0; }
  body:not(.home) { padding-top: var(--sticky-top); }

  .mobile-menu-toggle { display: flex; }
  /* Search and the language switch are both already in the drawer — kept
     off the top bar so it doesn't have to fit five things on one narrow
     row. The account icon stays, alongside cart: both are things a
     returning customer reaches for directly, not by way of the menu. */
  .main-nav,
  .header-search-toggle,
  .lang-switch,
  .currency-switch {
    display: none;
  }
  .site-header-row { gap: 10px; }
  /* Desktop's 246px-wide wordmark plus a burger, account icon and cart
     link no longer all fit on one narrow row — still sized to read
     clearly as the logo, just not at the exact width the wide desktop
     bar has room for. */
  .site-logo img { width: 156px; height: auto; }
  .header-actions { gap: 8px; }

  /* A fixed-position header with backdrop-filter (the homepage's glass
     effect over the hero) is a well-known trigger for mobile Safari/Chrome
     to visibly detach it from the top during a scroll — it can render a
     stale, no-longer-pinned frame of the header floating mid-page until
     the compositor catches up. Blur is what's expensive there; dropping it
     on the phone-width version (a plain, still-tinted background instead)
     removes the trigger instead of fighting the symptom. */
  body.home .site-header,
  body.home .site-header:not(.is-scrolled) {
    background: rgba(14,68,56,.96);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
}

/* ---------------- Hero / search ---------------- */
/* ---- Classic photo hero — straight under the header, no card, no search ---- */
.classic-hero {
  position: relative;
  /* The header floats fixed over this section now (see body.home .site-header
     above), so it no longer reserves its own space above the hero — full
     100vh is the space actually available to the photo. */
  min-height: 100vh;
  display: flex;
  align-items: center;
  color: var(--blueprint-ink);
  /* No overlay tint — the photo itself (grille lit from the left, dark
     paint filling the left third) is what carries the dark-green mood and
     keeps the text legible now. Plain cover, just a small nudge up from
     center so a little less of the empty hood shows at the bottom — the
     150%-zoom version tried earlier cropped in so far it read as
     "stretched" rather than just trimmed. */
  background: var(--blueprint) url('assets/img/hero-engine.jpg') center 8% / cover no-repeat;
}
.classic-hero-inner {
  position: relative;
  padding: 64px 0;
  max-width: 640px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

@media (max-width: 760px) {
  /* 100vh on a tall, narrow phone screen forces background:cover to crop
     hard into the (landscape-shaped) photo to fill all that extra height —
     it reads as an oddly zoomed-in, stretched slice of the grille rather
     than the same shot desktop gets. A shorter box needs a much smaller
     crop to fill it. */
  .classic-hero { min-height: 72vh; background-position: center 15%; align-items: flex-end; }
  .classic-hero-inner { padding: 0 0 56px; }
}

.hero-eyebrow { color: var(--ember); font-family: var(--font-mono); font-size: 12.5px; letter-spacing: .1em; text-transform: uppercase; margin-bottom: 18px; }
.classic-hero h1 {
  /* Was 14ch/62px — narrow enough that the expanded, heavy display font
     forced the first sentence into 3 nearly-equal lines and the whole
     block read as a square instead of a headline. Smaller max size + a
     wider box lets it settle into two natural, uneven lines instead. */
  font-size: clamp(32px, 4.6vw, 52px);
  line-height: 1.28;
  max-width: 560px;
  margin-bottom: 32px;
  text-wrap: balance;
}
.classic-hero h1 .line { display: block; }
.classic-hero h1 .line + .line { font-size: 0.86em; color: var(--ember); margin-top: 10px; }
.hero-cta { padding: 15px 30px; font-size: 15px; }
.btn-ember { background: var(--ember); color: var(--ink); }

/* ---- Search block — its own section below the hero, not layered on the photo ---- */
.search-section { background: var(--paper); padding: 40px 0 8px; }
.search-card {
  position: relative;
  background: var(--blueprint);
  color: var(--blueprint-ink);
  border-radius: 16px;
  padding: 40px 44px 36px;
  box-shadow: 0 24px 48px -24px rgb(0 0 0 / 0.35);
  scroll-margin-top: calc(var(--sticky-top) + 20px);
}
.bracket { position: absolute; width: 26px; height: 26px; border-color: var(--ember); pointer-events: none; }
.bracket.tl { top: 18px; left: 18px; border-top: 2px solid; border-left: 2px solid; }
.bracket.tr { top: 18px; right: 18px; border-top: 2px solid; border-right: 2px solid; }
.bracket.bl { bottom: 18px; left: 18px; border-bottom: 2px solid; border-left: 2px solid; }
.bracket.br { bottom: 18px; right: 18px; border-bottom: 2px solid; border-right: 2px solid; }

.search-card-title { font-size: clamp(18px, 2.2vw, 26px); max-width: 40ch; margin-bottom: 22px; color: var(--blueprint-ink); }

.part-search {
  display: flex; align-items: center; background: var(--paper-raised); border-radius: 12px; overflow: hidden;
  border: 1px solid rgba(255,255,255,.14); transition: box-shadow .15s ease;
}
.part-search:focus-within { box-shadow: 0 0 0 3px rgba(232,173,83,.4); }
.part-search-icon { width: 20px; height: 20px; margin-left: 18px; color: var(--steel); flex-shrink: 0; }
.part-search input {
  /* min-width:0 is the actual fix here: a flex item's default min-width is
     "auto" (its content's natural size), which on a narrow phone screen
     was wider than the space left for it once the icon and button took
     their share — the input refused to shrink and pushed the whole search
     card (and the page under it) wider than the viewport instead. */
  flex: 1; min-width: 0; border: none; background: transparent; padding: 18px 14px; font-family: var(--font-mono);
  font-size: 15.5px; color: var(--ink); outline: none; -webkit-appearance: none; appearance: none;
}
.part-search input::placeholder { color: var(--steel); opacity: .7; }
.part-search button { border: none; background: var(--torque); color: var(--torque-ink); font-weight: 600; padding: 0 30px; align-self: stretch; cursor: pointer; }
.part-search button:hover { opacity: .92; }

@media (max-width: 760px) {
  /* The button's desktop padding (0 30px) alone was eating close to a
     third of the row on a phone screen, leaving barely enough left for the
     input to show more than a few digits of the placeholder before it got
     clipped. Shrinking the button (not the input, which already has
     min-width:0 and would just give up the space right back to it) is
     what actually grows the typing room. */
  .search-card { padding: 28px 20px 26px; }
  .part-search-icon { margin-left: 12px; margin-right: 6px; }
  .part-search input { padding: 15px 10px; font-size: 14px; }
  .part-search button { padding: 0 16px; font-size: 14px; }
}


/* ---------------- Trust strip (homepage) ---------------- */
.trust-strip { background: var(--blueprint); color: var(--blueprint-ink); }
.trust-strip-inner {
  /* space-between let the outer items hug the very edges of the row — on
     screens where the four items don't perfectly fill the container that
     put them past where every other section's content lines up. Centering
     keeps the row itself inset like everything else, however wide it ends
     up being. min-width:0 on the items (below) is what actually lets them
     shrink/wrap instead of overflowing if it's ever a tight fit. */
  display: flex; justify-content: center; flex-wrap: nowrap;
  gap: 28px; padding: 30px 0;
}
.trust-strip-item { display: flex; align-items: center; gap: 14px; font-size: 15.5px; font-weight: 500; min-width: 0; }
.trust-strip-icon {
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 42px; height: 42px; border-radius: 50%;
  background: rgba(232,173,83,.14); border: 1px solid rgba(232,173,83,.3);
}
.trust-strip-item svg { width: 20px; height: 20px; color: var(--torque); flex-shrink: 0; }

@media (max-width: 760px) {
  /* Four items with icon+text each never fit on one un-wrapped row at
     phone width — nowrap (needed on desktop so a near-fit doesn't wrap
     oddly) was instead forcing them to overlap. A 2x2 grid reads better
     here than a wrapped row anyway: even pairs, not a stray 4th item alone
     on its own line. */
  .trust-strip-inner { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px 12px; padding: 24px 16px; }
  .trust-strip-item { font-size: 13px; gap: 10px; }
  .trust-strip-icon { width: 34px; height: 34px; }
  .trust-strip-item svg { width: 16px; height: 16px; }
}

/* ---------------- Process strip ---------------- */
.process {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  margin: 56px 0;
}
.process-step {
  background: var(--paper-raised); border: 1px solid var(--line); border-radius: 10px;
  padding: 32px 28px; box-shadow: 0 2px 0 var(--line); transition: box-shadow .15s ease, transform .15s ease;
}
.process-step:hover { box-shadow: 0 8px 20px -8px rgb(0 0 0 / 0.18); transform: translateY(-2px); }
.process-mark {
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-mono); font-size: 13px; font-weight: 700; letter-spacing: .03em;
  color: var(--torque-ink); background: var(--torque); border-radius: 999px; padding: 5px 14px; margin-bottom: 16px;
}
.process-title { font-family: var(--font-display); font-weight: 700; font-size: 18.5px; margin: 0 0 8px; }
.process-text { font-size: 15.5px; color: var(--steel); margin: 0; line-height: 1.5; }

/* ---------------- Category tiles ---------------- */
.section-title-row { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 20px; gap: 20px; }
/* Catalog page only — tighter than the shared 20px above, which also backs
   the homepage's section headers and doesn't need trimming there. */
.catalog-head .section-title-row { margin-bottom: 2px; }
.section-title-row h2 { font-size: 21px; margin: 0; }
.catalog-title { font-size: 30px !important; }
/* Compact by default — with no chips, the toolbar row is just the sort
   control off on the right, so the same margin the chip-filled state needs
   read as a slab of dead air between the title and the grid. Only the
   "has-chips" state (set in archive-product.php from $has_filters) gets
   the bigger gap, once there's an actual chips row filling it. */
.catalog-toolbar { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px; margin: 0 0 4px; }
.catalog-toolbar.has-chips { margin-bottom: 18px; }
.catalog-sort { display: flex; align-items: center; gap: 10px; flex-shrink: 0; margin-left: auto; }
.catalog-sort .filter-label { margin-bottom: 0; white-space: nowrap; }
.catalog-sort select {
  border: 1px solid var(--line); border-radius: var(--radius); padding: 8px 10px;
  font-family: var(--font-body); font-size: 13.5px; color: var(--ink); background: var(--paper);
}
/* Collapsed height is set in JS (front-page.php's own inline script, right
   after this grid) as the exact pixel offset of the end of the 2nd row —
   auto-fill means the column count (and so which tiles land in row 2)
   depends on the viewport width, so there's no fixed tile count that means
   "two rows" at every width; only a measurement after layout can know it.
   Collapsed by default via this transition so there's still something
   reasonable to animate from before that measurement runs. */
.cat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 18px; margin-bottom: 56px; }
.cat-grid.is-collapsed { overflow: hidden; transition: max-height .25s ease; }
.cat-grid-toggle {
  display: inline-flex; align-items: center; gap: 6px; border: none; background: none; padding: 0;
  font-family: var(--font-mono); font-size: 12px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--steel); cursor: pointer; flex-shrink: 0;
}
.cat-grid-toggle:hover { color: var(--torque); }
.cat-grid-toggle svg { width: 14px; height: 14px; transition: transform .2s ease; }
.cat-grid-toggle[aria-expanded="true"] svg { transform: rotate(180deg); }
.cat-tile {
  display: flex; flex-direction: column; gap: 14px;
  background: linear-gradient(165deg, var(--paper-raised) 0%, var(--paper) 100%);
  border: 1px solid var(--line); border-radius: 14px; padding: 26px 22px 24px;
  box-shadow: 0 1px 2px rgb(0 0 0 / 0.05);
  transition: box-shadow .2s ease, transform .2s ease;
}
/* Hover used to swap the border, a corner glow, AND the icon all to amber
   at once plus scale the icon up — four things firing together read as
   "too much" rather than a single clear signal. One calm, colorless lift
   is the whole hover state now; the icon stays the same green at rest and
   on hover. (position:relative/overflow:hidden above are gone too — they
   only ever existed to position and clip that glow.) */
.cat-tile:hover {
  box-shadow: 0 16px 30px -18px rgb(0 0 0 / 0.22);
  transform: translateY(-3px);
}
.cat-tile-icon {
  display: flex; align-items: center; justify-content: center;
  width: 48px; height: 48px; border-radius: 50%; flex-shrink: 0;
  background: var(--blueprint); color: var(--blueprint-ink);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.1), 0 8px 16px -8px rgba(14,68,56,.55);
}
.cat-tile-icon svg { width: 22px; height: 22px; }
.cat-tile-name { font-weight: 700; font-size: 15.5px; color: var(--ink); }
.cat-tile-count { font-family: var(--font-mono); font-size: 12px; color: var(--steel); }

@media (max-width: 760px) {
  /* auto-fill/minmax(200px,...) only ever fits one column below ~420px —
     every tile stacking full-width top to bottom read as an endless list,
     not a category grid. A fixed 2 columns keeps it looking like one. */
  .cat-grid { grid-template-columns: repeat(2, 1fr); gap: 12px; }
  .cat-tile { padding: 20px 16px 18px; gap: 12px; }
}

/* ---------------- Stock banner (homepage, between categories and popular) ---------------- */
/* The lit wall in the middle of the photo is already the image's own focal
   point — centering the text there instead of the hero's left-aligned
   layout follows what the photo is doing rather than fighting it. */
.stock-banner {
  position: relative;
  min-height: 380px;
  margin-bottom: 56px;
  display: flex; align-items: center; justify-content: center;
  text-align: center;
  color: var(--blueprint-ink);
  background:
    linear-gradient(0deg, rgba(14,68,56,.55) 0%, rgba(14,68,56,.15) 35%, rgba(14,68,56,.15) 65%, rgba(14,68,56,.55) 100%),
    var(--blueprint) url('assets/img/warehouse-banner.jpg') center 38% / cover no-repeat;
}
.stock-banner-inner { max-width: 560px; }
.stock-banner-eyebrow { font-family: var(--font-mono); font-size: 12.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--ember); margin-bottom: 14px; }
.stock-banner h2 { font-size: clamp(26px, 3.4vw, 38px); color: var(--blueprint-ink); margin-bottom: 12px; }
.stock-banner p { font-size: 16px; opacity: .9; margin: 0; }

.catalog-page { padding-top: 40px; }
@media (max-width: 760px) {
  /* body:not(.home) already adds padding-top: var(--sticky-top) to clear
     the fixed mobile header — stacking this 40px on top of that (as
     happened when both applied) read as an oversized gap before the title
     on a screen this short. The fixed-header clearance alone is enough
     room here. */
  .catalog-page { padding-top: 12px; }
}

/* ---------------- Catalog layout (filters + results) ---------------- */
.catalog-layout { display: grid; grid-template-columns: 240px 1fr; gap: 32px; align-items: start; }
.filters {
  background: var(--paper-raised); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 20px; position: sticky;
  /* The site header is itself sticky (~64px tall) — without this offset the
     panel's sticky point sat under the header, so its own top (the "Cena"
     label) was the part that ended up hidden once you scrolled. */
  top: calc(var(--sticky-top) + 16px);
  max-height: calc(100vh - var(--sticky-top) - 16px);
  overflow-y: auto;
}
.filter-group { margin-bottom: 18px; }
.filter-label { display: block; font-size: 11.5px; text-transform: uppercase; letter-spacing: .05em; color: var(--steel); margin-bottom: 8px; }
.filters select, .filters input[type="number"], .filters input[type="text"] {
  width: 100%; border: 1px solid var(--line); border-radius: var(--radius); padding: 9px 10px;
  font-family: var(--font-body); font-size: 13.5px; color: var(--ink); background: var(--paper);
}
.filters input[type="text"] { font-family: var(--font-mono); }
.filter-sku-field { position: relative; }
.filter-sku-field input { padding-right: 30px; }
.filter-sku-clear {
  position: absolute; top: 50%; right: 6px; transform: translateY(-50%);
  width: 22px; height: 22px; display: flex; align-items: center; justify-content: center;
  border: none; background: transparent; color: var(--steel); font-size: 18px; line-height: 1;
  cursor: pointer; border-radius: 50%;
}
.filter-sku-clear:hover { background: var(--paper); color: var(--ink); }
/* The button's own "display: flex" above has the same specificity as the
   browser default "[hidden] { display: none }" — whichever rule comes
   later in the stylesheet wins, so without this the hidden attribute was
   silently losing and the × showed even on an empty field. */
.filter-sku-clear[hidden] { display: none; }
.filter-price-row { display: flex; align-items: center; gap: 8px; }
.filter-price-row input { min-width: 0; }
.filter-price-row span { color: var(--steel); flex-shrink: 0; }
/* Category checkboxes — several can be checked at once, unlike the old
   single-choice dropdown. Scrolls on its own past ~7 rows so a long
   category list doesn't push price/sort out of the visible panel. */
.filter-cat-list { max-height: 224px; overflow-y: auto; display: flex; flex-direction: column; gap: 2px; }
.filter-checkbox {
  display: flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--ink); cursor: pointer;
  padding: 5px 4px; border-radius: 3px;
}
.filter-checkbox:hover { background: var(--paper); }
.filter-checkbox input { width: 16px; height: 16px; accent-color: var(--torque); flex-shrink: 0; }
.filter-checkbox span:first-of-type { flex: 1; }
.filter-cat-count { font-family: var(--font-mono); font-size: 11px; color: var(--steel); }
.filter-apply { width: 100%; justify-content: center; margin-top: 4px; }
.filter-clear { display: block; text-align: center; font-size: 12.5px; color: var(--steel); text-decoration: underline; margin-top: 12px; }
.filter-clear:hover { color: var(--torque); }

/* ---- Active filter chips — what's applied right now, one click to drop it ---- */
.filter-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.filter-chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--paper-raised); border: 1px solid var(--line); border-radius: 999px;
  padding: 6px 12px; font-size: 13px; color: var(--ink); transition: border-color .12s ease;
}
.filter-chip:hover { border-color: var(--torque); }
.filter-chip span { color: var(--steel); font-size: 15px; line-height: 1; }
.filter-chip-clear { color: var(--steel); border-style: dashed; }
.filter-chip-clear:hover { color: var(--torque); }

.empty-state {
  background: var(--paper-raised); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 40px 32px; text-align: center; color: var(--steel);
}
.empty-state-icon { width: 40px; height: 40px; color: var(--line); margin-bottom: 14px; }
.empty-state p { margin-bottom: 18px; }
.empty-state .btn { margin: 0 6px; }

/* Mobile-only trigger for the filters-as-drawer treatment below — same
   shape as a chip so it sits naturally in the toolbar row, hidden until the
   sidebar itself goes off-canvas. */
.catalog-filter-toggle {
  display: none;
  align-items: center; gap: 8px;
  border: 1px solid var(--line); border-radius: 999px; background: var(--paper-raised);
  padding: 8px 14px; font-size: 13.5px; font-weight: 500; color: var(--ink); cursor: pointer;
}
.catalog-filter-toggle svg { width: 16px; height: 16px; flex-shrink: 0; }
.catalog-filter-toggle-count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; padding: 0 4px; border-radius: 9px;
  background: var(--torque); color: var(--torque-ink); font-family: var(--font-mono); font-size: 11px;
}
.filters-mobile-head, .filters-mobile-close { display: none; }
.catalog-filters-overlay {
  display: none;
  position: fixed; inset: 0; background: rgba(10,20,17,.55);
  opacity: 0; pointer-events: none; transition: opacity .2s ease; z-index: 60;
}
.catalog-filters-overlay.is-open { opacity: 1; pointer-events: auto; }

@media (max-width: 760px) {
  .catalog-layout { grid-template-columns: 1fr; }
  .section-title-row { flex-wrap: wrap; }
  /* Filtry on the left, the sort control pinned to the right of the same
     row — chips (if any) are the one thing that can't share it, so they're
     the only child forced onto a row of their own below. */
  .catalog-toolbar { flex-wrap: wrap; }
  .catalog-filter-toggle { display: inline-flex; order: 1; }
  .filter-chips { order: 3; width: 100%; }
  .catalog-sort { order: 2; margin-left: auto; }
  .catalog-sort .filter-label { display: none; }
  .catalog-sort select {
    max-width: 132px; font-size: 12px; padding: 7px 8px;
    white-space: nowrap; text-overflow: ellipsis; overflow: hidden;
  }

  /* The sidebar becomes a left-side off-canvas drawer instead of an endless
     inline scroll above the results — same form, no duplicated markup,
     just repositioned and toggled via catalog-filter-toggle/is-open (see
     the <script> in archive-product.php). */
  .catalog-filters-overlay { display: block; }
  .filters {
    position: fixed; top: 0; left: 0; bottom: 0; width: min(320px, 84vw);
    max-height: none; border: none; border-radius: 0;
    transform: translateX(-100%); transition: transform .25s ease;
    z-index: 61; padding: 0 20px 20px;
  }
  .filters.is-open { transform: translateX(0); }
  .filters-mobile-head {
    display: flex; align-items: center; justify-content: space-between;
    margin: 0 -20px 16px; padding: 18px 20px; border-bottom: 1px solid var(--line);
    font-weight: 700; font-size: 15px; position: sticky; top: 0; background: var(--paper-raised);
  }
  .filters-mobile-close { display: block; border: none; background: transparent; font-size: 26px; line-height: 1; color: var(--steel); cursor: pointer; }
  .filters-mobile-close:hover { color: var(--ink); }
}

/* ---------------- Product grid / cards ---------------- */
.products-grid, ul.products {
  display: grid !important;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)) !important;
  gap: 16px;
  list-style: none;
  margin: 0 0 56px !important;
  padding: 0 !important;
}
.product-card, ul.products li.product {
  background: var(--paper-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px;
  transition: border-color .15s ease, transform .15s ease;
}
.product-card:hover, ul.products li.product:hover { border-color: var(--steel); transform: translateY(-2px); }
/* height:auto (previous fix) closed the side-gaps but let real-photo cards
   and no-photo-yet placeholder cards land at different heights — a fixed
   aspect-ratio box is what makes every card in the grid the same height
   regardless of which one it is. object-fit:cover fills that box edge to
   edge; since real photos already share close to this ratio, cover crops
   only a sliver rather than distorting anything. */
.product-photo {
  width: 100%; aspect-ratio: 4 / 3; background: var(--paper); border-radius: 3px;
  margin-bottom: 14px !important; overflow: hidden;
}
.product-photo img { display: block; width: 100%; height: 100%; object-fit: cover; }
.woocommerce ul.products li.product img {
  height: 130px;
  width: 100%;
  background: var(--paper);
  border-radius: 3px;
  object-fit: contain;
  margin-bottom: 14px !important;
}
/* Branded box photo (see directparts_photo_placeholder()) — same
   .product-photo sizing/crop as a real product image, so it drops into the
   grid without any special-casing beyond this one file swap. */
.product-sku { font-family: var(--font-mono); font-size: 12px; color: var(--steel); margin-bottom: 4px; }
.product-title, .woocommerce ul.products li.product .woocommerce-loop-product__title {
  font-size: 14px !important; font-weight: 500 !important; font-family: var(--font-body) !important;
  line-height: 1.32; margin: 0 0 12px !important; color: var(--ink) !important;
  /* WooCommerce's own bundled stylesheet centers ul.products li.product text
     by default — .product-card doesn't use that markup, but explicit beats
     any such inherited default regardless of exactly where it came from. A
     long title should run the width of the card, not sit centered. */
  text-align: left !important;
}
.product-foot { display: flex; align-items: baseline; justify-content: space-between; }
.product-price, .woocommerce ul.products li.product .price {
  font-family: var(--font-mono) !important; font-weight: 600; font-size: 17px;
  font-variant-numeric: tabular-nums; color: var(--ink) !important;
  /* IBM Plex Mono's space glyph is noticeably wider than its digits, so the
     thousands separator (a plain space, set in WooCommerce's price format
     options) left a gap that read as a typo rather than "1 383" as one
     number. */
  word-spacing: -0.2em;
}
.price-net-label { font-family: var(--font-body); font-size: 11px; font-weight: 500; color: var(--steel); text-transform: uppercase; letter-spacing: .04em; }
/* On the product page the netto note sat between two other gray lines (the
   big price above, "Dostępność..." below) with nothing to set it apart —
   a small tinted pill gives it its own visual weight instead of reading as
   more of the same muted text. */
.single-price .price-net-label {
  display: inline-flex; align-items: baseline; gap: 5px; flex-wrap: nowrap;
  background: rgba(232,173,83,.14); border: 1px solid rgba(232,173,83,.35);
  color: #8A5A12; border-radius: 999px; padding: 4px 10px; margin-top: 2px;
  line-height: 1.3;
}

/* Personal-discount price display (see inc/account-pricing.php): a small
   "-15%" tag, the price without the discount struck through, and the
   discounted price next to it — the familiar sale-price "was / now"
   pattern, so it reads as a clear personal saving rather than just a
   lower number sitting next to an unexplained badge. Wraps the whole
   .product-price / .single-price line so the pieces can drop to a second
   line on a narrow shop-grid card instead of overflowing it. */
.product-price, .single-price { flex-wrap: wrap; row-gap: 4px; }
.product-price { display: inline-flex; align-items: baseline; column-gap: 6px; }
.dp-discount-badge {
  display: inline-flex; align-items: center; font-family: var(--font-body);
  background: rgba(60,140,92,.14); border: 1px solid rgba(60,140,92,.4);
  color: var(--stock); font-weight: 700; font-size: 11px; letter-spacing: .02em;
  border-radius: 999px; padding: 2px 8px; line-height: 1.4;
}
/* Fixed, deliberately small size rather than em-relative — at the single-
   product page's 30px price size, even .6em (18px) still read as a
   second, competing price instead of a clearly secondary one; a flat 13px
   stays quiet in both that context and the 17px shop-grid card price. */
.dp-price-was {
  color: var(--steel); font-weight: 400; text-decoration: line-through;
  font-size: 13px; font-family: var(--font-body);
}
.single-price ins, .product-price ins { text-decoration: none; }
.single-price .price-net-label .woocommerce-Price-amount {
  display: inline-block !important;
  font-weight: 600;
  line-height: inherit;
  /* Explicitly normal, not inherited: word-spacing is inherited as a
     computed length rather than re-evaluated per element, so without this
     the big gross price's -0.2em-of-30px (a literal -6px) would apply here
     too. This pill renders in the body font, not the mono font the big
     price needed correcting for, so its space glyph was never oversized —
     it just needs to not inherit that -6px, not a scaled-down version of it. */
  word-spacing: normal;
}
/* On a grid card the big number IS "the price" — no room to explain it's
   gross, and the netto note right after it read as a continuation of the
   same price rather than a second, smaller figure. Keep that clarification
   for the product page, where there's space to label both explicitly. */
.product-card .price-net-label { display: none; }
.price-gross-label {
  font-family: var(--font-body); font-size: 11px; font-weight: 600; color: var(--steel);
  text-transform: uppercase; letter-spacing: .04em;
}

/*
 * Homepage "Najpopularniejsze" teaser: the query behind it (front-page.php)
 * always asks for 9 products so mobile's fixed 3-column grid gets exactly 3
 * full rows out of it — but the desktop grid just above uses a fluid
 * auto-fill column count that depends on viewport width, and 9 doesn't
 * divide evenly into every column count that can produce (4 columns, for
 * one, leaves a ragged last row of a single card). Desktop gets its own
 * fixed 4-column grid instead of the fluid one, purely so "9 items" and
 * "2 full rows" can both be guaranteed at once — the 9th card is hidden at
 * that width and revealed again once the mobile media query below switches
 * to the 3-column grid it was always meant to fully fill.
 */
body.home .products-grid { grid-template-columns: repeat(4, 1fr) !important; }
body.home .products-grid > .product-card:nth-child(n+9) { display: none; }

@media (max-width: 760px) {
  /* 3 per row instead of stacking to a single column — the auto-fill
     minmax(220px, 1fr) desktop grid above only ever fits one column below
     ~460px viewports. Placed after the desktop card rules on purpose: those
     use !important too, and being declared later is what makes this win. */
  .products-grid, ul.products {
    grid-template-columns: repeat(3, 1fr) !important;
    gap: 8px;
  }
  .product-card, ul.products li.product { padding: 8px; }
  .product-sku { font-size: 9.5px; }
  .product-title, .woocommerce ul.products li.product .woocommerce-loop-product__title {
    font-size: 11.5px !important; margin-bottom: 6px !important; line-height: 1.25;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  }
  .product-price, .woocommerce ul.products li.product .price { font-size: 12.5px; }
  .product-foot { flex-direction: column; align-items: flex-start; gap: 2px; }

  /* "Might also need this" (see single-product.php) always queries exactly
     4 related products — the shared 3-column rule above leaves an orphan
     card alone on its own row. 2x2 is a clean, full grid for exactly 4
     items; declared after the shared rule (and !important, matching it)
     so it wins on specificity-tied selectors. */
  .related-products-grid {
    grid-template-columns: repeat(2, 1fr) !important;
  }

  /* 3x3 = the full 9-item query, no card hidden — the desktop-only cap
     above is scoped outside this media query for exactly this reason. */
  body.home .products-grid {
    grid-template-columns: repeat(3, 1fr) !important;
    gap: 8px;
  }
  body.home .products-grid > .product-card:nth-child(n+9) { display: block; }
  body.home .product-card { padding: 8px; }
  body.home .product-title,
  body.home .woocommerce ul.products li.product .woocommerce-loop-product__title {
    font-size: 11.5px !important; margin-bottom: 6px !important; line-height: 1.25;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  }
  body.home .product-price,
  body.home .woocommerce ul.products li.product .price { font-size: 12.5px; }
}

/* ---------------- Breadcrumbs ---------------- */
.breadcrumbs { font-size: 13px; color: var(--steel); margin: 22px 0 4px; display: flex; gap: 8px; flex-wrap: wrap; }
.breadcrumbs a:hover { color: var(--torque); }
.breadcrumbs span[aria-hidden] { opacity: .5; }
.breadcrumbs span:last-child { color: var(--ink); }

/* ---------------- Single product ---------------- */
.single-product-wrap { display: grid; grid-template-columns: 1.65fr 1fr; gap: 48px; margin: 20px 0 64px; align-items: start; }
.single-photo { background: var(--paper-raised); border: 1px solid var(--line); border-radius: var(--radius); padding: 24px; display: flex; align-items: center; justify-content: center; min-height: 320px; }
.single-sku { font-family: var(--font-mono); font-size: 13.5px; font-weight: 500; color: var(--ink); margin-bottom: 10px; display: flex; align-items: center; gap: 10px; }
.brand-tag { background: rgba(232,173,83,.16); border: 1px solid rgba(232,173,83,.5); border-radius: 3px; padding: 3px 9px; font-size: 10.5px; font-weight: 600; letter-spacing: .04em; color: #8A5A12; }
.single-title { font-size: 28px; margin-bottom: 18px; }
.single-price {
  font-family: var(--font-mono); font-size: 30px; font-weight: 600; margin-bottom: 4px;
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 10px;
}
.single-price .was { color: var(--steel); text-decoration: line-through; font-size: 17px; margin-right: 10px; }
/* Explicit order, independent of source order: the amount first, then our
   own "brutto" label (added right in the template) sits between it and the
   netto note that woocommerce_price_display_suffix appends automatically —
   without this the suffix's own DOM position would land before our label. */
.single-price .woocommerce-Price-amount {
  order: 1;
  /* Scoped to this element (not the shared .single-price container) so it
     computes against ITS OWN font-size — see the matching note on the
     netto pill's amount below for why that distinction matters. */
  word-spacing: -0.2em;
}
.single-price .price-gross-label { order: 2; }
/* woocommerce_price_display_suffix wraps its output in this <small> — that
   element, not the .price-net-label span inside it, is the actual direct
   flex child .single-price sees, so it's what order/flex-basis must target. */
.single-price .woocommerce-price-suffix { order: 3; flex-basis: 100%; }
.single-availability { font-family: var(--font-body); font-size: 13px; color: var(--steel); margin-bottom: 22px; }

.notice-box {
  margin-top: 16px; background: var(--paper-raised); border: 1px solid var(--line); border-left: 3px solid var(--torque);
  border-radius: var(--radius); padding: 14px 16px; font-size: 13px; color: var(--steel); line-height: 1.5;
}
.notice-box a { color: var(--ink); text-decoration: underline; }

.trust-bar { display: flex; flex-direction: column; gap: 10px; margin: 24px 0; padding: 18px 0; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.trust-item { display: flex; align-items: center; gap: 10px; font-size: 13.5px; font-weight: 500; color: var(--ink); }
.trust-item svg { width: 19px; height: 19px; flex-shrink: 0; color: var(--torque); }

/* Its own callout, not folded into a fourth trust-bar line — those are all
   one-liners, and this needs room for a headline plus the two-leg-journey
   explanation underneath it without cramping either. */
.delivery-estimate {
  display: flex; align-items: flex-start; gap: 12px; margin: 0 0 24px;
  padding: 14px 16px; background: var(--paper-raised); border: 1px solid var(--line); border-radius: var(--radius);
}
.delivery-estimate-icon { width: 22px; height: 22px; flex-shrink: 0; color: var(--torque); margin-top: 1px; }
.delivery-estimate-headline { font-size: 14px; font-weight: 700; color: var(--ink); margin-bottom: 3px; }
.delivery-estimate-note { font-size: 12.5px; color: var(--steel); line-height: 1.5; }

.spec-table { width: 100%; border-collapse: collapse; margin: 8px 0 24px; font-size: 13.5px; }
.spec-table th { text-align: left; font-weight: 500; color: var(--steel); padding: 10px 0; width: 40%; border-bottom: 1px solid var(--line); }
.spec-table td { text-align: left; padding: 10px 0; border-bottom: 1px solid var(--line); font-family: var(--font-mono); font-weight: 600; color: var(--ink); }

.single-description { padding-top: 20px; font-size: 14.5px; color: var(--steel); line-height: 1.6; }

/* ---------------- WooCommerce add-to-cart form ---------------- */
form.cart { display: flex; align-items: center; gap: 12px; margin-bottom: 8px; }
form.cart .quantity { margin: 0; }

/* Quantity stepper — a bordered pill with −/+ buttons flanking the number,
   instead of a bare <input type=number> and its cramped native spinner
   arrows. directparts_assets() below injects the buttons via JS onto every
   .quantity WooCommerce renders (product page, cart rows), so this one rule
   covers both. */
.quantity { display: inline-flex; align-items: stretch; border: 1px solid var(--line); border-radius: var(--radius); background: var(--paper-raised); overflow: hidden; }
/* .woocommerce .quantity .qty (WooCommerce's own core CSS, width: 3.631em)
   outranks a bare .quantity .qty by specificity (three classes vs two)
   regardless of source order — silently winning over both this rule and
   its cart-row counterpart further down, clipping any quantity once it
   reached 4 digits (no longer a hard edge case now that the old 20-per-item
   cap is gone). The extra "input" element selector here is what actually
   beats WC's rule; the width itself moved to `ch` units — sized off the
   current font's own digit width — so it always fits exactly 4 digits
   instead of a fixed px guess that assumed 2. box-sizing here is
   border-box (global reset), so the padding has to be added on top of the
   ch value explicitly via calc() — plain `width: 4.5ch` would count that
   padding as part of the 4.5ch itself, leaving barely 2 digits' worth of
   actual room and clipping the same way as before. */
.woocommerce .quantity input.qty {
  width: calc(4.5ch + 8px); padding: 12px 4px; border: none; background: transparent; color: var(--ink);
  font-family: var(--font-mono); font-size: 15px; text-align: center; -moz-appearance: textfield;
}
.quantity .qty::-webkit-inner-spin-button, .quantity .qty::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.quantity .qty-step {
  display: flex; align-items: center; justify-content: center; align-self: stretch;
  box-sizing: border-box; height: auto; margin: 0; border-radius: 0; outline: none;
  /* Native button chrome (appearance: auto by default) draws its own
     platform-specific border/gradient/inset-shadow underneath whatever
     background/border this rule sets — on some browsers that shows through
     as a faint extra edge right where our flat background meets the
     wrapper's border, reading as a stray colour line. Turning it off
     entirely is what actually guarantees a flat fill with nothing behind it. */
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  border: none; background: transparent; color: var(--steel); width: 34px; cursor: pointer;
  font-size: 16px; line-height: 1; transition: background .12s ease, color .12s ease;
}
.quantity .qty-step:focus-visible { box-shadow: inset 0 0 0 2px var(--torque); }
.quantity .qty-step:hover { background: var(--paper); color: var(--ink); }
/* Matches the wrapper's own corner radius directly on whichever button sits
   in that corner — .quantity's overflow:hidden already clips them to this
   shape on its own, but relying on clipping alone left a faint colour seam
   right at the rounded corner while the hover background was transitioning
   in (a compositor quirk: the clip and the animating fill don't always
   repaint in perfect lockstep). Setting the same radius on the button
   itself removes the mismatch instead of just hiding it under the clip. */
.quantity .qty-step:first-child { border-right: 1px solid var(--line); border-radius: var(--radius) 0 0 var(--radius); }
.quantity .qty-step:last-child { border-left: 1px solid var(--line); border-radius: 0 var(--radius) var(--radius) 0; }
.woocommerce a.button, .woocommerce button.button, .woocommerce input.button,
.single_add_to_cart_button, .single_add_to_cart_button.alt, form.cart button[type="submit"] {
  border: none !important; border-radius: var(--radius) !important; background: var(--torque) !important; color: var(--torque-ink) !important;
  font-weight: 600 !important; font-size: 14.5px !important; padding: 14px 28px !important; cursor: pointer;
  transition: opacity .12s ease; text-shadow: none !important; box-shadow: none !important;
}
.woocommerce a.button:hover, .woocommerce button.button:hover, .single_add_to_cart_button:hover { opacity: .92 !important; }
/* The orders table's "View" + "Order again" (see the flex-gap fix on
   .woocommerce-orders-table__cell-order-actions further down this file)
   both inherited the same bright torque FILL as an add-to-cart button —
   fine for one CTA on a whole page, but two of them side by side on EVERY
   row of a long order history is a wall of gold buttons, not emphasis.
   Both outlined now, in the site's own accent color rather than a neutral
   gray, so the pair still reads as "this brand's buttons" — just as a
   border, not a block of fill repeated down the whole list. "Order again"
   (the more affirmative of the two) gets the accent at full strength;
   "View" gets it faded, keeping it the quieter of the pair without
   dropping the accent color entirely. */
.woocommerce a.button.view, .woocommerce a.button.dp-reorder {
  background: var(--paper-raised) !important;
  color: var(--ink) !important;
  font-weight: 500 !important;
  /* A flat outline read as inert next to every other clickable thing on
     this site (product cards, form fields) having at least some depth —
     a quiet shadow at rest, transform+stronger shadow on hover, matches
     the lift .product-card:hover already uses elsewhere in this file. */
  box-shadow: 0 1px 2px rgba(20,23,27,.06) !important;
  transition: box-shadow .15s ease, transform .15s ease, background .15s ease !important;
}
.woocommerce a.button.view { border: 1px solid color-mix(in srgb, var(--torque) 35%, var(--line)) !important; }
.woocommerce a.button.dp-reorder { border: 1.5px solid var(--torque) !important; }
.woocommerce a.button.view:hover, .woocommerce a.button.dp-reorder:hover {
  background: var(--paper) !important; opacity: 1 !important;
  box-shadow: 0 4px 10px rgba(20,23,27,.1) !important; transform: translateY(-1px);
}
.woocommerce a.button.view:active, .woocommerce a.button.dp-reorder:active { transform: translateY(0); box-shadow: 0 1px 2px rgba(20,23,27,.06) !important; }
/* WooCommerce's own CSS draws an icon glyph with `::before`, absolutely
   positioned at 1.5em from the left — it relies on the box keeping its
   default 3.5em left padding to leave room for that icon. Our own padding
   here must reserve the same space, or the icon lands on top of the first
   letters of the text (this is the "symbol on top of text" bug). */
.woocommerce-message, .woocommerce-info, .woocommerce-error {
  background: var(--paper-raised); border: 1px solid var(--line); border-left: 3px solid var(--torque);
  border-radius: var(--radius); padding: 14px 18px 14px 3.5em; font-size: 14px; list-style: none; margin: 20px 0;
  position: relative;
}
/* Re-asserted at doubled specificity (2 classes vs 1) — these render inside
   .page-content (checkout/cart/shop notices all do, since page.php wraps
   the WooCommerce shortcode output in it), and .page-content's own
   `ul, ol { padding-left: 22px; margin: 0 0 16px }` reset is a *tag plus a
   class* (0,1,1), which quietly outranks a bare single-class selector
   (0,1,0) regardless of which one comes later in the file. Doubling the
   class here (0,2,0) wins outright instead of depending on stylesheet
   order — the actual bug this fixes: with the real padding-left
   overridden down to 22px, the icon (positioned assuming the full 3.5em)
   was landing almost on top of the first line's own text. */
.woocommerce-message.woocommerce-message,
.woocommerce-info.woocommerce-info,
.woocommerce-error.woocommerce-error {
  padding: 14px 18px 14px 3.5em; margin: 20px 0;
}
.woocommerce-error { border-left-color: var(--error); margin-bottom: 32px; color: var(--ink); }
.woocommerce-message::before, .woocommerce-info::before, .woocommerce-error::before { left: 1.2em; }
.woocommerce-error li { padding: 2px 0; }

/* ---------------- Cart & checkout tables ---------------- */
.woocommerce-cart table.shop_table, .woocommerce-checkout table.shop_table {
  width: 100%; border-collapse: collapse; margin: 24px 0; font-size: 14.5px;
}
.woocommerce-cart table.shop_table th, .woocommerce-checkout table.shop_table th {
  text-align: left; font-family: var(--font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--steel); border-bottom: 1px solid var(--line); padding: 10px 8px;
}
.woocommerce-cart table.shop_table td, .woocommerce-checkout table.shop_table td {
  border-bottom: 1px solid var(--line); padding: 14px 8px; vertical-align: middle;
}
.woocommerce-cart table.shop_table .product-price, .woocommerce-cart table.shop_table .product-subtotal,
.woocommerce-checkout table.shop_table .amount {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
}
#order_review, .woocommerce-checkout-review-order { background: var(--paper-raised); border: 1px solid var(--line); border-radius: 12px; padding: 20px; }
.woocommerce form .form-row input.input-text, .woocommerce form .form-row select, .woocommerce form .form-row textarea {
  width: 100%; padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--paper-raised); color: var(--ink); font-family: var(--font-body);
}
.woocommerce form .form-row label { font-size: 13px; color: var(--steel); margin-bottom: 4px; display: block; }
#place_order {
  border: none; border-radius: var(--radius); background: var(--torque); color: var(--torque-ink);
  font-weight: 600; font-size: 15px; padding: 15px 30px; cursor: pointer; width: 100%;
}
#place_order:hover { opacity: .92; }

/* ---------------- Static pages (legal, about, contact, delivery) ----------------
   These went through index.php before — no theme template at all, just raw
   HTML at container width with no typography or table styling. That's what
   made pages like the cookie policy look "broken": an unstyled <table> next
   to otherwise-designed pages. */
/* Longhand top/bottom only — this element's other class, .container,
   already sets its own left/right padding (24px, the whole site's
   standard side margin). A "48px 0 80px" shorthand here was silently
   zeroing that back out on every page.php page (this one just adds
   vertical spacing on top of it) — invisible on desktop, where
   .container's own max-width + margin:auto centering creates the visual
   side margin regardless of its padding, but on any viewport narrower
   than that max-width — i.e. every phone — padding is the ONLY thing
   providing a side inset at all, so content read edge-to-edge with zero
   breathing room. */
.page-wrap { padding-top: 48px; padding-bottom: 80px; }
.page-article { max-width: 720px; margin: 0 auto; }
/* Cart and checkout are WordPress pages too (their [woocommerce_cart] /
   [woocommerce_checkout] shortcodes run through this same page.php), so
   they inherited the 720px prose-page width meant for reading text like
   the Terms page — which left no real room for a two-column items+summary
   layout: the fixed-width columns (thumbnail, qty, totals) alone were
   wider than 720px split in half, so the flexible name/description column
   collapsed to 0 and everything else overflowed and got clipped. Both
   need the full container width their own grid layouts (.cart-layout,
   .checkout-layout) were actually designed for. */
/* max-width: none alone used to be enough here, back when .page-article was
   plain block flow — margin: 0 auto only ever centers a block element
   *within* a max-width constraint, so removing the constraint made the auto
   margins a harmless no-op. That stopped being true once .page-article also
   became a flex item (the sticky-footer column chain, added later): a flex
   item's auto margins claim free space on the cross axis regardless of
   max-width, shrinking the item down to its content's own width and
   centering *that* — which is exactly the "title floating in the middle of
   a mostly-empty page" bug on a short page like an empty cart, where there's
   little content to force the width back out. Zeroing the margin here too
   is what actually gets back the intended edge-to-edge width. */
/* My Account never got added here when it was first built — same problem
   as cart/checkout above and the same fix: it's a dashboard with a nav +
   card grid (.myaccount-layout), not prose, and the 720px cap was
   squeezing that grid down into a narrow, off-center column with the
   rest of the (much wider) page sitting empty on both sides. */
.woocommerce-cart .page-article, .woocommerce-checkout .page-article, .woocommerce-account .page-article { max-width: none; margin: 0; }
/* Same bug, same fix, one more page nobody had added to this list yet: the
   Contact page's two-column .contact-split grid was squeezed into this
   720px prose cap exactly like cart/checkout/account used to be — every
   width/ratio/padding tweak made to .contact-split itself was happening
   *inside* that already-too-narrow box, which is why none of them visibly
   moved anything on a wide screen. :has() targets it by what's actually
   inside the page rather than a hardcoded page ID, so this keeps working
   if the Contact page ever gets recreated/duplicated. */
.page-article:has(.contact-split) { max-width: none; margin: 0; }
.page-title { font-size: clamp(28px, 4vw, 38px); margin-bottom: 32px; }
.page-content { font-size: 15px; line-height: 1.7; color: var(--ink); }
.page-content h2 { font-size: 21px; margin: 40px 0 14px; }
.page-content h2:first-child { margin-top: 0; }
.page-content h3 { font-size: 17px; margin: 28px 0 10px; }
.page-content p { margin: 0 0 16px; }
.page-content ul, .page-content ol { margin: 0 0 16px; padding-left: 22px; }
.page-content li { margin-bottom: 6px; }
.page-content a { color: var(--torque-ink, var(--ink)); text-decoration: underline; text-decoration-color: var(--torque); text-underline-offset: 2px; }
.page-content strong { color: var(--ink); }
.page-content table {
  width: 100%; border-collapse: collapse; margin: 8px 0 28px; background: var(--paper-raised);
  border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; font-size: 14px;
}
.page-content th, .page-content td { text-align: left; padding: 12px 16px; border-bottom: 1px solid var(--line); vertical-align: top; }
.page-content tr:last-child th, .page-content tr:last-child td { border-bottom: none; }
/* Only a real <thead> gets the "column header" look — a plain <table><tr>
   with no <thead> (e.g. the label/value rows on the Kontakt page) has no
   row that's semantically different from the rest, so tr:first-child here
   used to single one out and make it look like a mistake. */
.page-content thead th {
  font-family: var(--font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--steel); background: var(--paper);
}

/* ---------------- Contact form (Kontakt page) ---------------- */
/* Was an even 1fr/1fr split with a 56px gap — on this page's 1180px
   container that leaves each column ~540px, but the form's own inputs
   (width:100% of their column) and the info side's Email/Phone/Business
   hours/Address table both read as noticeably narrower and more cramped
   than either needs to be. Form gets slightly more room (it's the side
   with actual input fields to fill), info keeps enough width for its
   table's longer values ("[company address to be added]") to sit on one
   line instead of wrapping awkwardly, and the smaller gap gives both a
   little more width without widening the page itself. */
.contact-split { display: grid; grid-template-columns: 1.15fr 1fr; gap: 32px; align-items: start; margin: 8px 0 40px; }
/* A slightly wider ratio alone (the previous pass) barely reads as a
   change — both sides were still just plain text sitting on the same bare
   background with nothing marking where one block ends and the other
   starts, which is the actual "all mashed together" feeling. Giving each
   side the same card treatment already used across the site (dashboard
   stat tiles, address cards) is what actually separates them. */
.contact-form-wrap, .contact-split .contact-info {
  background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 28px 32px; margin: 0;
}
.contact-form .form-row input.input-text,
.contact-form .form-row textarea.input-text { padding: 13px 16px; background: var(--paper-raised); }
.contact-split .contact-info table { margin: 16px 0; }
.contact-split .contact-info th, .contact-split .contact-info td { border-bottom-color: var(--line); }
@media (max-width: 780px) {
  .contact-split { grid-template-columns: 1fr; gap: 16px; }
  .contact-form-wrap, .contact-split .contact-info { padding: 22px; }
}
.contact-form-notice { padding: 12px 16px; border-radius: var(--radius); font-size: 14px; margin-bottom: 18px; }
.contact-form-notice-success { background: rgba(60,140,92,.12); color: #1F5C3A; border: 1px solid rgba(60,140,92,.35); }
.contact-form-notice-error { background: rgba(179,38,30,.08); color: var(--error); border: 1px solid rgba(179,38,30,.3); }
.contact-form .form-row input.input-text,
.contact-form .form-row textarea.input-text { width: 100%; }
.contact-form button { margin-top: 4px; }

/* ---------------- Footer ---------------- */
.site-footer { background: var(--blueprint); color: var(--blueprint-ink); margin-top: 64px; padding: 48px 0 28px; }
/* Cart is a conversion funnel page, not a browsing one — footer nav
   (catalog links, legal pages, "o nas"...) is a set of exits from it with
   no upside, the standard reasoning most stores use to drop the footer
   specifically here (Onninen's own cart has none either). It's a sharper
   problem on mobile once the totals bar is pinned to the bottom of the
   viewport: scrolling this far still surfaces the real footer sitting
   right above that pinned bar, so "place order" ends up look glued to
   unrelated site links instead of to the order it's actually next to. */
.woocommerce-cart .site-footer, .woocommerce-checkout .site-footer { display: none; }
.footer-grid { display: grid; grid-template-columns: 2fr 1fr 1fr; gap: 32px; margin-bottom: 32px; }
.footer-grid-4 { grid-template-columns: 1.6fr 1fr 1fr 1fr; }
.footer-grid h4 { font-size: 13px; text-transform: uppercase; letter-spacing: .08em; font-family: var(--font-mono); font-weight: 500; opacity: .7; margin-bottom: 14px; }
.footer-grid ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; font-size: 14px; }
.footer-grid a:hover { color: var(--torque); }
.footer-tagline { opacity: .78; max-width: 34ch; font-size: 14px; margin-bottom: 14px; }
.footer-bottom { border-top: 1px solid rgba(255,255,255,.14); padding-top: 20px; font-size: 12.5px; opacity: .65; }
.footer-bottom-sep { margin: 0 8px; }

/* ---------------- Cookie consent banner ---------------- */
.cookie-banner {
  position: fixed; left: 20px; right: 20px; bottom: 20px; z-index: 100;
  max-width: 720px; margin: 0 auto;
  background: var(--paper-raised); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: 0 8px 28px rgba(0,0,0,.14);
  padding: 18px 20px; display: flex; align-items: center; justify-content: space-between; gap: 20px; flex-wrap: wrap;
}
/* The [hidden] attribute and a class selector both carry specificity (0,1,0)
   — whichever rule loads last in the cascade wins a tie, which was silently
   overriding hidden with our own unconditional `display: flex` above. */
.cookie-banner[hidden] { display: none !important; }
.cookie-banner-text { font-size: 13.5px; color: var(--steel); flex: 1; min-width: 220px; }
.cookie-banner-text a { color: var(--ink); text-decoration: underline; }
.cookie-banner-actions { display: flex; gap: 10px; flex-shrink: 0; }
.cookie-banner .btn { padding: 10px 18px; font-size: 13.5px; }

/* ==================================================================
   Cart page — woocommerce/cart/cart.php replaces WooCommerce's default
   single <table> (which a generic table.shop_table rule further down —
   meant for the sidebar totals table and checkout's review table — was
   losing a specificity fight over, since .woocommerce-cart table.shop_table
   below is more specific and applied its plainer, older values instead of
   the nicer ones) with a real two-column layout matching checkout.php:
   items on the left, sticky totals on the right. Every woocommerce_* hook
   the default template fires is still called, so coupons, quantity
   updates and totals calculation all keep working exactly as before.
   ================================================================== */
/* .page-wrap, not the bare .container class — header and footer also use
   .container for their own inner row (site-header-row, footer's own div),
   so targeting .container unscoped was inflating THEIR padding too on
   every cart/checkout page, not just the actual content wrapper. */
.woocommerce-cart .page-wrap, .woocommerce-checkout .page-wrap { padding-top: 40px; }
/* Cart (both the item list and the empty state) and checkout now both end
   on .dp-mini-footer, not blank page background — this used to be leftover
   space from before either had a footer, reading as the dark bar floating
   short of the page's actual bottom instead of sitting flush against it. */
.woocommerce-cart .page-wrap, .woocommerce-checkout .page-wrap { padding-bottom: 0; }
@media (max-width: 760px) {
  /* This 40px stacks on top of the fixed mobile header's own offset
     (body:not(.home) already adds padding-top: var(--sticky-top) so
     content clears it) — the two together read as a much bigger gap
     above the title than intended, since the extra 40px was really sized
     for desktop's roomier layout. 24px (the site's standard spacing unit,
     also .container's own side padding) is the harmonious middle ground:
     enough breathing room above the title, without stacking back into the
     oversized gap the 40px caused. */
  .woocommerce-cart .page-wrap, .woocommerce-checkout .page-wrap { padding-top: 24px; }
}

.page-title-row {
  display: flex; align-items: center; justify-content: space-between; gap: 24px; flex-wrap: wrap;
  margin-bottom: 32px;
}
.page-title-row .page-title { margin-bottom: 0; }
.checkout-steps {
  display: flex; align-items: center; gap: 10px; flex-shrink: 0;
}
.checkout-step { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }
.checkout-step-num {
  display: flex; align-items: center; justify-content: center; width: 28px; height: 28px; flex-shrink: 0;
  border-radius: 50%; font-family: var(--font-mono); font-size: 13px; font-weight: 700;
  background: var(--paper-raised); border: 1.5px solid var(--line); color: var(--steel);
}
.checkout-step-label { font-size: 13.5px; color: var(--steel); white-space: nowrap; }
/* flex: 0 0 Npx, not 1 1 Npx — being an empty element with nothing to set
   a minimum size, this was the first thing the flex algorithm shrank
   whenever the row got remotely tight (the text-bearing step labels next
   to it have their own words as a floor and don't budge nearly as
   easily), collapsing it to 0 width and erasing the connecting line
   entirely well before the row was actually out of room. Fixed at 32px
   and non-shrinking, it always renders; if space is genuinely too tight
   for the whole row, .page-title-row's own wrap drops the steps below the
   title instead, rather than this line quietly vanishing on its own. */
.checkout-step-line { flex: 0 0 32px; height: 1.5px; background: var(--line); }
.checkout-step-line.is-done { background: var(--torque); }
.checkout-step-current .checkout-step-num { background: var(--torque); border-color: var(--torque); color: var(--torque-ink); }
.checkout-step-current .checkout-step-label { color: var(--ink); font-weight: 600; }
.checkout-step-done .checkout-step-num { background: var(--torque); border-color: var(--torque); color: var(--torque-ink); }
.checkout-step-done .checkout-step-label { color: var(--ink); }
/* Below 760px: title on its own row, steps centred on their own row under
   it — the two were still sharing one row via .page-title-row's own
   flex-wrap fallback, which only wrapped the *whole* steps block below
   the title once it ran out of room, with nothing to stop it clipping /
   overflowing off the right edge right up to that point. Explicitly
   stacked and centred instead, with the steps sized down (smaller circles,
   tighter gaps, a shorter connecting line) — the room a dedicated row
   frees up is exactly what makes keeping the text labels here possible at
   all, instead of numbers-only. */
@media (max-width: 760px) {
  /* Slightly more room between the title and the steps than 10px gave it,
     but less below the steps than the shared 32px (that value was sized
     for desktop, where the steps sit inline next to the title instead of
     stacked under it) — the steps row was reading too tight against
     "Koszyk" above it and too loose against the toolbar/items below it. */
  .page-title-row { flex-direction: column; align-items: flex-start; gap: 16px; margin-bottom: 10px; }
  /* Number on top, label wrapped underneath, inside each step's own
     column — not a single-line row of circle+label anymore. That row
     could only ever fit all three full labels by either shrinking them
     illegibly small or scrolling sideways to reach the later ones
     (both tried, neither read as "done" rather than a workaround); a
     step's own label wrapping to two short lines under its circle fits
     naturally at a normal, readable size with nothing cut off or hidden
     behind a scroll. */
  .checkout-steps { width: 100%; align-items: flex-start; gap: 2px; }
  .checkout-step {
    flex: 1 1 0; min-width: 0; flex-direction: column; align-items: center; gap: 6px;
  }
  .checkout-step-label { font-size: 11px; white-space: normal; text-align: center; line-height: 1.25; }
  /* Sits beside the circles, not the labels below them — align-self here
     (rather than the step's own align-items:center) is what keeps it at
     circle height instead of drifting down to the row's full, label-
     inclusive height. margin-top nudges it down to the circle's own
     vertical centre (half of .checkout-step-num's 22px). */
  .checkout-step-line { flex: 1 1 auto; align-self: flex-start; margin-top: 11px; }
  /* var(--line) reads as almost invisible against the mobile page
     background at this thin 1.5px height — the desktop steps sit right
     next to the title where a faint connector is enough, but here it's a
     dedicated row on its own with more surrounding blank space, and the
     line was blending into the background rather than reading as a
     connector at all. Not switched to --steel outright (too heavy for a
     decorative line) — a partial-opacity version of it keeps the same
     hue, just visible. */
  .checkout-step-line:not(.is-done) { background: rgba(88, 95, 85, .35); }
}

.cart-layout { display: grid; grid-template-columns: 2.3fr 1fr; gap: 48px; align-items: start; }
.cart-main { min-width: 0; }
.cart-summary { min-width: 0; }
/* Desktop-only closing line for the page (see the comment in cart.php next
   to .dp-mini-footer for why the real site footer is dropped here
   entirely) — display:none by default, switched on above 760px below;
   mobile has no spare room for it under the pinned totals bar.
   Full-bleed like the real .site-footer: that element gets full width for
   free by living as a direct sibling of body outside .page-wrap, but this
   one is stuck rendering from inside the WooCommerce shortcode's output,
   nested deep inside .container.page-wrap — so it has to break out of that
   ancestor's max-width/padding itself via the 100vw/-50vw trick, with an
   inner wrapper reinstating .container's own max-width+padding for the
   actual content. body.woocommerce-cart gets overflow-x:hidden below to
   absorb the sub-pixel width mismatch that trick causes whenever a
   vertical scrollbar is present. */
.dp-mini-footer { display: none; }
@media (min-width: 761px) {
  .dp-mini-footer {
    display: block; position: relative; left: 50%; right: 50%;
    width: 100vw; margin-left: -50vw; margin-right: -50vw;
    margin-top: 40px; background: var(--blueprint); color: var(--blueprint-ink);
  }
  .dp-mini-footer-inner {
    max-width: var(--container); margin: 0 auto; padding: 20px 24px;
    display: flex; align-items: center; justify-content: space-between; gap: 16px;
    font-family: var(--font-mono); font-size: 14px;
  }
  .dp-mini-footer-brand { display: flex; align-items: center; gap: 12px; }
  .dp-mini-footer-brand img { display: block; height: 18px; width: auto; }
  .dp-mini-footer-copy { opacity: .75; }
  .dp-mini-footer-trust { display: flex; align-items: center; gap: 6px; opacity: .85; }
  .dp-mini-footer-trust svg { width: 16px; height: 16px; }
}
body.woocommerce-cart, body.woocommerce-checkout { overflow-x: hidden; }
/* Sticky footer: on a short cart (few line items, page shorter than the
   viewport), .dp-mini-footer was ending wherever the content happened to
   stop — nowhere near the bottom of the screen, with the page's own paper
   background filling the rest of the viewport below it, reading as "not
   attached to the bottom" (removing .page-wrap's own trailing padding
   fixed the *long*-page case, where the footer already reached past the
   fold, but did nothing for a short one). Standard sticky-footer stack: a
   flex column the full height of the viewport, with the piece of content
   that should absorb any leftover space (.cart-layout / .cart-empty-state)
   set to flex:1 so it grows to push everything after it — the footer
   included — down to the true bottom, while still scrolling normally past
   it once real content exceeds the viewport height. */
body.woocommerce-cart, body.woocommerce-checkout { display: flex; flex-direction: column; min-height: 100vh; }
body.woocommerce-cart .site-header, body.woocommerce-checkout .site-header { flex-shrink: 0; }
body.woocommerce-cart .page-wrap, body.woocommerce-checkout .page-wrap { flex: 1 0 auto; display: flex; flex-direction: column; }
/* .cart-page isn't actually a direct child of .page-wrap — page.php wraps
   the shortcode output in .page-article > .page-content > .woocommerce
   first — so flex:1 on .cart-page alone was a no-op: flex-grow only does
   anything on an item whose own direct parent is a flex container, and
   none of those three intermediate wrappers were. Every link in that
   chain needs to pass the stretch down for it to actually reach cart-page
   (this is also why .page-wrap's own bottom lined up with the viewport
   correctly already — it IS page-wrap's direct flex child — while
   .cart-page kept sizing to its own content several levels further in).
   Checkout's own .checkout-layout (the <form> itself) doesn't need this
   same extra step — it IS a direct child of .woocommerce already, no
   intermediate "page" wrapper of its own the way cart.php has one. */
body.woocommerce-cart .page-article, body.woocommerce-checkout .page-article,
body.woocommerce-cart .page-content, body.woocommerce-checkout .page-content,
body.woocommerce-cart .woocommerce, body.woocommerce-checkout .woocommerce {
  flex: 1 0 auto; display: flex; flex-direction: column;
}
body.woocommerce-cart .cart-page { flex: 1 0 auto; display: flex; flex-direction: column; }
/* Desktop only — .dp-mini-footer itself is desktop-only (mobile has no
   room for it under the pinned totals bar), so there's nothing for this
   push to accomplish on mobile. Growing .cart-layout there is harmless
   (it has no visible background/border of its own, so the extra space is
   invisible). .cart-empty-state very much DOES have both a border and a
   background, so it must never get flex-grow itself — that stretches the
   bordered white card into a huge mostly-empty box instead of the small
   card it's meant to be. Auto top/bottom margins center it in whatever
   leftover space there is instead, keeping its own height natural while
   still pushing .dp-mini-footer down to the true bottom (only one thing
   in the column claims the free space either way). */
@media (min-width: 761px) {
  body.woocommerce-cart .cart-layout,
  body.woocommerce-checkout .checkout-layout { flex: 1 0 auto; }
  /* max-width + horizontal margin:auto is the same flex auto-margin
     centering trick as .dp-mini-footer's own fix above, just on the cross
     axis: it keeps the card itself compact instead of stretching
     edge-to-edge now that .page-article is no longer artificially narrowed
     (see the .page-article margin fix above — that fix widened the whole
     page back out, which would have otherwise stretched this card into the
     same "giant white bar" bug visible before *that* fix, just wider
     instead of taller).
     Centering it vertically too (auto on all four sides) was a second try
     that made a different problem: true dead-center of the *entire*
     leftover viewport reads as "a small box lost in a mostly-empty page",
     not as a deliberate layout. A fixed top gap plus auto on the bottom
     only anchors the card just below the title instead — normal reading
     position — while the bottom auto margin still absorbs all the
     remaining space and keeps .dp-mini-footer pinned to the true bottom. */
  body.woocommerce-cart .cart-empty-state { max-width: 480px; margin: 64px auto auto; }
}
/* Checkout has a state .checkout-layout doesn't cover: an empty cart (e.g.
   after placing an order, then going back) makes WooCommerce's own
   class-wc-shortcode-checkout.php bail out before ever rendering
   form-checkout.php at all — so .checkout-layout above is simply absent,
   and .woocommerce is left with nothing but a bare notice (".Sorry, your
   session has expired") directly followed by .dp-mini-footer, neither of
   which grows — same "footer stuck right under short content" bug, just
   with no specific class to target this time. Fix generically instead of
   chasing every notice/edge-case template: grow whatever invisible wrapper
   div(s) .woocommerce always prints (.woocommerce-notices-wrapper, emitted
   unconditionally by several woocommerce_before_checkout_form_* hooks even
   with nothing to show) rather than the notice box itself — growing the
   visible .woocommerce-error/.woocommerce-message/.woocommerce-info bordered
   box directly would stretch that box itself to fill the whole page instead
   of just adding blank space below it. */
@media (min-width: 761px) {
  body.woocommerce-checkout .woocommerce > *:not(.dp-mini-footer):not(.woocommerce-error):not(.woocommerce-message):not(.woocommerce-info) { flex: 1 0 auto; }
}
/* A faint tint of the header's own dark green (--blueprint-ink is that
   green's very light tint, already used as text-on-dark elsewhere) instead
   of the plain white the item cards use — enough to read as "the one that
   matters" at a glance, without turning it into a whole dark card. */
.cart-summary-sticky {
  position: sticky; top: calc(var(--sticky-top) + 16px); background: var(--blueprint-ink); border: 1px solid rgba(14,68,56,.14);
  border-radius: 12px; padding: 24px; box-shadow: 0 2px 0 rgba(14,68,56,.1);
}
.cart-summary-sticky .cart_totals { border: none; background: transparent; padding: 0; box-shadow: none; }

/* Brutto (what's actually due) is the one figure that needs to read
   instantly — big, bold, in the brand colour. VAT and netto are supporting
   detail underneath, shrinking in that order: VAT smallest (it's the
   least anyone needs to act on), netto a step up since B2B buyers often
   want it for their own accounting. */
.totals-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.totals-row + .totals-row { margin-top: 6px; }
.totals-label { color: var(--steel); }
.totals-value { white-space: nowrap; }
/* Label and value used to share one row (like every other .totals-row),
   competing for the same line — fine for the small VAT/Netto figures, but
   a large brutto total at this row's own big 26px font had nowhere left to
   go and wrapped mid-number (and dragged the label onto two lines with it,
   squeezed down to almost nothing). Stacking label above value instead
   gives the number the *entire* card width to lay out on — the fix isn't
   really "let the card grow to fit the number" (that'd mean the checkout's
   two-column grid resizing itself off one row's content, which fights the
   whole layout), it's "give this one row all the width the card already
   has" instead of half of it. font-size: clamp() is a second line of
   defence for a genuinely extreme total (thousands of units) even the
   full card width would struggle with — it only ever shrinks the number,
   never grows past the normal 26px. */
.totals-row-brutto { flex-direction: column; align-items: flex-start; gap: 2px; margin-bottom: 4px; }
.totals-row-brutto .totals-label { font-size: 16px; font-weight: 700; color: var(--ink); }
.totals-row-brutto .totals-value { font-size: clamp(18px, 5vw, 26px); font-weight: 800; color: var(--torque); font-family: var(--font-mono); display: block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
.totals-row-vat .totals-label,
.totals-row-vat .totals-value { font-size: 12px; color: var(--steel); font-family: var(--font-mono); }
.totals-row-netto .totals-label { font-size: 13.5px; }
.totals-row-netto .totals-value { font-size: 15.5px; font-weight: 600; color: var(--ink); font-family: var(--font-mono); }

.totals-shipping-table { width: 100%; border: none; margin: 10px 0 0; }
.totals-shipping-table td, .totals-shipping-table th {
  padding: 0; border: none; font-size: 13px; text-align: left; font-weight: 400;
}
.totals-shipping-table td { text-align: right; }

.totals-recap {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line);
  font-size: 12.5px; color: var(--steel); font-family: var(--font-mono);
}
.totals-recap-total { color: var(--ink); }
.totals-recap-total strong { font-weight: 700; }
/* Same messages as the product page's .trust-bar, tighter for the narrower
   summary card — no top/bottom rule (already inside a bordered card), and
   the icon shrunk down so three lines don't visually outweigh the total. */
.trust-bar-compact {
  margin: 18px 0 0; padding: 16px 0 0; border-top: 1px solid var(--line); border-bottom: none; gap: 8px;
}
.trust-bar-compact .trust-item { font-size: 12.5px; }
.trust-bar-compact .trust-item svg { width: 16px; height: 16px; }
/* #place_order (right above this, via woocommerce_review_order_after_submit
   in the same .form-row.place-order wrapper) computes as floated — not from
   any rule in this file or WooCommerce's own CSS that a full selector-by-
   selector search turns up, so whatever's actually setting it stayed
   unidentified, but the effect is unambiguous: a floated previous sibling
   with nothing to clear it collapses this block down to zero width instead
   of the full card width, which is what was actually behind both the
   "icons lost under the button" (its own start now painting over/beside
   the float instead of below it) and the "text crammed into a thin column"
   (three words per line instead of the card's real width) look. clear:both
   is the standard, harmless-either-way fix for exactly this regardless of
   which rule is the actual source. */
.dp-checkout-trust { clear: both; width: 100%; }

.cart-continue-shopping {
  display: inline-flex; align-items: center; gap: 6px; margin-top: 16px; font-size: 13.5px;
}

/* Brief dim while a quantity change's AJAX round-trip is in flight — the
   whole block gets replaced wholesale a moment later, so this only needs to
   read as "something's happening", not track precise loading boundaries. */
.cart-page.is-updating { opacity: .55; pointer-events: none; transition: opacity .15s ease; }

.cart-toolbar {
  display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; padding: 0 2px;
}
.cart-toolbar-count { font-size: 12.5px; color: var(--steel); font-family: var(--font-mono); }
.cart-toolbar-actions { display: flex; align-items: center; gap: 18px; }
.cart-toolbar-pdf {
  border: none; background: none; padding: 0; cursor: pointer; font-family: inherit;
  font-size: 12.5px; color: var(--steel); text-decoration: underline;
}
.cart-toolbar-pdf:hover { color: var(--ink); }
.cart-toolbar-pdf:disabled { cursor: default; opacity: .6; text-decoration: none; }
.cart-toolbar-clear { font-size: 12.5px; color: var(--steel); text-decoration: underline; }
.cart-toolbar-clear:hover { color: var(--error); }
.cart-toolbar-clear.is-confirming { color: var(--error); font-weight: 600; }

/* The print/PDF-export sheet (#dp-cart-export in cart.php) — display:none
   at rest. The @media print block at the bottom of this file is the only
   place that ever shows it (display:block there, alongside hiding
   everything else on the page) — an actual browser print or "save as
   PDF" is the only time this needs to be visible at all, so there's no
   JS-driven show/hide step to get wrong. */
.dp-export-sheet {
  display: none; width: 780px; background: #fff; color: #14171B;
  font-family: var(--font-body); box-sizing: border-box; border: 1px solid #ddd;
}
.dp-export-header {
  display: flex; align-items: center; justify-content: space-between; gap: 24px;
  background: var(--blueprint); padding: 20px 32px;
}
/* Scoped under #dp-cart-export, not just .dp-export-logo alone — WooCommerce's
   own stylesheet has ".woocommerce img { height: auto; max-width: 100%; }"
   (1 class + 1 element), which out-specifics a bare single-class selector
   here the same way it did for .cart-row-remove and the checkout button
   earlier — the logo was rendering at ~3.5x its intended size, stretched
   to the header's full width via that rule's own max-width:100%/height:auto
   instead of the fixed 22px height meant for it. */
#dp-cart-export .dp-export-logo { display: block; height: 22px; width: auto; }
.dp-export-header-meta { text-align: right; }
.dp-export-doc-title { font-family: var(--font-display); font-size: 15px; font-weight: 700; color: var(--blueprint-ink); }
.dp-export-doc-date { font-size: 11px; color: var(--blueprint-ink); opacity: .75; margin-top: 2px; }

.dp-export-table { width: 100%; border-collapse: collapse; margin-top: 22px; }
.dp-export-table th {
  text-align: left; font-size: 10.5px; text-transform: uppercase; letter-spacing: .04em; color: #666;
  border-bottom: 1px solid #ddd; padding: 14px 8px 10px; font-weight: 600; background: #fafaf8;
}
.dp-export-table th:first-child { padding-left: 32px; }
.dp-export-table th:last-child { padding-right: 32px; }
.dp-export-table td { padding: 14px 8px; border-bottom: 1px solid #eee; vertical-align: middle; }
.dp-export-table tr:last-child td { border-bottom: none; }
.dp-export-table td:first-child { padding-left: 32px; }
.dp-export-table td:last-child { padding-right: 32px; }
/* Faint zebra striping — an aid for the eye tracking one row across four
   columns on a longer list, not decoration for its own sake, so it's kept
   very light rather than a strong banded look. */
.dp-export-table tbody tr:nth-child(even) { background: #fafaf8; }
.dp-export-col-num { width: 32px; text-align: center; font-size: 12px; color: #777; font-family: var(--font-mono); }
/* Name + catalog number are the two things worth grabbing at a glance —
   sized and weighted well above the price column on purpose. */
.dp-export-name { font-size: 15px; font-weight: 700; line-height: 1.3; }
.dp-export-sku { font-family: var(--font-mono); font-size: 12.5px; color: #555; margin-top: 3px; }
.dp-export-col-qty { width: 70px; text-align: center; }
.dp-export-qty-badge {
  display: inline-flex; align-items: center; justify-content: center; min-width: 34px; height: 34px;
  padding: 0 8px; border-radius: 17px; background: var(--torque); color: #14171B;
  font-family: var(--font-mono); font-weight: 800; font-size: 15px;
}
.dp-export-col-price {
  width: 130px; text-align: right; font-family: var(--font-mono); font-size: 12px; color: #666; white-space: nowrap;
}

.dp-export-summary {
  padding: 16px 32px; background: #fafaf8; border-top: 1px solid #ddd; border-bottom: 2px solid var(--blueprint);
  font-size: 12.5px; color: #444; font-family: var(--font-mono); text-align: right;
}

.dp-export-footer { padding: 18px 32px 22px; }
.dp-export-footer-tagline { font-size: 11.5px; color: #444; line-height: 1.5; max-width: 560px; }
.dp-export-footer-url {
  font-family: var(--font-mono); font-size: 11.5px; color: var(--torque); font-weight: 700; margin-top: 8px;
}
.cart-items {
  background: var(--paper-raised); border: 1px solid var(--line); border-radius: 12px;
  padding: 4px 20px; box-shadow: 0 2px 0 var(--line); margin-bottom: 20px;
}
/* No more dedicated left-hand column for a remove control (see
   .cart-row-menu below) — that column, plus the gap next to it, is
   exactly what was making the price/qty side feel squeezed against the
   card's own edge. Freed up, .cart-row-meta's own 346px gets to be real
   breathing room instead of bare minimum. position:relative + the extra
   top padding is what gives the "⋮" menu (position:absolute) a spot to
   sit in without overlapping the thumbnail below it. */
.cart-row {
  display: grid; grid-template-columns: 72px 1fr 346px; align-items: center; gap: 16px;
  padding: 34px 0 18px; border-bottom: 1px solid var(--line); position: relative;
}
.cart-row:last-child { border-bottom: none; }
/* .cart-row-meta (qty + line total) is one grid item on desktop (its own
   276px = 132+16+130 matches the .cart-row column above), split back into
   two fixed-width columns internally — that's what lets it collapse to a
   single flex row on mobile (below) without juggling grid-column
   reassignment across two separate grid children. */
.cart-row-meta { display: grid; grid-template-columns: 130px 200px; gap: 16px; align-items: center; }

/* The "⋮" menu replacing the old plain "×" — Onninen tucks its own
   per-item remove control behind exactly this kind of menu instead of a
   bare, always-visible icon; reads as tidier, and (the actual reason it's
   worth doing here) means one less column's width to reserve on every
   row all the time for an action used rarely. */
/* Top-right, not top-left: on the left, the open dropdown floated straight
   over the product photo (a busy image showing through around the "Usuń"
   text read as broken, not as an intentional overlay) — the top-right
   corner sits over the qty/price area instead, plain background, no photo
   underneath. right:0/left:auto throughout so it opens flush against the
   row's own right edge instead of the left one. */
.cart-row-menu { position: absolute; top: 6px; right: 0; left: auto; }
.cart-row-menu-toggle {
  display: flex; align-items: center; justify-content: center; width: 28px; height: 28px;
  border: none; background: transparent; color: var(--steel); border-radius: 50%; cursor: pointer;
  transition: background .12s ease, color .12s ease;
}
.cart-row-menu-toggle svg { width: 18px; height: 18px; }
.cart-row-menu-toggle:hover,
.cart-row-menu.is-open .cart-row-menu-toggle { background: var(--paper); color: var(--ink); }
.cart-row-menu-dropdown {
  position: absolute; top: calc(100% + 4px); right: 0; left: auto; z-index: 20; min-width: 116px;
  background: var(--paper-raised); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: 0 8px 20px -6px rgb(0 0 0 / 0.18); padding: 4px; opacity: 0; visibility: hidden;
  transform: translateY(-4px); transition: opacity .12s ease, transform .12s ease, visibility .12s;
}
.cart-row-menu.is-open .cart-row-menu-dropdown { opacity: 1; visibility: visible; transform: translateY(0); }
/* Scoped under TWO ancestor classes, not just .cart-row-menu-remove alone
   — WooCommerce's own ".woocommerce a.remove" selector is 2 classes + 1
   element (specificity 0,2,1). A single extra ancestor class here only
   gets to 0,2,0 — still loses on the element-count tiebreak, which is
   exactly why the first attempt at this fix didn't actually take. Three
   classes (0,3,0) beats it outright regardless of any element type WC's
   side adds. Same cascade fight as the old "×" button and the checkout
   button before it: WC's rule was forcing its own display:block, circular
   width:1em/height:1em box, and red colour onto this link no matter what
   this rule declared — exactly the icon-stacked-above-text-in-a-tiny-
   circle look reported as "broken". */
.cart-row-menu .cart-row-menu-dropdown .cart-row-menu-remove {
  display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; height: auto;
  padding: 9px 12px; border-radius: 7px; text-align: left; line-height: 1.3;
  color: var(--error) !important; text-decoration: none !important; font-size: 13.5px; font-weight: 500;
  transition: background .12s ease;
}
.cart-row-menu .cart-row-menu-dropdown .cart-row-menu-remove:hover { background: var(--paper); color: var(--error) !important; }
.cart-row-menu .cart-row-menu-dropdown .cart-row-menu-remove svg { width: 16px; height: 16px; flex-shrink: 0; }
/* aspect-ratio: 4/3 + cover, not a fixed square box with contain — real
   catalog photos are already 4:3 (see .product-photo), so a square frame
   around one just added visible letterboxing/padding on every thumbnail.
   This matches the shape they actually are instead of fighting it. */
.cart-row-thumb img {
  width: 72px; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 8px;
  border: 1px solid var(--line); background: var(--paper); display: block;
}
.cart-row-info { min-width: 0; }
.cart-row-sku { font-family: var(--font-mono); font-size: 11.5px; color: var(--steel); margin-bottom: 3px; }
/* .page-content's own "a" rule (styled for prose-page links, underlined)
   otherwise leaks in here too — this template's markup renders inside
   that same wrapper (see the .page-article note above). */
.cart-row-name a, .cart-row-name { font-weight: 500; color: var(--ink); font-size: 14.5px; text-decoration: none; }
.cart-row-qty .quantity { width: 100%; justify-content: center; }
.cart-row-total {
  text-align: right; font-family: var(--font-mono); font-weight: 700; font-size: 16.5px;
  font-variant-numeric: tabular-nums;
}
/* Line total is the one figure that matters at a glance (qty already
   folded in) — the per-unit price is just a "why" underneath it, only
   printed server-side at all once there's more than 1 of something to
   divide, so no extra display toggle needed here. */
.cart-row-unit-price {
  font-family: var(--font-mono); font-weight: 400; font-size: 12px; color: var(--steel); margin-top: 3px;
  white-space: nowrap;
}
/* WooCommerce renders the amount and this "(z VAT)" tag as two separate
   inline elements with just a space between — when the column's too
   narrow for both on one line, the browser was free to wrap inside the
   tag itself ("(z" / "VAT)"). Its own line, every time, reads cleaner
   than leaving that to chance. */
.cart-row-total .tax_label {
  display: block; font-family: var(--font-body); font-weight: 400; font-size: 11px; color: var(--steel);
  margin-top: 2px;
}

.cart-actions-row {
  display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 14px;
  background: var(--paper-raised); border: 1px solid var(--line); border-radius: 12px;
  padding: 18px 20px; box-shadow: 0 2px 0 var(--line);
}
.cart-actions-row .coupon { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.cart-actions-row .coupon .input-text {
  border: 1px solid var(--line); border-radius: var(--radius); padding: 10px 14px;
  font-family: var(--font-body); font-size: 13.5px; background: var(--paper); min-width: 180px;
}
.cart-empty-state { margin-top: 12px; }

/* Mobile-only elements — plain blocks on desktop screens would just sit
   there unused otherwise, so both stay display:none until the breakpoint
   below turns them into real UI. */
.cart-mobile-bar,
.cart-mobile-trust,
.cart-mobile-count,
.checkout-mobile-bar { display: none; }

@media (max-width: 760px) {
  .cart-layout { grid-template-columns: 1fr; gap: 28px; }
  .cart-summary-sticky { position: static; }
  .cart-items { padding: 4px 14px; }
  /* Name/SKU on their own row next to the thumbnail, qty + line total
     together on a second row below — .cart-row-meta is a single grid
     item here (see the desktop rule above), so it just needs to span
     that second row as plain flex, no per-child column reassignment. */
  .cart-row {
    grid-template-columns: 64px 1fr; grid-template-rows: auto auto; row-gap: 10px; padding: 30px 0 14px;
  }
  .cart-row-info { grid-column: 2; grid-row: 1; }
  .cart-row-meta {
    grid-column: 1 / 3; grid-row: 2; display: flex; align-items: center; justify-content: space-between;
  }
  .cart-actions-row { flex-direction: column; align-items: stretch; }
  .cart-actions-row .coupon { flex-direction: column; align-items: stretch; }

  /* Count on its own line, the two text-link actions spread across the
     row below — all three crammed into one row (the original layout,
     unchanged since this element predates having three things in it) had
     nowhere near enough width and wrapped mid-phrase. */
  .cart-toolbar { flex-direction: column; align-items: flex-start; gap: 8px; margin-bottom: 16px; }
  .cart-toolbar-actions { width: 100%; justify-content: space-between; }

  /* The whole sidebar card (VAT/netto breakdown, its own checkout button,
     the trust bullets) is dropped entirely on mobile, not just its button
     — .cart-mobile-bar below is the one totals summary shown, in the one
     place (the end of the list) Onninen's own mobile cart puts theirs,
     rather than this same information appearing twice on one screen. */
  .cart-summary { display: none; }

  .cart-continue-shopping { margin-top: 4px; }

  /* Same three lines as the (now hidden on mobile) sidebar card, moved
     here instead — right after the items, before "kontynuuj zakupy",
     the same spot Onninen uses for its own reassurance line (their
     free-shipping badge). */
  .cart-mobile-trust {
    display: flex; flex-direction: column; gap: 10px; margin: 18px 0;
    padding: 16px 18px; background: var(--paper-raised); border: 1px solid var(--line); border-radius: 12px;
  }
  .cart-mobile-trust .trust-item { font-size: 13px; }

  /* The one totals summary on mobile — netto (+ its VAT, small) on the
     left, brutto prominent on the right, then the checkout button below.
     Pinned to the bottom of the viewport, not just the end of the page
     flow — "how much, and pay" needs to stay reachable while scrolling a
     long item list, the same way it does on Onninen's own mobile cart. */
  .cart-mobile-bar {
    display: block; position: fixed; left: 0; right: 0; bottom: 0; z-index: 500;
    padding: 14px 18px; padding-bottom: calc(14px + env(safe-area-inset-bottom, 0px));
    background: var(--blueprint-ink); border-top: 1px solid rgba(14,68,56,.14);
    box-shadow: 0 -6px 16px -4px rgb(0 0 0 / 0.12);
  }
  /* Leaves room at the bottom of the page so the fixed bar never sits on
     top of real content — the "Kontynuuj zakupy" button was disappearing
     half under it on a short cart (few line items). That reservation has
     to live on .cart-layout itself, not body: body's padding-bottom only
     ever adds extra *scrollable* space past the end of the document, which
     does nothing when the page is already shorter than the viewport (there
     is nothing to scroll to) — exactly the short-cart case this was meant
     to fix. .cart-layout carries the sticky-footer flex:1 that stretches
     it to fill the viewport on a short page (see body.woocommerce-cart
     above), so padding reserved on *it* actually pushes its own last
     child up clear of the fixed bar's covered strip, on a short page and
     a long one alike. --dp-mobile-bar-h is kept in sync with the bar's
     actual rendered height by a ResizeObserver in the script at the
     bottom of cart.php, instead of a hardcoded guess that silently goes
     stale the next time the bar's own content grows a few px taller;
     128px only matters for the instant before that JS runs. */
  .cart-layout { padding-bottom: calc(var(--dp-mobile-bar-h, 128px) + 20px); }

  /* Netto and brutto used to sit side by side, each getting only half the
     bar's width — fine for an ordinary total, but a customer needs to read
     the *exact* amount due every time, not a shortened approximation, and
     splitting the width in half is exactly what forced the ellipsis
     fallback to actually kick in on a large-but-real order, not just an
     absurd test case. Stacked full-width rows instead: brutto (the number
     that matters) on its own line gets the *entire* bar width to lay out
     in, so it would take a genuinely enormous number to still not fit —
     the ellipsis stays only as a last-resort safety net, never the normal
     outcome. */
  .cart-mobile-bar-prices { display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px; }
  .cart-mobile-bar-netto, .cart-mobile-bar-brutto { display: flex; flex-direction: column; gap: 2px; }
  .cart-mobile-bar-label {
    font-size: 11px; color: #4b5147; text-transform: uppercase; letter-spacing: .03em;
  }
  /* Brutto is the amount actually due — its label reads bolder/darker than
     netto's so the two aren't mistaken for equally-weighted numbers. */
  .cart-mobile-bar-brutto .cart-mobile-bar-label { color: var(--ink); font-weight: 700; }
  /* Explicit line-height: with none set, the font's own metrics box crops
     this bold monospace's tall glyphs (digits, the currency mark) right at
     the top edge at some non-integer browser zoom/DPI scales — invisible
     zoomed in (rounding happens to land clean), visibly clipped at 100%.
     1.3 gives the glyphs enough box to round into at any scale. */
  .cart-mobile-bar-netto-value {
    font-family: var(--font-mono); font-size: clamp(11px, 4.2vw, 16.5px); font-weight: 600; color: var(--ink);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: block; line-height: 1.3;
  }
  /* Small and quiet — VAT here is "for the record", not something to act
     on, so it trails right under netto instead of claiming its own
     column or competing with brutto for attention. Still legible-sized
     though, not so small it reads as an afterthought. */
  .cart-mobile-bar-vat {
    display: block; font-family: var(--font-mono); font-size: clamp(9px, 3.2vw, 12px); color: #4b5147; margin-top: 1px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.3;
  }
  .cart-mobile-bar-value {
    /* A manually darkened shade of --torque, not the token itself — at
       this size and against this card's pale background, the full-
       brightness accent colour read as too light / yellow rather than a
       confident "this is the number that matters" orange. */
    font-family: var(--font-mono); font-size: clamp(13px, 6vw, 24px); font-weight: 800; color: #b8791f;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: block; line-height: 1.3;
  }
  /* A bit taller, with an actual shadow of its own — flat and the same
     height as any other button on the page undersold it as THE one
     action this whole bar exists for; the extra padding and a soft
     shadow underneath it (echoing the amber it's already filled with,
     not a generic grey one) give it the weight/depth to read as the
     obvious thing to press. */
  .cart-mobile-bar-btn {
    display: flex; align-items: center; justify-content: center; width: 100%;
    background: var(--torque); color: var(--torque-ink) !important; font-weight: 700; font-size: 16.5px;
    padding: 17px 24px; border-radius: var(--radius); text-decoration: none !important;
    box-shadow: 0 6px 16px -4px rgb(184 121 31 / 0.55);
  }

  /* Same count as .cart-toolbar-count above, just relocated — see
     .cart-mobile-count in cart.php for why. */
  .cart-toolbar-count { display: none; }
  .cart-mobile-count {
    display: block; font-size: 12.5px; color: var(--steel); font-family: var(--font-mono); margin: 16px 0 -6px;
  }

  /* Checkout's own version of .cart-mobile-bar above, same reasoning: the
     real submit button sits at the very bottom of a long, multi-field form,
     out of reach without a long scroll on a small screen. Only one number
     here (not netto+VAT+brutto like the cart's) — by checkout, "how much"
     has already been the cart's own question to answer; this bar only
     needs to say "yes, still this much" and let you actually press go. */
  .checkout-mobile-bar {
    display: flex; align-items: center; justify-content: space-between; gap: 14px;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 500;
    padding: 14px 18px; padding-bottom: calc(14px + env(safe-area-inset-bottom, 0px));
    background: var(--blueprint-ink); border-top: 1px solid rgba(14,68,56,.14);
    box-shadow: 0 -6px 16px -4px rgb(0 0 0 / 0.12);
  }
  .checkout-mobile-bar-total { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
  .checkout-mobile-bar-label {
    font-size: 11px; color: var(--ink); font-weight: 700; text-transform: uppercase; letter-spacing: .03em;
  }
  .checkout-mobile-bar-value {
    font-family: var(--font-mono); font-size: clamp(13px, 5vw, 20px); font-weight: 800; color: #b8791f;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: block; line-height: 1.3;
  }
  .checkout-mobile-bar-btn {
    display: flex; align-items: center; justify-content: center; flex-shrink: 0;
    background: var(--torque); color: var(--torque-ink); font-weight: 700; font-size: 15px;
    padding: 15px 22px; border: none; border-radius: var(--radius); cursor: pointer;
    box-shadow: 0 6px 16px -4px rgb(184 121 31 / 0.55);
  }
  /* Same reasoning as .cart-layout's own version of this — see the long
     comment above it. body's own padding-bottom only ever adds *scrollable*
     space past the end of an already-viewport-filling page, which does
     nothing on a short checkout (little in the cart, no shipping options);
     .checkout-layout carries the sticky-footer flex:1 that stretches it to
     fill the viewport there (see body.woocommerce-checkout further up), so
     padding reserved on it is what actually pushes the real submit button
     and trust bar up clear of the fixed bar's covered strip either way. */
  .checkout-layout { padding-bottom: calc(var(--dp-mobile-bar-h, 90px) + 20px); }
}

/* Barely readable against --paper (both very light, very close in tone)
   — var(--steel), the colour this same border already switches to on
   hover elsewhere, reads clearly at rest without needing a heavier
   change than just that. */
/* Solid var(--steel) read as too heavy/prominent for a secondary link;
   var(--steel) at partial opacity keeps the same hue (so it still reads as
   an intentional border, not the original barely-visible var(--line)) while
   landing lighter than either fixed swatch. */
.cart-continue-shopping { border-color: rgba(88, 95, 85, 0.4); }
.woocommerce-cart h1.entry-title, .woocommerce-checkout h1.entry-title { font-size: 28px; margin-bottom: 24px; }

table.shop_table {
  width: 100%; border-collapse: collapse; background: var(--paper-raised);
  border: 1px solid var(--line); border-radius: 12px; overflow: hidden;
  margin-bottom: 24px; box-shadow: 0 2px 0 var(--line);
}
table.shop_table tbody tr:hover { background: var(--paper); }
table.shop_table thead th {
  text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--steel); font-weight: 500; padding: 14px 16px; border-bottom: 1px solid var(--line);
}
table.shop_table td { padding: 16px; border-bottom: 1px solid var(--line); vertical-align: middle; font-size: 14px; }
table.shop_table tr:last-child td { border-bottom: none; }
table.shop_table td.product-thumbnail img { width: 68px; height: 68px; object-fit: contain; border-radius: 8px; border: 1px solid var(--line); background: var(--paper); padding: 4px; }
table.shop_table td.product-name a { font-weight: 500; color: var(--ink); }
table.shop_table td.product-price, table.shop_table td.product-subtotal { font-family: var(--font-mono); }
table.shop_table td.actions { background: transparent; }
a.remove {
  display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px;
  border-radius: 50%; color: var(--steel) !important; text-decoration: none !important; font-size: 18px; line-height: 1;
  transition: background .12s ease, color .12s ease;
}
a.remove:hover { background: var(--torque); color: var(--torque-ink) !important; }

/* Same WooCommerce-core specificity problem as the desktop rule above
   (.woocommerce .quantity .qty, width: 3.631em, three classes beating this
   rule's two) — this mobile-only override needs the same "input" element
   bump and ch-based width to actually hold past 2 digits, plus the same
   calc() adjustment as the desktop rule above for its own (wider) padding,
   since border-box counts padding as part of a plain ch value otherwise. */
.woocommerce .quantity input.qty {
  width: calc(4.5ch + 20px); padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--radius);
  font-family: var(--font-mono); font-size: 14px; text-align: center; background: var(--paper);
}

.woocommerce-cart-form .coupon {
  display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-top: 4px;
}
.woocommerce-cart-form .coupon .input-text {
  border: 1px solid var(--line); border-radius: var(--radius); padding: 10px 14px;
  font-family: var(--font-body); font-size: 13.5px; background: var(--paper-raised); min-width: 200px;
}
.woocommerce-cart-form table.shop_table td.actions {
  padding: 18px 16px; display: flex; gap: 12px; flex-wrap: wrap; align-items: center; justify-content: space-between;
}

button.button, input.button, .woocommerce #respond input#submit,
.checkout-button, #place_order {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  background: var(--torque); color: var(--torque-ink) !important; border: none; border-radius: var(--radius);
  padding: 13px 24px; font-family: var(--font-body); font-weight: 600; font-size: 14px; cursor: pointer;
  transition: opacity .12s ease; text-decoration: none !important;
}
button.button:hover, input.button:hover, #place_order:hover { opacity: .92; }
button.button:disabled { opacity: .5; cursor: default; }

/* This is the rule that actually reaches the real "Przejdź do płatności"
   link — its parent in the live markup is .cart_totals (a plain div, from
   our own cart-totals.php), not the ".wc-proceed-to-checkout" wrapper a
   duplicate rule further up assumed WooCommerce prints around it (it
   doesn't — woocommerce_button_proceed_to_checkout() renders the link with
   no wrapper at all). That duplicate never matched anything, which is why
   an earlier spacing fix aimed at it had no visible effect.
   Scoped with 3 classes + the "a" element on purpose — WooCommerce's own
   default stylesheet has a same-tier rule (.woocommerce a.button, effectively
   2 classes + 1 element once its :where() wrapper — zero specificity by
   definition — is discounted) that was winning the tie on element-count and
   silently overriding this margin/width/display with its own generic
   button defaults. */
.cart-summary-sticky .cart_totals a.checkout-button { display: flex; width: 100%; margin-top: 38px; text-align: center; justify-content: center; }
.woocommerce-shipping-calculator, .shipping-calculator-button { font-size: 13px; color: var(--steel); }

/* ==================================================================
   Checkout — two-column layout: form fields on the left, an order
   summary that stays pinned on the right instead of an unbounded list
   at the bottom of the page.
   ================================================================== */
.checkout-layout { display: grid; grid-template-columns: 1.3fr 1fr; gap: 48px; align-items: start; }
/* WooCommerce's own checkout.js prepends error/notice markup (and blocks like
   coupon forms) directly as a child of form.checkout-layout on validation
   failure — without this, that extra grid item steals a column and the
   whole two-column layout scrambles. Anything that isn't our two known
   columns spans full width instead of being auto-placed into the grid. */
.checkout-layout > *:not(.checkout-main):not(.checkout-summary) { grid-column: 1 / -1; }
.checkout-main { min-width: 0; }
.checkout-summary { min-width: 0; }
/* Same faint green tint as the cart page's summary card (see
   .cart-summary-sticky) — one consistent "this card is the important one"
   treatment across both pages. */
.checkout-summary-sticky {
  position: sticky; top: calc(var(--sticky-top) + 16px); background: var(--blueprint-ink); border: 1px solid rgba(14,68,56,.14);
  border-radius: 12px; padding: 24px; box-shadow: 0 2px 0 rgba(14,68,56,.1);
}
.checkout-summary-sticky h3 { font-size: 17px; margin-bottom: 16px; }
.checkout-summary .woocommerce-checkout-review-order-table { border: none; background: transparent; margin-bottom: 0; }
.checkout-summary .woocommerce-checkout-review-order-table th,
.checkout-summary .woocommerce-checkout-review-order-table td { padding: 10px 0; font-size: 13.5px; }
.checkout-summary .woocommerce-checkout-review-order-table thead { display: none; }

.checkout-fields-block { display: block; }
.woocommerce-billing-fields h3, .woocommerce-shipping-fields h3, .woocommerce-additional-fields h3 {
  font-size: 16px; margin: 28px 0 16px; padding-top: 20px; border-top: 1px solid var(--line);
}
.woocommerce-billing-fields:first-child h3 { margin-top: 0; padding-top: 0; border-top: none; }
/* Osoba prywatna / Firma — a two-way pill toggle, not a pair of radio
   buttons with visible circles: this is a single either/or choice that
   reshapes the form beneath it, closer to a segmented control than a
   traditional radio list. */
.dp-customer-type {
  display: inline-flex; padding: 4px; background: var(--paper); border: 1.5px solid var(--steel);
  border-radius: 999px; margin-bottom: 22px; gap: 2px;
}
.dp-customer-type-option {
  position: relative; display: flex; align-items: center; padding: 9px 18px; border-radius: 999px;
  font-size: 13.5px; font-weight: 600; color: var(--ink); cursor: pointer; transition: color .15s ease;
}
.dp-customer-type-option input {
  position: absolute; opacity: 0; width: 100%; height: 100%; top: 0; left: 0; margin: 0; cursor: pointer;
}
.dp-customer-type-option:has(input:checked) { background: var(--blueprint); color: var(--blueprint-ink); }
/* Fallback for browsers without :has() support (rare, but this is a form —
   worth not silently breaking on) — same end state, driven by the JS toggle
   already needed for showing/hiding the company fields rather than a second
   mechanism just for this. */
.dp-customer-type-option.is-active { background: var(--blueprint); color: var(--blueprint-ink); }
/* The company fields' own required-state (added/removed by JS alongside
   the native `required` attribute) reuses the exact look every other
   required field already has — .form-row .required is that same red
   asterisk, just triggered by a class here instead of being baked into
   the field's static PHP config. */
.form-row.dp-company-field.validate-required label::after { content: " *"; color: var(--torque); }
/* WooCommerce's own woocommerce_form_field() bakes a literal "(optional)"
   span into the label HTML for any field whose PHP config has required:
   false — which both company fields always do, since PHP can't know yet
   which radio the customer will pick. Toggling to "Firma" only adds the
   *visual* required state (the native attribute + this class); without
   this, the label would confusingly still read "(optional)" right next
   to the red asterisk that says otherwise. */
.form-row.dp-company-field.validate-required .optional { display: none; }
.form-row { margin-bottom: 14px; }
.form-row label { display: block; font-size: 12.5px; color: var(--steel); margin-bottom: 6px; }
.form-row .required { color: var(--torque); text-decoration: none; }
.form-row input.input-text, .form-row select, .form-row textarea {
  width: 100%; border: 1px solid var(--line); border-radius: var(--radius); padding: 11px 14px;
  font-family: var(--font-body); font-size: 14px; background: var(--paper-raised); color: var(--ink);
}
.form-row input.input-text:focus, .form-row select:focus, .form-row textarea:focus {
  outline: 2px solid var(--torque); outline-offset: 1px;
}
.form-row-first, .form-row-last { width: calc(50% - 8px); display: inline-block; }
.form-row-first { margin-right: 16px; }
#payment { background: var(--paper-raised); border: 1px solid var(--line); border-radius: var(--radius); padding: 4px; margin-top: 18px; }
#payment ul.payment_methods { list-style: none; margin: 0; padding: 0; }
#payment .wc_payment_method { padding: 14px 16px; border-bottom: 1px solid var(--line); }
#payment .wc_payment_method:last-child { border-bottom: none; }
#payment .payment_box { margin-top: 10px; font-size: 13px; color: var(--steel); background: var(--paper); padding: 12px 14px; border-radius: var(--radius); }
#place_order { width: 100%; margin-top: 38px; padding: 15px 24px; font-size: 15px; }

/* WooCommerce's own select2.css hard-codes the highlighted-option colour as
   var(--wp-admin-theme-color, #0073aa) — that CSS variable only ever exists
   inside wp-admin, so on the front end it's always the #0073aa fallback:
   admin blue, nothing to do with this site's own palette. Same specificity
   (3 classes/attributes) as the rule it's overriding, so the extra `body`
   element here is what wins the tie regardless of stylesheet load order,
   rather than reaching for !important. */
body .select2-container--default .select2-results__option--highlighted[aria-selected],
body .select2-container--default .select2-results__option--highlighted[data-selected] {
  background-color: var(--blueprint);
  color: var(--blueprint-ink);
}
body .select2-container--default .select2-selection--single:focus,
body .select2-container--default.select2-container--focus .select2-selection--single,
body .select2-container--default.select2-container--open .select2-selection--single {
  border-color: var(--blueprint);
}

@media (max-width: 760px) {
  .single-product-wrap { grid-template-columns: 1fr; }
  /* One column stacked all four blocks — brand paragraph, then three link
     lists — into a single endless scroll. The brand block reads fine full
     width (it's prose, not a list); the three link groups pair up neatly
     into 2 columns instead, with the odd one out (Informacje prawne)
     simply starting its own row. */
  .footer-grid, .footer-grid-4 { grid-template-columns: repeat(2, 1fr); gap: 28px 20px; }
  .footer-grid .footer-brand { grid-column: 1 / -1; }
  .process { grid-template-columns: 1fr; }
  /* 48px is the desktop two-column gutter — once the grid collapses to one
     column here, that same value becomes vertical space between the form
     and the summary card stacked under it, which reads as a much bigger
     gap than a single-column layout needs. */
  .checkout-layout { grid-template-columns: 1fr; gap: 20px; }
  .checkout-summary-sticky { position: static; max-height: none; padding-top: 12px; }
  table.shop_table thead { display: none; }
  table.shop_table td { display: block; width: 100%; border-bottom: none; padding: 6px 16px; }
  table.shop_table tr { display: block; border-bottom: 1px solid var(--line); padding: 12px 0; }
  /* WooCommerce's own table markup (cart, orders list, order-view line
     items) writes a data-title attribute onto every cell specifically for
     this stacked mobile layout — hiding the header row without surfacing
     it back through ::before leaves each stacked value unlabeled (a bare
     "#5150", "286,12 zł", … with no indication which is which). */
  table.shop_table td[data-title]::before {
    content: attr(data-title);
    display: block; font-family: var(--font-display); font-size: 11px; font-weight: 700;
    text-transform: uppercase; letter-spacing: .04em; color: var(--steel); margin-bottom: 3px;
  }
  table.shop_table td.product-thumbnail[data-title]::before,
  table.shop_table td.actions[data-title]::before,
  table.shop_table td[class*="-actions"][data-title]::before { content: none; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; scroll-behavior: auto !important; }
}

/* ==================================================================
   Cart — print / "save as PDF" (the browser's own print dialog already
   offers that as a destination, so this needs no library or server-side
   PDF generation at all). Everything on the cart page is hidden except
   #dp-cart-export (see cart.php) — a plain, purpose-built sheet, not the
   interactive on-screen cart, so there's no live <input>, hidden button
   leaving a gap in a CSS grid, or anything else about the interactive
   page that needs special-casing here. Scoped to body.woocommerce-cart —
   #dp-cart-export only exists on this one page, so an unscoped version of
   this rule would hide every other page's content when printed too,
   leaving a blank sheet with nothing matching to reveal.

   Hides each surrounding block BY NAME with display:none, rather than a
   blanket "hide everything, then reveal #dp-cart-export" rule built on
   visibility:hidden — a first version did exactly that, and it printed
   correctly but with a mostly-blank second page every time. The reason:
   visibility:hidden hides an element's paint but not its layout — every
   hidden block (header, footer, the interactive cart, cross-sells...)
   still reserved its normal height, so the page's total printable height
   was still the full on-screen cart page, not just #dp-cart-export's own
   (much shorter) height, and the extra space spilled onto a second page.
   display:none actually collapses that space. It isn't used as a
   catch-all here (a "hide everything except X" display:none rule would
   also hide X's own ancestors, taking X down with them) — instead each
   sibling block that needs to disappear is named directly. */
@media print {
  @page { size: A4; margin: 10mm; }
  body.woocommerce-cart .site-header,
  body.woocommerce-cart .site-footer,
  body.woocommerce-cart .page-title-row,
  body.woocommerce-cart .cart-toolbar,
  body.woocommerce-cart .cart-items,
  body.woocommerce-cart .cart-continue-shopping,
  body.woocommerce-cart .cart-summary,
  /* Fixed/floating elements that are normally toggled on purely by a
     max-width media query (not a permanent display:none this list would
     otherwise already be overriding) — .cart-mobile-bar/.dp-mini-footer's
     own @media (max-width:760px)/(min-width:761px) rules go by the actual
     printed page's rendered width, and an A4 sheet's content box at this
     @page margin lands under 760px, so both were switching themselves on
     for print exactly as they do on a narrow phone screen: the fixed
     totals bar and its checkout button floating over the bottom of every
     printed page, on top of #dp-cart-export's own content. Neither belongs
     in a document meant for a mechanic pulling parts off a shelf. */
  body.woocommerce-cart .cart-mobile-bar,
  body.woocommerce-cart .cart-mobile-count,
  body.woocommerce-cart .cart-mobile-trust,
  body.woocommerce-cart .dp-mini-footer,
  body.woocommerce-cart .cross-sells,
  body.woocommerce-cart .woocommerce-message,
  body.woocommerce-cart .woocommerce-error,
  body.woocommerce-cart .woocommerce-info,
  /* The mobile nav drawer and its dimming overlay hide themselves on
     screen with transform/opacity (translateX(-100%), opacity:0), not
     display:none — a fixed-position element's transform isn't always
     honoured during print/"save as PDF" the way it is on screen, so the
     (still very much present, just normally off-canvas) drawer panel and
     its semi-transparent dark backdrop were both rendering at their
     untransformed position: a solid band down the left edge of every
     page from the drawer panel, and the backdrop's own tint bleeding
     into the colour of everything else on the page — including making
     #dp-cart-export's own dark grey text read as duller / slightly green
     than it actually is. Both need an explicit display:none here since
     neither actually vanishes in print on its own. */
  body.woocommerce-cart .mobile-drawer,
  body.woocommerce-cart .mobile-drawer-overlay,
  body.woocommerce-cart .header-search-drop {
    display: none !important;
  }
  body.woocommerce-cart #dp-cart-export {
    display: block !important; position: absolute; top: 0; left: 0; border: none;
    /* Its ancestors (.page-wrap, .cart-page, .cart-main, the cart form...)
       stay visible, since they're what keeps this element itself on the
       page at all — but several of them carry their own padding/margin
       for the normal on-screen layout (.page-wrap alone adds 40px of
       padding-top on the cart page), which otherwise pushes this down
       and opens up a big gap of blank space above the header band before
       it even starts. position:absolute lifts it out of that flow
       entirely so none of that ancestor spacing applies to it. */
    /* Chrome (and some other engines) skip large background-color fills
       during print/"save as PDF" by default, treating them as ink-saving
       candidates the way it would a decorative background image — which
       is what turned the header's dark-green band invisible, leaving its
       white half of the logo unreadable against the now-bare white page.
       This tells it to render backgrounds exactly as styled instead. */
    -webkit-print-color-adjust: exact; print-color-adjust: exact; color-adjust: exact;
  }
  body.woocommerce-cart #dp-cart-export * {
    -webkit-print-color-adjust: exact; print-color-adjust: exact; color-adjust: exact;
  }
  body.woocommerce-cart { background: #fff !important; }
  /* Keeps one product's name+SKU+price together instead of splitting a
     row across a page break. */
  .dp-export-table tr { page-break-inside: avoid; }
}

/* ==================================================================
   My Account — login (password + emailed-code tabs), the logged-in
   dashboard shell (nav + content card), and light restyling of core
   WooCommerce account templates (edit-account, addresses, orders) that
   are otherwise left unoverridden — see woocommerce/myaccount/.
   ================================================================== */

.myaccount-login {
  max-width: 440px; margin: 56px auto; background: var(--paper-raised);
  border: 1px solid var(--line); border-radius: var(--radius); padding: 32px 28px;
}
.myaccount-login-tabs {
  display: flex; gap: 4px; background: var(--paper); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 4px; margin-bottom: 22px;
}
.myaccount-login-tab {
  flex: 1; border: none; background: transparent; padding: 10px 14px; cursor: pointer;
  font-family: var(--font-display); font-weight: 700; font-size: 12.5px; letter-spacing: .02em;
  color: var(--steel); border-radius: calc(var(--radius) - 1px);
}
.myaccount-login-tab.is-active { background: var(--paper-raised); color: var(--ink); box-shadow: 0 1px 2px rgba(0,0,0,.08); }
.myaccount-login-lead { color: var(--steel); font-size: 14px; line-height: 1.5; margin: 0 0 20px; }
.myaccount-login-notice {
  padding: 12px 14px; border-radius: var(--radius); font-size: 13.5px; margin: 0 0 18px;
}
.myaccount-login-notice.is-error {
  background: color-mix(in srgb, var(--error) 10%, var(--paper-raised));
  color: var(--error); border: 1px solid color-mix(in srgb, var(--error) 30%, transparent);
}
.myaccount-code-input { letter-spacing: .5em; font-family: var(--font-mono); font-size: 22px; text-align: center; }
/* Only ever rendered when directparts_is_local_env() is true server-side
   (see inc/account-auth.php) — never appears on a real deployment. */
.myaccount-login-dev-code {
  background: #fff7d6; border: 1px dashed #b59b00; color: #6b5900; border-radius: var(--radius);
  padding: 10px 12px; font-size: 13px; margin: 0 0 16px;
}
.myaccount-login-dev-code code { font-family: var(--font-mono); font-weight: 700; letter-spacing: .1em; }
.myaccount-login-submit { width: 100%; margin-top: 4px; justify-content: center; }
.myaccount-login-row-end { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.myaccount-remember-me { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--steel); }
.myaccount-login-alt { text-align: center; font-size: 13px; margin-top: 18px; }
.myaccount-login-alt a { color: var(--blueprint); text-decoration: underline; }


/* Pulled up close to the page title (.page-title's own 32px margin-bottom
   already does most of the separating) — the extra 32px this used to add
   on top of that just pushed the actual nav/content down with nothing
   but blank paper between them and the heading above. */
.myaccount-layout { display: grid; grid-template-columns: 234px 1fr; gap: 32px; align-items: start; margin: 8px 0 64px; }
.myaccount-nav { position: sticky; top: var(--sticky-top); }
.myaccount-content {
  background: var(--paper-raised); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 32px; min-width: 0;
}
.myaccount-content h2, .myaccount-content h3 { font-family: var(--font-display); }
/* A tab whose content starts with a raw <h2> (Notifications: heading, then
   lead paragraph, then the form) carried a large top-margin ON TOP of this
   container's own 32px padding — visibly more empty space above that
   heading than any other tab has above its own first line. The actual
   first child is always WooCommerce's own .woocommerce-notices-wrapper —
   empty and collapsed to zero height when there's nothing to show, so it
   contributes no visible space itself, but it meant a plain :first-child
   reset landed on that wrapper instead of the h2 right after it, doing
   nothing. Resetting whichever of the two actually starts the visible
   content is what removes the extra gap in both cases. */
.myaccount-content > *:first-child,
.myaccount-content > .woocommerce-notices-wrapper:first-child + * {
  margin-top: 0;
}
.myaccount-content table.shop_table th {
  text-align: left; font-family: var(--font-display); font-size: 12px; text-transform: uppercase;
  letter-spacing: .04em; color: var(--steel); border-bottom: 1px solid var(--line); padding-bottom: 10px;
}
.myaccount-content table.shop_table td { padding: 12px 8px; border-bottom: 1px solid var(--line); font-size: 13.5px; }

/* WooCommerce's own woocommerce-layout.css floats this at 30% width
   (.woocommerce-account .woocommerce-MyAccount-navigation — two classes),
   sized for its default two-column account page — .myaccount-layout above
   already does that job with a CSS grid, so this needs resetting back to
   a plain block or the float shrinks it to 30% of the 234px nav column
   (~70px) instead of filling it. Same "beat core's specificity with an
   extra qualifier instead of !important" approach as the select2 overrides
   further up — the plain-class version of this selector ties core's own
   two-class one on specificity and only wins by source order, which is
   fragile; the body element tag here outranks it outright. */
body.woocommerce-account .woocommerce-MyAccount-navigation { float: none; width: 100%; }
.woocommerce-MyAccount-navigation ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.woocommerce-MyAccount-navigation li a { display: block; padding: 11px 14px; border-radius: var(--radius); color: var(--ink); text-decoration: none; font-size: 13.5px; }
.woocommerce-MyAccount-navigation li a:hover { background: var(--paper); }
.woocommerce-MyAccount-navigation li.is-active a { background: var(--blueprint); color: var(--blueprint-ink); font-weight: 600; }
.woocommerce-MyAccount-navigation li.woocommerce-MyAccount-navigation-link--customer-logout { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line); }

.woocommerce-EditAccountForm fieldset { border: 1px solid var(--line); border-radius: var(--radius); padding: 18px 18px 6px; margin: 24px 0 18px; }
.woocommerce-EditAccountForm legend { font-family: var(--font-display); font-weight: 700; font-size: 13px; padding: 0 8px; color: var(--steel); }

/* Addresses page — the built-in Billing/Shipping pair (core markup, only
   restyled) plus the saved-delivery-addresses book below it (custom, see
   woocommerce/myaccount/my-address.php + inc/account-addresses.php). Same
   "beat core's two-class float rule with a body-scoped one" fix as the
   nav above — .woocommerce-Addresses.col2-set carries the same
   .woocommerce-account-scoped float:left/width:% core CSS sized for its
   own full-width layout, not the narrower card this theme renders it in. */
body.woocommerce-account .woocommerce-Addresses.col2-set {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 20px; margin: 24px 0 40px;
}
/* .u-columns/.col2-set carries a clearfix (content:" "; display:table) on
   both ::before and ::after, left over from when this was a float layout
   and needed one. In a grid container those two pseudo-elements don't
   just do nothing — content:" " makes each of them a real (invisible)
   grid item, so a 2-item row turns into 4 items across 2 tracks and
   auto-placement fills it in DOM order: (empty), Billing, Shipping,
   (empty) — landing Billing top-right and Shipping bottom-left instead
   of side by side. Neither pseudo-element does anything a grid needs. */
body.woocommerce-account .woocommerce-Addresses.col2-set::before,
body.woocommerce-account .woocommerce-Addresses.col2-set::after {
  content: none;
}
body.woocommerce-account .woocommerce-Addresses .woocommerce-Address { float: none; width: auto; }
.woocommerce-Address { background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius); padding: 20px; }
/* justify-content: space-between here (against WooCommerce's own two-child
   <header>{h2, a.edit}) was leaving equal ~44px gaps on BOTH outer edges as
   well as between the two children — effectively space-evenly, not
   space-between, pushing "Billing address"/"Shipping address" visibly off
   the card's left edge. flex-start + margin-left:auto on the edit link is
   the more explicit, unambiguous way to say "title stays left, edit link
   stays right" and doesn't depend on that same distribution math. */
/* Root cause of that ~12px it was still off by: WooCommerce core's own
   CSS carries .woocommerce-account .addresses .title::before/::after —
   content:" "; display:table, a clearfix left over from a float layout
   that no longer applies here. In a flex container that isn't inert — it
   becomes a real (near-invisible) flex item, and this rule's own gap:12px
   puts exactly that much space in front of it, ahead of the h2. A plain
   .woocommerce-Address-title::before (one class) loses the specificity
   fight against core's three-class selector regardless of source order;
   matching its ancestor classes is what actually wins. Same fix as
   .woocommerce-Addresses.col2-set::before/::after further up this file,
   for the same underlying reason. */
.woocommerce-account .addresses .woocommerce-Address-title::before,
.woocommerce-account .addresses .woocommerce-Address-title::after { content: none; }
.woocommerce-Address-title { display: flex; align-items: center; justify-content: flex-start; gap: 12px; margin-bottom: 10px; }
.woocommerce-Address-title h2 { font-family: var(--font-display); font-size: 15px; margin: 0; }
.woocommerce-Address-title .edit { font-size: 12.5px; color: var(--blueprint); text-decoration: underline; white-space: nowrap; margin-left: auto; }
.woocommerce-Address address { font-style: normal; font-size: 13.5px; line-height: 1.6; color: var(--ink); }

.myaccount-address-book { margin-top: 8px; }
.myaccount-address-book-header { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-bottom: 16px; }
.myaccount-address-book-header h2 { font-family: var(--font-display); font-size: 17px; margin: 0; }
.myaccount-address-add { font-size: 13px; padding: 9px 16px; text-decoration: none; }
.myaccount-address-book-empty {
  color: var(--steel); font-size: 13.5px; background: var(--paper); border: 1px dashed var(--line);
  border-radius: var(--radius); padding: 20px; text-align: center; margin: 0;
}
.myaccount-address-book-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 16px; }
/* auto-fill (unlike auto-fit) keeps every track it can fit even when only
   one card exists to fill it, leaving an orphaned card beside empty
   space — this caps a lone card's width instead of stretching it across
   tracks nothing else occupies. */
.myaccount-address-book-grid > .myaccount-address-card:only-child { max-width: 320px; }
.myaccount-address-card {
  background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 18px; display: flex; flex-direction: column; gap: 10px;
}
.myaccount-address-card.is-default { border-color: var(--blueprint); box-shadow: 0 0 0 1px var(--blueprint); }
.myaccount-address-card-label {
  font-family: var(--font-display); font-size: 14px; margin: 0;
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.myaccount-address-default-badge {
  font-family: var(--font-body); font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em;
  background: var(--blueprint); color: var(--blueprint-ink); border-radius: 999px; padding: 2px 8px;
}
.myaccount-address-card address { font-style: normal; font-size: 13px; line-height: 1.6; color: var(--steel); flex: 1; margin: 0; }
.myaccount-address-card-actions { display: flex; gap: 16px; font-size: 12.5px; flex-wrap: wrap; }
.myaccount-address-card-actions a { color: var(--blueprint); text-decoration: underline; cursor: pointer; }
.myaccount-address-card-delete.is-confirming { color: var(--error); font-weight: 600; }

.myaccount-address-back { display: inline-block; font-size: 13px; color: var(--steel); text-decoration: none; margin-bottom: 18px; }
.myaccount-address-back:hover { color: var(--ink); }
.myaccount-address-form-title { font-family: var(--font-display); margin: 0 0 20px; }
.myaccount-address-form { max-width: 560px; }
.myaccount-address-form-actions { margin-top: 8px; }

/* Checkout — saved-address picker + "save this address" row, both inside
   WooCommerce's own .shipping_address wrapper (see
   inc/account-addresses.php), so they already show/hide together with the
   rest of the shipping fields under "Ship to a different address?". */
.dp-address-picker select { width: 100%; }
.dp-save-address-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; background: var(--paper);
  border: 1px solid var(--line); border-radius: var(--radius); padding: 12px 14px; margin-top: 6px !important;
}
.dp-save-address-label { display: flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--ink); cursor: pointer; }
.dp-save-address-name-wrap { flex: 1; min-width: 180px; }
.dp-save-address-name-wrap input { width: 100%; }

/* Single order view — tracking + invoice sections (see
   inc/account-orders.php), appended after WooCommerce's own order table. */
.dp-order-next-steps, .dp-order-tracking, .dp-order-invoice { margin-top: 24px; padding-top: 20px; border-top: 1px solid var(--line); }
.dp-order-next-steps h2 { font-size: 15px; margin: 0 0 10px; }
.dp-order-next-steps ol { margin: 0; padding: 0 0 0 20px; display: flex; flex-direction: column; gap: 6px; }
.dp-order-next-steps li { font-size: 13.5px; color: var(--steel); line-height: 1.5; }
.dp-order-next-steps li::marker { color: var(--blueprint); font-weight: 700; }
.dp-order-tracking h2 { font-size: 15px; margin: 0 0 8px; }
.dp-order-tracking p { margin: 0; font-size: 13.5px; }
.dp-order-tracking a { color: var(--blueprint); }

/* WooCommerce's own orders-table markup puts "View" and "Order again" as two
   plain adjacent <a class="button"> tags with nothing between them but a
   text-node space — this theme's own heavy button padding (line ~1048
   above) swallows that thin gap almost entirely, so the two visually read
   as one long pill instead of two distinct actions. An explicit flex gap
   guarantees real separation regardless of button padding. */
.woocommerce-orders-table__cell-order-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* Replaces the browser's hardcoded-yellow <mark> default on the order
   number/date in "Order #X was placed on Y" (see
   directparts_order_details_status_text() in inc/account-orders.php) with
   a quiet on-brand tint instead of trying to override a UA style. */
.dp-order-highlight {
  background: color-mix(in srgb, var(--blueprint) 8%, transparent);
  color: var(--blueprint); font-weight: 600; padding: 1px 5px; border-radius: 3px;
}

/* Dashboard — greeting, order/spend stats, recent orders (see
   woocommerce/myaccount/dashboard.php). */
.myaccount-dashboard-greeting { font-size: 16px; margin: 0 0 20px; }
.myaccount-dashboard-nudge {
  display: flex; align-items: center; gap: 10px; font-size: 13.5px; color: var(--ink);
  background: color-mix(in srgb, var(--torque) 10%, var(--paper)); border: 1px solid color-mix(in srgb, var(--torque) 30%, var(--line));
  border-radius: var(--radius); padding: 12px 16px; margin: 0 0 20px;
}
.myaccount-dashboard-nudge-icon { color: var(--torque-ink); flex-shrink: 0; }
.myaccount-dashboard-nudge a { color: var(--blueprint); font-weight: 600; text-decoration: none; white-space: nowrap; }
.myaccount-dashboard-nudge a:hover { text-decoration: underline; }
/* Was an equal-width auto-fit grid — with 4 tiles (orders/spend/discount/
   credit) that math didn't leave room for all of them on one row, so the
   4th (credit) always fell to a lonely second row. Flexbox instead: each
   tile keeps a sensible minimum but grows to fill the row, and "Orders" —
   a single digit, never needing as much room as a currency figure — gets a
   smaller basis so the other three can claim the space it doesn't need. */
.myaccount-dashboard-stats { display: flex; flex-wrap: wrap; gap: 12px; }
.myaccount-dashboard-stat {
  background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 14px 18px; display: flex; flex-direction: column; gap: 4px;
  flex: 1 1 170px;
  min-width: 0; /* lets the amount below truncate/wrap as a whole unit instead of forcing the grid track wider */
}
/* Orders (a 1-2 digit count) and Discount (always just "N%") never need
   real width — narrow. Available credit carries a value line AND a
   separate credit-limit line AND a note underneath, so it gets more room
   than the plain two-line tiles; --wide's bigger flex-grow is also what
   claims the row space the narrow tiles don't use. */
.myaccount-dashboard-stat--narrow { flex: 0 1 130px; }
.myaccount-dashboard-stat--wide { flex: 1.6 1 260px; }
.myaccount-dashboard-stat-label { font-size: 12px; color: var(--steel); text-transform: uppercase; letter-spacing: .03em; }
.myaccount-dashboard-stat-value { font-family: var(--font-display); font-size: 24px; font-weight: 700; color: var(--ink); }
/* WooCommerce's own price markup (<bdi>1 000,00&nbsp;€</bdi>) uses a plain,
   breakable space as the thousands separator — fine in flowing text, but
   at a narrow tile width the number itself was wrapping mid-figure ("1" on
   one line, "000,00 €" on the next). Any amount, any size, stays one
   unbroken unit. */
.myaccount-dashboard-stat-value .woocommerce-Price-amount,
.myaccount-dashboard-stat-sub .woocommerce-Price-amount { white-space: nowrap; }
/* Credit limit is now its own line under the remaining-balance value
   (was inline as "of X" trailing the big number, which is the layout
   that was reading as crooked) — a plain block, not sharing a line with
   anything else. */
.myaccount-dashboard-stat-sub { display: block; }

.myaccount-dashboard-recent { margin-top: 24px; padding-top: 20px; border-top: 1px solid var(--line); }
.myaccount-dashboard-recent h2 { font-size: 15px; margin: 0 0 12px; }
.myaccount-dashboard-recent-list { list-style: none; margin: 0 0 14px; padding: 0; display: flex; flex-direction: column; }
.myaccount-dashboard-recent-list li {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 12px 0; border-bottom: 1px solid var(--line); font-size: 13.5px;
}
.myaccount-dashboard-recent-list li:last-child { border-bottom: none; }
/* Order number + date grouped as one unit on the left (was 3 separate flex
   children with justify-content:space-between, which left a dead gap in
   the middle of the row whenever the date text was short) — total stays
   the one thing on the right, the way a receipt line reads. */
.myaccount-dashboard-recent-main { display: flex; align-items: baseline; gap: 10px; }
.myaccount-dashboard-recent-list a { color: var(--blueprint); font-weight: 600; text-decoration: none; }
.myaccount-dashboard-recent-list a:hover { text-decoration: underline; }
.myaccount-dashboard-recent-date { color: var(--steel); }
.myaccount-dashboard-recent-total { font-family: var(--font-mono); font-weight: 600; white-space: nowrap; }
.myaccount-dashboard-recent-total .woocommerce-Price-amount { white-space: nowrap; }
.myaccount-dashboard-all-orders { font-size: 13px; color: var(--blueprint); text-decoration: underline; }

/* Discount/credit tiles (see woocommerce/myaccount/dashboard.php) share
   .myaccount-dashboard-stat with the orders/spend tiles, plus this
   modifier — a blueprint-tinted background sets them apart as "your
   terms" rather than plain activity counts. */
.myaccount-dashboard-stat--accent { background: color-mix(in srgb, var(--blueprint) 6%, var(--paper)); border-color: color-mix(in srgb, var(--blueprint) 25%, var(--line)); }
.myaccount-dashboard-stat--accent .myaccount-dashboard-stat-value { color: var(--blueprint); }
.myaccount-dashboard-stat-sub { font-family: var(--font-body); font-size: 12.5px; font-weight: 400; color: var(--steel); }
.myaccount-dashboard-stat-note { display: block; font-size: 12px; color: var(--steel); margin-top: 6px; }
.myaccount-dashboard-stat-note a { color: var(--blueprint); text-decoration: underline; }

/* directparts_info_tip() (functions.php) — a small "?" trigger that reveals
   its explanatory text on click/tap, so a tile doesn't have to carry that
   text inline all the time (see the "Available credit" label above). */
.myaccount-dashboard-stat-label { position: relative; }
.dp-info-tip-wrap { display: inline-block; position: relative; }
.dp-info-tip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; margin-left: 4px; padding: 0;
  border-radius: 50%; border: 1px solid var(--steel); background: transparent;
  color: var(--steel); font-size: 10px; font-weight: 700; line-height: 1;
  cursor: pointer; vertical-align: middle;
}
.dp-info-tip:hover, .dp-info-tip[aria-expanded="true"] { border-color: var(--blueprint); color: var(--blueprint); }
.dp-info-tip-panel {
  position: absolute; z-index: 5; top: calc(100% + 8px); left: 0; width: 240px;
  background: var(--ink); color: var(--paper); font-size: 12px; font-weight: 400;
  line-height: 1.5; text-transform: none; letter-spacing: normal;
  border-radius: var(--radius); padding: 10px 12px; box-shadow: 0 6px 20px rgba(0,0,0,.18);
}

/* Invoices tab (see inc/account-invoice.php). */
.myaccount-invoices-empty {
  color: var(--steel); font-size: 13.5px; background: var(--paper); border: 1px dashed var(--line);
  border-radius: var(--radius); padding: 20px; text-align: center; margin: 0;
}
.myaccount-invoices-table .myaccount-invoices-action { text-align: right; }
.myaccount-invoices-table .btn { padding: 7px 14px; font-size: 12.5px; }

/* Notifications tab (see inc/account-notifications.php). */
.myaccount-notifications-lead { color: var(--steel); font-size: 13.5px; margin: 0 0 20px; }
.myaccount-notifications-form { display: flex; flex-direction: column; gap: 4px; max-width: 480px; }
.myaccount-notify-row {
  display: flex; align-items: flex-start; gap: 12px; padding: 14px 4px; border-bottom: 1px solid var(--line); cursor: pointer;
}
.myaccount-notify-row input[type="checkbox"] { margin-top: 3px; flex-shrink: 0; }
.myaccount-notify-row span { display: flex; flex-direction: column; gap: 2px; }
.myaccount-notify-row strong { font-size: 14px; color: var(--ink); }
.myaccount-notify-row small { font-size: 12.5px; color: var(--steel); }
.myaccount-notifications-form button { margin-top: 26px !important; align-self: flex-start; }

@media (max-width: 760px) {
  /* min-width: 0 on both rows — a grid item's default min-width is auto
     (its content's min-content size), not 0. .myaccount-nav's pill strip
     scrolls internally (overflow-x: auto on the <ul> below), but that
     doesn't stop .myaccount-nav ITSELF from reporting the pills' full
     unwrapped width as its min-content contribution, which was forcing
     this single grid *column* — and the whole page along with it — wider
     than the viewport instead of actually clipping/scrolling in place.
     This is the standard fix for that CSS grid/flexbox gotcha. */
  .myaccount-layout { grid-template-columns: 1fr; gap: 16px; }
  .myaccount-layout > * { min-width: 0; }
  .myaccount-content { padding: 20px; }
  .myaccount-login { margin: 24px auto; padding: 24px 20px; }

  /* The desktop sidebar (6 stacked links) reads fine down the left edge
     next to the content, but stacked full-width above it on a phone, it
     pushes every page's actual content — the one order someone tapped
     "View" to see, the address they're editing — below a full screen of
     nav first. A horizontal, swipeable tab strip keeps the same "where am
     I / where else can I go" job without the scroll tax. */
  .myaccount-nav {
    position: sticky; top: var(--sticky-top); z-index: 5;
    background: var(--paper); margin: 0 -24px; padding: 0 24px;
    border-bottom: 1px solid var(--line); min-width: 0;
  }
  .woocommerce-MyAccount-navigation ul {
    flex-direction: row; flex-wrap: nowrap; gap: 4px; overflow-x: auto;
    -webkit-overflow-scrolling: touch; scrollbar-width: none; padding: 10px 0;
  }
  .woocommerce-MyAccount-navigation ul::-webkit-scrollbar { display: none; }
  .woocommerce-MyAccount-navigation li { flex: 0 0 auto; }
  .woocommerce-MyAccount-navigation li a {
    white-space: nowrap; padding: 8px 14px; font-size: 13px;
    background: var(--paper-raised); border: 1px solid var(--line); border-radius: 999px;
  }
  .woocommerce-MyAccount-navigation li.is-active a { border-color: var(--blueprint); }
  /* Sits at the end of the same scroll row by DOM order already — order:1
     just keeps it visually last even though flex-wrap could otherwise let
     it climb if an item's label wraps, and drops the desktop divider
     (border-top reads as a stray line partway through a horizontal row). */
  .woocommerce-MyAccount-navigation li.woocommerce-MyAccount-navigation-link--customer-logout {
    order: 1; margin-top: 0; padding-top: 0; border-top: none;
  }
  .woocommerce-MyAccount-navigation li.woocommerce-MyAccount-navigation-link--customer-logout a {
    background: transparent; color: var(--steel);
  }
}

/* ---------------------------------------------------------------------------
   Parts with no price — the SKUs neither supplier could quote, listed so a
   search for that part number still finds this shop. They can't be bought,
   so the page says that plainly instead of leaving the price/availability
   blocks empty (which read as a page that failed to load, not as an answer).
   See woocommerce/single-product.php and directparts_product_card().
--------------------------------------------------------------------------- */
.single-price-unavailable {
  display: inline-flex; align-items: center;
  font-family: var(--font-body); font-size: 15px; font-weight: 700;
  color: #8A5A12; background: rgba(232,173,83,.14); border: 1px solid rgba(232,173,83,.35);
  border-radius: 999px; padding: 7px 16px; margin-bottom: 14px;
  /* Same amber tint already used for the netto badge (.price-net-label) on
     a buyable product — "Price on request" needs to read with the same
     weight a real price would carry here, not blend into the paragraph
     below it as a footnote. */
}
.single-availability-unavailable { color: var(--ink); max-width: 46ch; line-height: 1.5; }
.single-unavailable-cta { display: inline-block; margin: 18px 0 22px; }
.product-price-unavailable {
  font-family: var(--font-body); font-size: 13px; font-weight: 700;
  color: #8A5A12; background: rgba(232,173,83,.14); border: 1px solid rgba(232,173,83,.35);
  border-radius: 999px; padding: 4px 10px;
  /* Same amber-pill treatment as the single-product page's price-on-request
     badge — a plain gray line here read as noticeably fainter than every
     other card's bold price, making the whole card feel unfinished rather
     than a deliberate "no price for this one" state. */
}

/* Contact-form honeypot (see directparts_contact_form_looks_like_spam() in
   functions.php) — visually and semantically hidden, but present in the DOM
   and tabbable-out-of-reach, which is what makes it invisible to a real
   visitor while still catching a generic bot that fills every field it finds. */
.dp-honeypot { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ---------------------------------------------------------------------------
   Catalog grid: long unbreakable strings must not widen the grid tracks.

   A `1fr` track is `minmax(auto, 1fr)`, and that `auto` minimum resolves to
   the item's min-content width — so a single long unbreakable product name
   or catalog number (e.g. "ABGASTEMPERATURSENSOR") stretched its column and
   pushed the whole grid past the viewport: on a 375px phone the grid measured
   400px and the page scrolled sideways with the right-hand cards cut off.
   minmax(0, 1fr) lets the tracks shrink as intended; the wrapping rules below
   are the other half of the fix, so the long word breaks instead of spilling
   out of its own card. */
.products-grid,
ul.products {
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)) !important;
}
.products-grid > *,
ul.products > * { min-width: 0; }

.product-card .product-title,
.product-card .product-sku,
.woocommerce ul.products li.product .woocommerce-loop-product__title {
  overflow-wrap: anywhere;
  word-break: break-word;
}

@media (max-width: 760px) {
  .products-grid,
  ul.products { grid-template-columns: repeat(3, minmax(0, 1fr)) !important; }
  body.home .products-grid { grid-template-columns: repeat(3, minmax(0, 1fr)) !important; }
}

/* ---------------------------------------------------------------------------
   Catalog pagination.

   paginate_links() was being printed raw into a bare <div>, so the only way
   through 1,105 pages of catalog was a row of unstyled default-blue browser
   links sitting under a carefully designed product grid. Same visual language
   as the rest of the site: bordered square controls, amber for the current
   page, monospace digits so the numbers line up. */
.catalog-results .page-numbers,
.dp-pagination .page-numbers {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 40px;
  height: 40px;
  padding: 0 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--paper-raised);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 14px;
  font-variant-numeric: tabular-nums;
  text-decoration: none;
  transition: border-color .15s ease, background-color .15s ease;
}
.catalog-results a.page-numbers:hover,
.dp-pagination a.page-numbers:hover {
  border-color: var(--blueprint);
  background: var(--blueprint);
  color: var(--blueprint-ink);
}
.catalog-results .page-numbers.current,
.dp-pagination .page-numbers.current {
  background: var(--torque);
  border-color: var(--torque);
  color: var(--torque-ink);
  font-weight: 600;
}
.catalog-results .page-numbers.dots,
.dp-pagination .page-numbers.dots {
  border-color: transparent;
  background: transparent;
  min-width: 24px;
  padding: 0 4px;
}
.dp-pagination {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
  margin: 8px 0 56px;
}
@media (max-width: 760px) {
  .catalog-results .page-numbers,
  .dp-pagination .page-numbers { min-width: 36px; height: 36px; padding: 0 8px; font-size: 13px; }
}
