/* ── Reset & Variables ── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* Clinical Premium SaaS palette + typography (phase-A: tokens only).
   Bright #F7F9FC page surface, white cards, slate text, signal-red
   accent. Space Grotesk drives display, Inter carries UI/body.
   This phase swaps tokens only — every component rule below is
   unchanged so layout dimensions stay identical to the previous
   build. */
:root {
  /* Clinical Premium palette */
  --bg-main:        #F7F9FC;    /* page background */
  --bg-secondary:   #F1F4F8;    /* tray / muted panel */
  --color-accent:   #9F2942;    /* signal red */
  --color-accent-hover: #8A243A;
  --text-title:     #111827;    /* slate-900 — headings */
  --text-body:      #111827;    /* slate-900 — body */
  --surface-card:   #FFFFFF;
  --border-light:   #E5E7EB;    /* slate-200 */

  /* Legacy aliases — concrete hex, no var() chains, so cascade
     never depends on multi-step custom-property resolution. */
  --bg:           #F7F9FC;
  --bg-card:      #FFFFFF;
  --bg-sidebar:   #FFFFFF;
  --border:       #E5E7EB;
  --text:         #111827;
  --text-muted:   #6B7280;
  --text-sub:     #6B7280;
  --text-faint:   #9CA3AF;
  --accent:       #9F2942;
  --accent-hover: #8A243A;
  --accent-light: #F6E8ED;
  --accent-border:#DFC2CC;
  --success:      #0F9D58;
  --success-bg:   #E6F4EA;
  --warning:      #D97706;
  --warning-bg:   #FEF3C7;
  --danger:       #DC2626;
  --danger-bg:    #FEE2E2;
  --info:         #2563EB;
  --info-bg:      #EFF6FF;
  --topbar-h:     58px;
  --sidebar-w:    0px;
  --radius:       4px;
  --shadow-sm:    0 1px 2px rgba(17,24,39,0.04);
  --shadow:       0 4px 12px rgba(17,24,39,0.05);
  --shadow-md:    0 10px 30px rgba(17,24,39,0.06);
  --sans:         'Inter', system-ui, -apple-system, sans-serif;
  --serif:        'Space Grotesk', system-ui, -apple-system, sans-serif;
  --mono:         'Inter', system-ui, -apple-system, sans-serif;
  --body:         'Inter', system-ui, -apple-system, sans-serif;

  /* ── Type scale — calibrated. h1 ramps 30→40→48→56→64 across
        the breakpoint ladder (was 34→48→56→64→72 — too dominant
        for a working B2B environment). Stat numbers and body
        copy come down in proportion so the hierarchy stays
        intact but no element shouts. */
  --fs-h1:      1.875rem;     /* 30px */
  --fs-h2:      1.625rem;     /* 26px */
  --fs-h3:      1.25rem;      /* 20px */
  --fs-h4:      1.0625rem;    /* 17px */
  --fs-stat:    1.75rem;      /* 28px */
  --fs-body-lg: 1.0625rem;    /* 17px */
  --fs-body:    0.9375rem;    /* 15px */
  --fs-body-sm: 0.8125rem;    /* 13px */
  --fs-label:   0.6875rem;    /* 11px */

  /* ── Component dimensions + spacing (mobile-first, refined). ── */
  --btn-h:      44px;
  --btn-px:     18px;
  --input-h:    48px;
  --space-card: 18px;
  --space-grid-gap: 16px;
  --space-section: 48px;
  --max-content:  1440px;
  --max-reading:   900px;
  --max-form:      520px;
}

@media (min-width: 768px) {
  :root {
    --fs-h1:      2.125rem;   /* 34px (mobile-large) */
    --fs-h2:      1.75rem;    /* 28px */
    --fs-h3:      1.375rem;   /* 22px */
    --fs-h4:      1.125rem;   /* 18px */
    --fs-stat:    2rem;       /* 32px */
    --fs-body-lg: 1.125rem;   /* 18px */
    --fs-body:    1rem;       /* 16px */
    --fs-body-sm: 0.875rem;   /* 14px */
    --fs-label:   0.75rem;    /* 12px */
    --btn-h:      46px;
    --input-h:    50px;
    --space-card: 22px;
    --space-grid-gap: 20px;
    --space-section: 64px;
  }
}
@media (min-width: 1024px) {
  :root {
    --fs-h1:      2.5rem;     /* 40px (laptop) */
    --fs-h2:      2rem;       /* 32px */
    --fs-h3:      1.5rem;     /* 24px */
    --fs-h4:      1.25rem;    /* 20px */
    --fs-stat:    2.25rem;    /* 36px */
    --fs-body-lg: 1.1875rem;  /* 19px */
    --fs-body:    1.0625rem;  /* 17px */
    --btn-h:      48px;
    --btn-px:     24px;
    --input-h:    52px;
    --space-card: 24px;
    --space-grid-gap: 24px;
    --space-section: 80px;
  }
}
@media (min-width: 1280px) {
  :root {
    --fs-h1:      3rem;       /* 48px (desktop) */
    --fs-h2:      2.25rem;    /* 36px */
    --fs-h3:      1.625rem;   /* 26px */
    --fs-stat:    2.5rem;     /* 40px */
    --space-card: 28px;
    --space-section: 96px;
  }
}
@media (min-width: 1440px) {
  :root {
    --fs-h1:      3.5rem;     /* 56px (desktop large) */
    --fs-h2:      2.5rem;     /* 40px */
    --space-section: 112px;
  }
}
@media (min-width: 1680px) {
  :root {
    --fs-h1:      4rem;       /* 64px (XL displays only) */
  }
}

html {
  font-size: 16px;
  /* iOS Safari auto-zooms text inside position:fixed popovers when
     this is left at the default `auto`, blowing up the dropdown
     option font on mobile. Pin to 100% so option labels render at
     the size CSS asks for. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  background: var(--bg-main);
  color: var(--text-body);
  font-family: var(--body);
  font-size: var(--fs-body);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

/* Display layer (h1-h4, article / stat / hero titles) uses
   --serif (Space Grotesk) at weight 600. UI / body / labels use
   --sans (Inter) via the cascade. NO uppercase by default —
   eyebrow / chip / filter classes opt-in below. */
h1, h2, h3, h4, h5, h6,
.article-title, .product-detail-title, .stat-value {
  font-family: var(--serif);
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--text-title);
  text-transform: none;
}
h1, .article-title, .product-detail-title { font-size: var(--fs-h1); line-height: 1.05; letter-spacing: -0.03em; }
h2 { font-size: var(--fs-h2); line-height: 1.1; }
h3 { font-size: var(--fs-h3); line-height: 1.18; }
h4 { font-size: var(--fs-h4); line-height: 1.25; }
.stat-value { font-size: var(--fs-stat); line-height: 1; letter-spacing: -0.025em; }

p { font-size: var(--fs-body); line-height: 1.65; }
.body-large { font-size: var(--fs-body-lg); line-height: 1.7; }
.body-small { font-size: var(--fs-body-sm); color: var(--text-secondary, var(--text-muted)); }

.section-eyebrow,
.article-tag-chip,
.field-label {
  font-family: var(--sans);
  font-weight: 300;
  font-size: 0.875rem;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  color: var(--text-muted);
}
a { color: var(--color-accent); text-decoration: none; }
a:hover { color: var(--color-accent-hover); }

/* ── Topbar (clinical) ─────────────────────────────────────── */
.topbar {
  background: var(--bg-card);
  border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 50;
}
.topbar-inner {
  display: flex; align-items: center; gap: 12px;
  max-width: var(--max-content);
  margin: 0 auto;
  padding: 0 24px;
  min-height: var(--topbar-h);
}
.topbar-brand { display: flex; align-items: center; }
.brand-logo   { display: block; width: auto; }
.topbar-brand .brand-logo { height: 32px; }
.login-brand  .brand-logo { height: 54px; margin: 0 auto; }

.topbar-nav {
  display: flex; align-items: stretch;
  margin-left: 20px; gap: 2px;
  /* min-width:0 lets the flex algorithm shrink the nav below its
     min-content if the right-side cluster (CTA / user-area / Logout)
     is competing for room. fitTopbarNav() in portal.js then walks
     items right-to-left into the More dropdown until the bar fits
     again — see assets/js/portal.js. We deliberately keep overflow
     visible here: the More dropdown is an absolutely-positioned
     descendant of the nav, and any clip on this ancestor (overflow:
     clip / hidden / contain: paint) would also clip the dropdown,
     producing the "Companie…" cut-off effect. The nav-overflow
     safety net is JS, not CSS. */
  min-width: 0;
}
.topbar-nav-item {
  position: relative;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 0 14px;
  height: var(--topbar-h);
  color: var(--text-muted);
  font-family: var(--sans);
  font-size: 0.9375rem; font-weight: 500;
  letter-spacing: 0;
  text-decoration: none;
  transition: color .25s ease, background .25s ease;
}
.topbar-nav-item:hover    { color: var(--text); }
/* Active state: wine ink + soft accent-light tinted background
   (--accent-light = #F6E8ED) + 2px underline. The tint stays
   gentle so the navbar reads as Scandinavian-minimal rather
   than highlighted with a hard pill. */
.topbar-nav-item.is-active {
  color: var(--accent) !important;
  font-weight: 500 !important;
  background: var(--accent-light) !important;
}
.topbar-nav-item.is-active::after {
  content: '';
  position: absolute;
  left: 14px; right: 14px; bottom: 0;
  height: 2px;
  background: var(--accent);
}
.topbar-nav-badge {
  font-family: var(--mono);
  font-size: 10px; font-weight: 500; letter-spacing: 0;
  padding: 1px 6px;
  color: #fff; background: var(--accent);
}

/* ── Dropdown nav group ─────────────────────────────────────────
   Shop is the only dropdown so far, but the markup is generic so
   any nav item with `children` gets the same treatment. Hover
   on desktop, click-toggle on touch (handled via .is-open in JS). */
.topbar-nav-group { position: relative; display: inline-flex; align-items: stretch; }
/* Group items (Shop, More …) carry a caret on their right edge. The
   .topbar-nav-item already supplies a 10px flex-gap between its
   children, so the caret needs no extra left margin — and the right
   padding only needs to leave breathing room for the caret itself,
   not for a phantom label after it. */
.topbar-nav-group > .topbar-nav-item { padding-right: 8px; }
.topbar-nav-caret {
  margin-left: 0;
  color: inherit;
  opacity: .85;
  transition: transform .18s;
  flex-shrink: 0;
}
.topbar-nav-group:hover .topbar-nav-caret,
.topbar-nav-group.is-open .topbar-nav-caret { transform: rotate(180deg); }

.topbar-dropdown {
  position: absolute;
  top: 100%; left: 0;
  min-width: 180px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-top: 2px solid var(--accent);
  box-shadow: 0 6px 16px rgba(15,20,24,.08);
  display: none;
  z-index: 80;
  padding: 4px 0;
}
.topbar-nav-group:hover .topbar-dropdown,
.topbar-nav-group.is-open .topbar-dropdown { display: block; }

/* ── Catalog facet panel ───────────────────────────────────────────
   In-page section on /devices that lists three browse-by-X axes
   (Areas of use / Brands / Technologies). Each item deep-links to
   /devices with the matching facet pre-applied. Auto-fit grid
   means the columns wrap naturally on narrower viewports without
   media-query gymnastics. */
.catalog-mega {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 24px 36px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 22px 24px 18px;
  margin: 0 0 22px;
}
.catalog-mega-col { display: flex; flex-direction: column; min-width: 0; }
.catalog-mega-title {
  font-family: 'Space Grotesk', sans-serif;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--text);
  margin: 0 0 10px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border-light);
}
.catalog-mega-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
/* By default each column shows its first 10 entries — anything past
   that hides behind a "Show all (N)" affordance. Expanding one
   column is column-scoped: the `.is-expanded` class lives only on
   the column the visitor clicked, so the rest of the panel keeps
   its compact layout. */
.catalog-mega-list > li:nth-child(n+11) { display: none; }
.catalog-mega-col.is-expanded .catalog-mega-list > li:nth-child(n+11) { display: list-item; }
.catalog-mega-expand {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: 8px;
  padding: 4px 0;
  background: none;
  border: none;
  border-top: 1px solid var(--border-light);
  width: 100%;
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  color: var(--accent);
  letter-spacing: 0.02em;
  cursor: pointer;
  text-align: left;
}
.catalog-mega-expand:hover { color: var(--accent-dark, var(--accent)); filter: brightness(0.95); }
/* Show / Hide labels swap based on the column's expanded state. */
.catalog-mega-expand-expanded   { display: none; }
.catalog-mega-col.is-expanded .catalog-mega-expand-collapsed { display: none; }
.catalog-mega-col.is-expanded .catalog-mega-expand-expanded  { display: inline; }
.catalog-mega-list li { margin: 0; }
.catalog-mega-list a {
  display: block;
  padding: 7px 0;
  font-size: 13.5px;
  color: var(--text-muted);
  text-decoration: none;
  transition: color .12s;
  letter-spacing: 0.01em;
}
.catalog-mega-list a:hover { color: var(--accent); }
.catalog-mega-see-all {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--border-light);
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--accent);
  text-decoration: none;
  letter-spacing: 0.02em;
}
.catalog-mega-see-all:hover { color: var(--accent-dark, var(--accent)); }
.catalog-mega-see-all svg { transition: transform .12s; }
.catalog-mega-see-all:hover svg { transform: translateX(2px); }

/* Phone layout: stack columns, tighten padding, the list items
   take a denser vertical rhythm. */
@media (max-width: 640px) {
  .catalog-mega {
    grid-template-columns: 1fr;
    gap: 16px;
    padding: 16px 18px 14px;
    margin-bottom: 16px;
  }
  .catalog-mega-title { padding-bottom: 6px; margin-bottom: 4px; }
  .catalog-mega-list a { padding: 5px 0; font-size: 13px; }
  .catalog-mega-see-all { margin-top: 8px; padding-top: 8px; }
}

/* ── Catalog active filter chips ─────────────────────────────
   When the visitor lands on /devices with brand=, area=, or
   tech= in the URL, the mega panel is hidden and each active
   value surfaces here as a removable chip. Clicking × strips
   that value from the URL and reloads. The wrapper also carries
   a "Show categories" toggle so the visitor can bring the mega
   panel back without having to clear filters first. */
.catalog-active-chips-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 0 0 14px;
}
.catalog-active-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.catalog-mega-toggle,
.catalog-back-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 4px;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--text);
  cursor: pointer;
  font-family: inherit;
  text-decoration: none;
  transition: background .12s, border-color .12s, color .12s;
}
.catalog-mega-toggle:hover,
.catalog-back-link:hover {
  background: var(--bg);
  border-color: var(--accent);
  color: var(--accent);
}
/* The "back to all devices" link is the primary exit — give it the
   accent treatment so visitors don't have to puzzle over which X to
   click to undo a filter selection. */
.catalog-back-link {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.catalog-back-link:hover {
  background: var(--accent-dark, var(--accent));
  border-color: var(--accent-dark, var(--accent));
  color: #fff;
  filter: brightness(0.95);
}
.catalog-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px 6px 12px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 12.5px;
  color: var(--text);
  cursor: pointer;
  transition: background .12s, border-color .12s;
  font-family: inherit;
}
.catalog-chip:hover { background: var(--bg); border-color: var(--accent); }
.catalog-chip-label { white-space: nowrap; }
.catalog-chip-label strong { color: var(--text); font-weight: 600; }
.catalog-chip-x {
  display: inline-flex;
  align-items: center; justify-content: center;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: var(--bg);
  font-size: 14px;
  line-height: 1;
  color: var(--text-muted);
}
.catalog-chip:hover .catalog-chip-x { color: var(--accent); }

.topbar-dropdown-item {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px;
  padding: 10px 16px;
  color: var(--text-muted);
  font-size: 13px;
  text-decoration: none;
  letter-spacing: 0.02em;
  transition: color .12s, background .12s;
  white-space: nowrap;
}
.topbar-dropdown-item:hover {
  color: var(--text);
  background: var(--bg);
}
.topbar-dropdown-item.is-active {
  color: var(--accent);
  background: var(--accent-light);
  font-weight: 600;
}
.topbar-dropdown-badge {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0;
  padding: 1px 7px;
  color: #fff;
  background: var(--accent);
}

.topbar-spacer { flex: 1; }

/* Adaptive topbar collapse rules live further down the file (after
   the base .topbar-user / .topbar-cta declarations) so they actually
   override them at narrow widths. Search for "Adaptive topbar
   collapse" to find them.
*/

/* Burgundy primary call-to-action sitting inside the topbar, just
   before the user tile. Clients only — admins don't file requests.
   Compact-pill sizing lives in .topbar-inner .topbar-cta below at
   higher specificity so the .btn / .btn-sm cascade can't win it. */
.topbar-cta {
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
  flex-shrink: 0;
}
.topbar-cta svg { flex-shrink: 0; }
.topbar-inner .topbar-cta {
  padding: 4px 8px;
  gap: 4px;
  letter-spacing: 0;
}

/* 3-step progress indicator above the service-request form.
   The wrapper lays three circular dots connected by lines. The
   current step is burgundy, past steps are solid grey, future steps
   are outlined grey. Mobile stacks the dots slightly tighter. */
.sr-steps {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin: 4px 0 6px;
}
.sr-step-dot {
  width: 32px; height: 32px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--bg-card);
  color: var(--text-muted);
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 500;
  display: grid; place-items: center;
  flex-shrink: 0;
  transition: background .15s, border-color .15s, color .15s;
}
.sr-step-dot.is-current {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.sr-step-dot.is-done {
  background: var(--text);
  border-color: var(--text);
  color: #fff;
}
.sr-step-line {
  flex: 0 0 60px;
  height: 1px;
  background: var(--border);
}
.sr-step-title {
  text-align: center;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 22px;
}

/* Individual steps. Only the `is-active` one is rendered; the
   others still live in the DOM so their inputs submit with the
   form. */
.sr-step { display: none; }
.sr-step.is-active { display: block; }

/* Footer row per step: ← Back / Cancel on the left, Next → or
   Submit on the right. On mobile stacks to two full-width rows so
   the submit button doesn't get tucked in a corner. */
.sr-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 18px 0 32px;
}
@media (max-width: 600px) {
  .sr-nav { flex-direction: column-reverse; }
  .sr-nav .btn { width: 100%; justify-content: center; }
}

/* Collected-files chip list rendered below the upload input on the
   service-request form. Lets the user see what's already attached and
   drop items individually before submitting. */
.sr-file-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 10px;
}
.sr-file-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 12px;
  border: 1px solid var(--border);
  background: var(--bg-card);
  font-size: 13px;
  min-width: 0;
}
.sr-file-row-name {
  display: flex; align-items: baseline; gap: 8px;
  min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sr-file-row-name strong { color: var(--text); font-weight: 500; }
.sr-file-row-name span    { color: var(--text-muted); font-size: 11.5px; font-family: var(--mono); }
.sr-file-row-remove {
  background: transparent;
  border: 0;
  color: var(--text-muted);
  cursor: pointer;
  font-size: 18px;
  line-height: 1;
  padding: 0 4px;
}
.sr-file-row-remove:hover { color: var(--danger); }

.topbar-user-area {
  display: flex; align-items: center; gap: 12px;
  /* Never compress — the .topbar-spacer next to nav already
     pushes us to the right edge, but flex-shrink:0 here is what
     guarantees Logout never gets squeezed off-screen even when
     the nav (with overflow → More) plus CTA are demanding more
     room than the viewport has. */
  flex-shrink: 0;
}
.topbar-logout-form { flex-shrink: 0; }
.topbar-user {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 12px;
  border-left: 1px solid var(--border);
  min-width: 0;
}
.topbar-avatar {
  width: 32px; height: 32px;
  background: var(--accent); color: #fff;
  display: grid; place-items: center;
  font-family: var(--sans);
  font-size: 13px; font-weight: 600;
  flex-shrink: 0;
}
.topbar-user-meta { line-height: 1.2; min-width: 0; max-width: 220px; }
.topbar-user-email {
  font-size: 12.5px; color: var(--text); font-weight: 500;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.topbar-user-role {
  font-family: var(--mono); font-size: 10px; color: var(--text-muted);
  letter-spacing: 0.12em; margin-top: 1px;
}
.topbar-user-link {
  text-decoration: none; color: inherit; cursor: pointer;
  transition: background-color .12s ease;
  border-radius: 0;
}
.topbar-user-link:hover { background: rgba(17, 24, 39, 0.04); }
.topbar-logout-form { margin: 0; }
.topbar-logout-btn {
  background: transparent;
  border: 1px solid var(--border);
  padding: 7px 12px;
  color: var(--text-muted);
  cursor: pointer;
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--sans);
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: 0.02em;
  transition: color .12s, border-color .12s;
}
.topbar-logout-btn:hover { color: var(--accent); border-color: var(--accent); }
.topbar-logout-btn svg { display: block; width: 16px; height: 16px; }
.topbar-logout-label { white-space: nowrap; }
.topbar-menu-toggle {
  display: none;
  width: 36px; height: 36px;
  flex-direction: column; align-items: center; justify-content: center;
  gap: 5px;
  background: transparent; border: 1px solid var(--border); cursor: pointer; padding: 4px;
}
.topbar-menu-toggle span {
  display: block; width: 18px; height: 1.5px;
  background: var(--text-sub); transition: all .2s;
}

.overlay {
  display: none;
  position: fixed; inset: 0;
  background: rgba(15,20,24,.35);
  z-index: 40;
  backdrop-filter: blur(2px);
}
.overlay.active { display: block; }

/* ── Main content ───────────────────────────────────────────── */
.main-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: calc(100vh - var(--topbar-h));
}
.page-inner {
  padding: 28px 32px 40px;
  max-width: var(--max-content);
  width: 100%;
  margin: 0 auto;
  flex: 1;
  min-width: 0;
}
.page-inner.is-reading { max-width: var(--max-reading); }
.page-inner.is-form    { max-width: var(--max-form); }

/* Impersonate banner */
.impersonate-bar {
  background: #111417; color: #fff;
  padding: 10px 32px;
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; font-size: 13px; flex-wrap: wrap;
}
.impersonate-label {
  color: var(--accent); font-family: var(--mono);
  letter-spacing: 0.12em; text-transform: uppercase; font-size: 11px;
}
.impersonate-back {
  color: #fff !important;
  border-color: rgba(255,255,255,.4) !important;
  background: transparent !important;
}

/* ── Breadcrumb + page header ──────────────────────────────── */
.breadcrumb {
  display: flex; align-items: center; gap: 8px;
  margin-bottom: 10px;
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--text-muted);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.breadcrumb a { color: var(--text-muted); text-decoration: none; }
.breadcrumb a:hover { color: var(--text); }
.breadcrumb .sep { color: var(--text-faint); }
.breadcrumb .current { color: var(--text); }

.page-header {
  display: flex;
  /* flex-start so action buttons (e.g. Edit on the device /
     company detail page) sit level with the h1 title at the top
     of the row instead of dropping to the bottom when the title
     block contains a subtitle + secondary action below it. */
  align-items: flex-start;
  justify-content: space-between;
  gap: 18px;
  flex-wrap: wrap;
  margin-bottom: 28px;
}
.page-header h1 {
  font-family: var(--serif);
  font-size: var(--fs-h1);
  font-weight: 600;
  color: var(--text);
  letter-spacing: -0.03em;
  line-height: 1.05;
  font-variant-numeric: tabular-nums lining-nums;
}
.page-subtitle {
  font-family: var(--sans);
  font-size: var(--fs-body-sm);
  color: var(--text-muted);
  letter-spacing: 0;
  text-transform: none;
  margin-top: 8px;
}

/* ── Buttons ────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center; justify-content: center;
  gap: 8px;
  height: var(--btn-h);
  padding: 0 var(--btn-px);
  font-family: var(--sans);
  font-size: 0.9375rem;       /* 15px desktop, 14px mobile via cascade */
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  cursor: pointer;
  border: 1px solid transparent;
  border-radius: 12px;
  transition: background-color .25s ease, color .25s ease, border-color .25s ease, box-shadow .25s ease;
  text-decoration: none;
  white-space: nowrap;
}
@media (max-width: 767px) { .btn { font-size: 0.875rem; } }
.btn:focus-visible { outline: none; box-shadow: 0 0 0 4px rgba(159,41,66,0.18); }
.btn-primary       { background: var(--color-accent); color: #fff; border: none; border-radius: 12px; }
.btn-primary:hover { background: var(--color-accent-hover); color: #fff; }
.btn-secondary     { background: #FFFFFF; color: var(--text); border: 1px solid var(--border); }
.btn-secondary:hover { background: var(--bg-secondary, #F1F4F8); color: var(--text); border-color: var(--border); }
.btn-sm            { height: 34px; padding: 0 12px; font-size: 0.8125rem; border-radius: 8px; }
.btn-ghost         { background: transparent; color: var(--text-muted); border: 1px solid transparent; }
.btn-ghost:hover   { color: var(--text); background: var(--bg-secondary, #F1F4F8); }

/* ── Cards ─────────────────────────────────────────────────── */
.card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: var(--space-card);
  margin-bottom: 16px;
  box-shadow: var(--shadow-sm);
}
.card-header {
  display: flex; align-items: baseline; justify-content: space-between;
  margin: calc(var(--space-card) * -1) calc(var(--space-card) * -1) 20px;
  padding: var(--space-card);
  border-bottom: 1px solid var(--border);
  gap: 12px; flex-wrap: wrap;
}
/* Let the title-block child of a card-header take up all the
   available space (flex: 1 1 0) so any sibling .btn keeps its
   natural width on the right. We use `flex-basis: 0` rather than
   `auto` because flex-wrap collects items into a line based on
   their basis, and `auto` resolves to max-content — when the
   subtitle is long ("LANGUAGES: RUSSIAN, ENGLISH, ESTONIAN")
   the basis exceeds the container before any shrinking happens
   and the button drops to a second row. With basis 0 each item
   starts at zero width, fits trivially, then flex-grow shares
   the remaining space — title block grows to fill, button stays
   at content width.

   :first-child guards us against the materials cards (and any
   future header with multiple wrapper divs), where a non-title
   actions wrapper would otherwise also pick up flex:1 and end up
   centred mid-row instead of anchoring to the right edge. */
.card-header > div:first-child:not(.card-title):not(.card-subtitle) {
  min-width: 0;
  flex: 1 1 0;
}
.card-header > .btn,
.card-header > a.btn,
.card-header > button.btn { flex-shrink: 0; }

/* Same trick for the page-level header on detail pages
   (devices, companies). Title block takes all available width;
   any action button on the right side keeps its natural size
   and anchors to the corner. */
.page-header > div { min-width: 0; flex: 1 1 0; }
.page-header > .btn,
.page-header > a.btn,
.page-header > button.btn { flex-shrink: 0; }
.card-title {
  font-family: var(--serif);
  font-size: 17px; font-weight: 600;
  color: var(--text); letter-spacing: -0.01em;
  text-transform: none;
}
.card-subtitle {
  font-family: var(--sans);
  font-size: 12px; color: var(--text-muted);
  margin-top: 4px;
  letter-spacing: 0.04em;
  text-transform: none;
}

/* ── Stats: monospace caps label, big serif number ─────────── */
.stats-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 14px;
  margin-bottom: 28px;
  max-width: 720px;
}
.stat-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 18px 20px;
  box-shadow: var(--shadow-sm);
}
.stat-card-link {
  display: block;
  color: inherit;
  text-decoration: none;
  transition: box-shadow .25s ease, transform .25s ease, border-color .25s ease;
}
.stat-card-link:hover {
  color: inherit;
  border-color: var(--border);
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}
.stat-label {
  font-family: var(--sans);
  font-size: 11px;
  color: var(--text-muted);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 500;
}
.stat-value {
  font-family: var(--serif);
  font-size: var(--fs-stat); font-weight: 600;
  color: var(--text); line-height: 1;
  margin-top: 8px;
  letter-spacing: -0.025em;
  font-variant-numeric: tabular-nums lining-nums;
}

/* ── Form fields: plain labels above input, mono uppercase —
      kept here because most pages reuse .form-group + .form-control.
      Design-wise the serif-heavy pages use mono labels; others still
      look fine with the current caps styling below. ──────────── */


/* ── Table ── */
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; width: 100%; }
table { width: 100%; border-collapse: collapse; }
th {
  font-size: 11px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .7px;
  color: var(--text-muted);
  padding: 9px 14px;
  border-bottom: 1px solid var(--border);
  text-align: left;
  white-space: nowrap;
}
td { padding: 12px 14px; border-bottom: 1px solid var(--border-light); font-size: 13px; color: var(--text-sub); }
tr:last-child td { border-bottom: none; }
tr:hover td { background: #faf9f7; }
td a { color: var(--text); font-weight: 500; }
td a:hover { color: var(--accent); }

/* ── Badges ── */
.badge {
  display: inline-flex;
  align-items: center;
  padding: 3px 8px;
  border-radius: 4px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .2px;
  white-space: nowrap;
}
.badge-success { background: var(--success-bg); color: var(--success); }
.badge-warning { background: var(--warning-bg); color: var(--warning); }
.badge-danger  { background: var(--danger-bg);  color: var(--danger); }
.perm-chip {
  display: inline-flex;
  align-items: center;
  padding: 2px 7px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text-sub);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .2px;
  white-space: nowrap;
}

/* ── Team card on company-detail ── */
.team-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.team-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  border: 1px solid var(--border-light);
  background: var(--bg);
  padding: 12px 14px;
}
.team-row.is-self {
  border-color: var(--accent);
  background: var(--bg-card);
}
.team-row-main {
  min-width: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.team-row-email {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  font-weight: 600;
  font-size: 13.5px;
  color: var(--text);
  word-break: break-word;
}
.team-row-perms {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.team-self-tag {
  display: inline-block;
  padding: 1px 6px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .4px;
  text-transform: uppercase;
  background: var(--accent);
  color: #fff;
}
.team-role-pill {
  display: inline-block;
  padding: 1px 7px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .3px;
  text-transform: uppercase;
  border: 1px solid var(--border);
  color: var(--text-sub);
}
.team-role-pill.team-role-owner       { color: var(--accent); border-color: var(--accent); }
.team-role-pill.team-role-salon-admin { color: var(--accent); border-color: var(--accent); opacity: .85; }
.team-row-actions { flex-shrink: 0; }
.team-perm-cell {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 13px;
  line-height: 1.4;
  cursor: pointer;
}
.team-perm-cell input { margin-top: 3px; }
@media (max-width: 540px) {
  .team-row { flex-direction: column; align-items: stretch; gap: 10px; }
  .team-row-actions .btn { width: 100%; }
}
.badge-info    { background: var(--info-bg);    color: var(--info); }
.badge-muted   { background: #f3f2ef; color: var(--text-muted); }

/* ── Info Grid ── */
.info-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px 24px; }
/* Two form-groups side by side on desktop, auto-stacked under ~520px
   regardless of any global .info-grid responsive overrides. Flex-wrap
   makes the breakpoint container-relative, so a narrow card collapses
   to one column even when the viewport is wide. */
.form-row-pair {
  display: flex;
  flex-wrap: wrap;
  gap: 16px 24px;
  /* Match the .form-group bottom margin so the next form element
     (e.g. Country under Website/Instagram on company-edit) doesn't
     butt up against the row when the inner cells reset their own
     margin-bottom to 0. */
  margin-bottom: 18px;
}
.form-row-pair > .form-group {
  flex: 1 1 240px;
  min-width: 0;
  margin-bottom: 0;
}
.info-item { min-width: 0; }
.info-item label { display: block; font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: .7px; margin-bottom: 3px; font-weight: 600; }
.info-item span  { font-size: 13.5px; color: var(--text); word-break: break-word; overflow-wrap: anywhere; }

/* ── Contact Fields (clinical: mono uppercase type pill, thin border) ── */
.contact-section-label {
  font-family: var(--mono);
  font-size: 9.5px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.18em;
  margin-bottom: 10px;
  font-weight: 500;
}
.contact-row {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 0;
  border-top: 1px solid var(--border-light);
}
.contact-row:first-child { border-top: none; }
.contact-type-badge {
  font-family: var(--sans);
  font-size: 0.6875rem;
  font-weight: 300;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-faint);
  background: transparent;
  border: 0;
  padding: 0;
  min-width: 64px;
  text-align: left;
  flex-shrink: 0;
}
.contact-value {
  font-size: 13px; color: var(--text);
  word-break: break-all;
  overflow-wrap: anywhere;
  min-width: 0;
}

/* ── Email subscriptions (clinical: dot + label / mono pill) ── */
.sub-list { display: flex; flex-direction: column; }
.sub-row {
  display: flex; align-items: center; justify-content: space-between;
  padding: 11px 0;
  border-top: 1px solid var(--border-light);
  gap: 12px;
}
.sub-row:first-child { border-top: none; }
.sub-row-label {
  display: flex; align-items: center; gap: 10px;
  font-size: 13px; color: var(--text);
  min-width: 0;
}
.sub-dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--text-faint);
  flex-shrink: 0;
}
.sub-dot.is-on { background: var(--success); }
.sub-pill {
  font-family: var(--sans);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
  background: var(--bg-secondary);
  border: 0;
  border-radius: 999px;
  padding: 5px 12px;
  flex-shrink: 0;
  line-height: 1.4;
}
.sub-pill.is-on {
  color: var(--success);
  background: var(--success-bg);
}
/* Button variant: re-assert font + padding because user-agent button
   styles otherwise reset both. Same shape, soft hover transition. */
button.sub-pill {
  cursor: pointer;
  transition: background-color .25s ease, color .25s ease, box-shadow .25s ease;
}
button.sub-pill:hover:not(:disabled) { background: #E5E7EB; color: var(--text); }
button.sub-pill.is-on:hover:not(:disabled) { background: #D9EBE0; color: var(--success); }
button.sub-pill:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(159,41,66,0.18);
}
button.sub-pill:disabled { cursor: default; opacity: .6; }

/* ── Colleagues ── */
.colleague-row {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border-light);
}
.colleague-row:last-child { border-bottom: none; }
.colleague-avatar {
  width: 32px; height: 32px;
  border-radius: 50%;
  background: #f0efeb;
  color: var(--text-sub);
  font-size: 11px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
.colleague-name { font-size: 13.5px; font-weight: 500; color: var(--text); }

/* ── Device Row (Dashboard) ── */
.device-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 0;
  border-bottom: 1px solid var(--border-light);
  gap: 12px;
  flex-wrap: wrap;
}
.device-row:last-child { border-bottom: none; }
.device-row-info { flex: 1; min-width: 0; overflow: hidden; }
.device-row-model { font-size: 13.5px; font-weight: 600; color: var(--text); word-break: break-word; }
.device-row-meta  { font-size: 12px; color: var(--text-muted); margin-top: 2px; word-break: break-word; overflow-wrap: anywhere; }
.device-row-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; flex-wrap: wrap; }

/* ── Device Cards (Equipment list) ── */
.device-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  transition: border-color .15s, box-shadow .15s;
  box-shadow: var(--shadow-sm);
}
.device-card:hover { border-color: #d0cdc8; box-shadow: var(--shadow); }
.device-card-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.device-model  { font-size: 14px; font-weight: 650; color: var(--text); }
.device-serial { font-size: 12px; color: var(--text-muted); margin-top: 2px; }
.device-grid   { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 16px; }
.device-meta { min-width: 0; }
.device-meta label { font-size: 11px; color: var(--text-muted); display: block; font-weight: 600; letter-spacing: .3px; }
.device-meta span  { font-size: 12.5px; color: var(--text-sub); display: block; overflow-wrap: anywhere; word-break: break-word; }
.device-cards-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 16px; margin-bottom: 24px; }

/* Footer strip for device cards — margin-top:auto bottom-aligns it
   inside the flex column so every "View details →" lines up across
   the grid regardless of how many meta rows each card has. */
.device-card-actions {
  display: flex;
  justify-content: flex-end;
  margin-top: auto;
  padding-top: 10px;
  border-top: 1px solid var(--border-light);
}

/* ── Dashboard 2-column grid: left = contact info, right = linked
      companies + email subscriptions stacked. Collapses to a single
      column below 900px so the contact card keeps breathing room on
      tablets / phones. ─────────────────────────────────────────── */
.dashboard-grid {
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: 20px;
  align-items: start;
}
.dashboard-main,
.dashboard-aside {
  display: flex;
  flex-direction: column;
  gap: 20px;
  min-width: 0;
}
/* The grid/aside use `gap` for spacing — suppress the default bottom
   margin on cards inside it so we don't stack 16px + 20px of gap. */
.dashboard-grid > .card,
.dashboard-aside .card { margin-bottom: 0; }
@media (max-width: 900px) {
  .dashboard-grid { grid-template-columns: 1fr; }
}

/* ── Clickable row used in the right-column "Linked Companies" card.
      Name + reg number on the left, subtle chevron on the right. ── */
.linked-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
  padding: 12px 24px;
  border-top: 1px solid var(--border-light);
  color: inherit;
  text-decoration: none;
  transition: background .12s;
  min-width: 0;
}
.linked-row:first-child { border-top: none; }
.linked-row:hover       { background: var(--bg); }
.linked-row-name        { font-size: 13.5px; color: var(--text); font-weight: 500; word-break: break-word; }
.linked-row-meta        { font-family: var(--mono); font-size: 11.5px; color: var(--text-muted); margin-top: 2px; }
.linked-row-arrow       { color: var(--text-faint); flex-shrink: 0; }

/* ── Subtle "view details" link used on cards instead of a filled
      button. Text + arrow, no chrome. ─────────────────────────── */
.link-action {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 500;
  color: var(--text);
  text-decoration: none;
  letter-spacing: 0.04em;
  padding: 4px 0;
  transition: color .12s, gap .12s;
  cursor: pointer;
  background: transparent;
  border: 0;
}
.link-action:hover { color: var(--accent); gap: 9px; }

/* ── "+N more" collapse used on company cards to cap their device
      list at the first 3 rows. Clicking the pill reveals the rest.
      Note: display is driven entirely by these rules — do NOT put
      `display:flex` on .more-row inline, or the "is-extra hidden"
      state gets overridden and every device ends up visible. */
.more-list {
  border-top: 1px solid var(--border-light);
  margin-top: 10px;
  padding-top: 8px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.more-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 13px;
  padding: 2px 0;
  gap: 10px;
  min-width: 0;
}
.more-row .more-row-text {
  min-width: 0;
  display: flex; flex-direction: column;
}
.more-row .more-row-label {
  font-weight: 500; color: var(--text);
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Location line under the device name — lighter and smaller so it
   reads as supporting detail, not another equally-weighted column. */
.more-row .more-row-sub {
  font-size: 11.5px;
  color: var(--text-muted);
  line-height: 1.35;
  margin-top: 1px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.more-list .more-row.is-extra            { display: none; }
.more-list.is-expanded .more-row.is-extra { display: flex; }
.more-list-btn {
  align-self: flex-start;
  margin-top: 4px;
  background: transparent;
  border: 0;
  padding: 4px 0;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  cursor: pointer;
}
.more-list-btn:hover              { color: var(--accent-hover); }
/* Default: "+N more" visible, "Show less" hidden; when the list is
   expanded those flip. Both buttons share .js-more-toggle so the same
   delegated click handler toggles the list either way. */
.more-list-btn[data-less]                       { display: none; }
.more-list.is-expanded .more-list-btn[data-more]{ display: none; }
.more-list.is-expanded .more-list-btn[data-less]{ display: inline-flex; }

/* ── Company card actions row: pinned to the bottom of the flex
      column so every card's "View details →" sits on the same line
      regardless of how many devices it has. ─────────────────── */
.company-actions {
  margin-top: auto;
  padding-top: 10px;
  border-top: 1px solid var(--border-light);
  display: flex;
  justify-content: flex-end;
}

/* ── Lean device card (clinical "My Devices" grid: whole card is a link,
      three sections divided by hairlines — identity / meta / Open →) ── */
.dev-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 14px;
}
.dev-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 0;
  display: flex;
  flex-direction: column;
  color: inherit;
  text-decoration: none;
  transition: border-color .15s, transform .15s;
}
.dev-card:hover {
  border-color: var(--text);
  transform: translateY(-1px);
}
.dev-card-head {
  padding: 18px 20px;
  border-bottom: 1px solid var(--border-light);
}
.dev-card-head .dev-name {
  font-family: var(--sans);
  font-size: 15px; font-weight: 600;
  color: var(--text);
  line-height: 1.3;
}
.dev-card-head .dev-serial {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--text-muted);
  margin-top: 4px;
}
.dev-card-body {
  padding: 14px 20px;
  display: flex; flex-direction: column; gap: 10px;
  flex: 1;
}
.dev-card-body .kv-label {
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.18em;
  color: var(--text-faint);
  text-transform: uppercase;
  margin-bottom: 2px;
}
.dev-card-body .kv-value {
  font-size: 12.5px;
  color: var(--text);
  word-break: break-word;
  overflow-wrap: anywhere;
}
.dev-card-foot {
  padding: 12px 20px;
  border-top: 1px solid var(--border-light);
  display: flex;
  justify-content: flex-end;
  align-items: center;
}
.dev-card-foot .dev-open {
  font-family: var(--sans);
  font-size: 11.5px;
  font-weight: 500;
  color: var(--text);
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* ── Timeline ── */
.timeline { position: relative; padding-left: 26px; }
.timeline::before { content: ''; position: absolute; left: 6px; top: 8px; bottom: 8px; width: 1px; background: var(--border); }
.timeline-item { position: relative; margin-bottom: 22px; }
.timeline-dot {
  position: absolute; left: -26px; top: 5px;
  width: 12px; height: 12px;
  border-radius: 50%;
  background: var(--bg-card);
  border: 2px solid var(--border);
}
.timeline-dot.dot-engineer { border-color: var(--accent); }
.timeline-dot.dot-closed   { border-color: var(--success); background: var(--success); }
.timeline-meta { font-size: 12px; color: var(--text-muted); margin-bottom: 6px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.timeline-author { font-weight: 600; color: var(--text-sub); }
.timeline-msg { font-size: 13px; color: var(--text-sub); background: #faf9f7; border: 1px solid var(--border-light); border-radius: 7px; padding: 10px 14px; line-height: 1.65; }

/* ── Materials (legacy list, kept for fallback) ── */
.material-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 0;
  border-bottom: 1px solid var(--border-light);
}
.material-item:last-child { border-bottom: none; }
.material-icon { color: var(--accent); flex-shrink: 0; opacity: .8; }
.material-title { font-size: 13px; color: var(--text); font-weight: 500; }
.material-meta  { font-size: 11.5px; color: var(--text-muted); margin-top: 2px; }
.material-action { margin-left: auto; flex-shrink: 0; }

/* ── SharePoint File Browser ── */
.sp-breadcrumb {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 4px 20px 10px;
  font-size: 13px;
  flex-wrap: wrap;
  min-height: 32px;
}
.sp-bc-seg {
  color: var(--accent);
  cursor: pointer;
  white-space: nowrap;
  font-weight: 500;
}
.sp-bc-seg:hover { text-decoration: underline; }
.sp-bc-seg.current { color: var(--text); cursor: default; font-weight: 600; }
.sp-bc-sep { color: var(--text-muted); margin: 0 2px; }

.sp-toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 20px;
  border-bottom: 1px solid var(--border-light);
  flex-wrap: wrap;
}

.sp-sel-bar {
  display: none;
  align-items: center;
  gap: 12px;
  padding: 8px 20px;
  background: var(--accent-light);
  border-bottom: 1px solid var(--border-light);
  font-size: 13px;
  font-weight: 600;
  color: var(--accent);
}
.sp-sel-bar.active { display: flex; }

/* ── Grid View ── */
.sp-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 2px;
  padding: 10px;
}

.sp-grid-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 12px 8px 10px;
  border-radius: 8px;
  cursor: pointer;
  position: relative;
  transition: background 0.12s;
  user-select: none;
}
.sp-grid-item:hover { background: rgba(0,0,0,.05); }
.sp-grid-item.sp-selected { background: rgba(168,36,32,.08); outline: 1.5px solid rgba(168,36,32,.25); outline-offset: -1.5px; border-radius: 8px; }

.sp-grid-thumb {
  width: 76px;
  height: 76px;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  margin-bottom: 8px;
}
.sp-grid-thumb img {
  width: 76px;
  height: 76px;
  object-fit: cover;
  border-radius: 5px;
  border: 1px solid var(--border-light);
}

.sp-grid-cb {
  position: absolute;
  top: -5px;
  left: -5px;
  z-index: 2;
  opacity: 0;
  transition: opacity 0.1s;
}
.sp-grid-item:hover .sp-grid-cb,
.sp-grid-item.sp-selected .sp-grid-cb { opacity: 1; }
.sp-grid-cb input { width: 16px; height: 16px; cursor: pointer; accent-color: var(--accent); }

.sp-grid-name {
  font-size: 12px;
  text-align: center;
  color: var(--text);
  word-break: break-word;
  line-height: 1.35;
  max-width: 108px;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.sp-grid-meta { font-size: 11px; color: var(--text-muted); margin-top: 3px; text-align: center; }

/* ── List View ── */
.sp-list { width: 100%; }
.sp-list-head,
.sp-list-row {
  display: grid;
  grid-template-columns: 36px 1fr 100px 80px 90px;
  align-items: center;
  padding: 7px 16px;
  border-bottom: 1px solid var(--border-light);
}
.sp-list-head {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .5px;
  color: var(--text-muted);
  font-weight: 600;
}
.sp-list-row {
  font-size: 13px;
  transition: background 0.1s;
  cursor: default;
}
.sp-list-row:last-child { border-bottom: none; }
.sp-list-row:hover { background: rgba(0,0,0,.04); }
.sp-list-row.sp-selected { background: rgba(168,36,32,.07); }
.sp-list-name-cell {
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  min-width: 0;
}
.sp-list-name-cell span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sp-list-date { color: var(--text-muted); font-size: 12px; }
.sp-list-size { color: var(--text-muted); font-size: 12px; }
.sp-list-acts { display: flex; justify-content: flex-end; }
.sp-list-check { display: flex; align-items: center; }
.sp-list-check input { accent-color: var(--accent); cursor: pointer; }

/* ── File type icons ── */
.sp-icon-wrap {
  width: 52px;
  height: 64px;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}
.sp-icon-folder-svg { width: 62px; height: 52px; }
.sp-icon-file {
  width: 42px;
  height: 54px;
  border-radius: 3px;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding-bottom: 8px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .3px;
  color: #fff;
  position: relative;
}
.sp-icon-file::before {
  content: '';
  position: absolute;
  top: 0; right: 0;
  width: 14px; height: 14px;
  background: rgba(255,255,255,.3);
  clip-path: polygon(0 0, 100% 100%, 100% 0);
}
.sp-icon-pdf   { background: #e53935; }
.sp-icon-doc   { background: #1976d2; }
.sp-icon-xls   { background: #388e3c; }
.sp-icon-ppt   { background: #e64a19; }
.sp-icon-img   { background: #6a1b9a; }
.sp-icon-zip   { background: #f57c00; }
.sp-icon-video { background: #c62828; }
.sp-icon-other { background: #607d8b; }

/* list view icon (smaller) */
.sp-list-icon { font-size: 20px; flex-shrink: 0; line-height: 1; }
.sp-list-icon svg { width: 22px; height: 18px; }

.sp-empty { text-align: center; padding: 48px 20px; color: var(--text-muted); font-size: 14px; }
.sp-loading { text-align: center; padding: 48px 20px; color: var(--text-muted); }

@media (max-width: 600px) {
  .sp-list-head,
  .sp-list-row { grid-template-columns: 36px 1fr 80px; }
  .sp-list-date,
  .sp-list-acts { display: none; }
  .sp-grid { grid-template-columns: repeat(auto-fill, minmax(90px, 1fr)); }

  /* Drop the "Modified" column on the JS-rendered SharePoint file list —
     filenames get clipped to 2-3 chars otherwise on a 390px phone.
     The Modified <col> is marked .sp-col-mod by the JS; the cells are
     targeted by :nth-child(3) (the third column in the rendered table). */
  .sp-file-table .sp-col-mod { width: 0 !important; }
  .sp-file-table thead th:nth-child(3),
  .sp-file-table tbody td:nth-child(3) { display: none !important; }
}

/* ── Forms (clinical style: mono uppercase labels, square inputs) ── */
.form-group { margin-bottom: 18px; }
.form-group label {
  display: block;
  font-family: var(--mono);
  font-size: 9.5px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.18em;
  margin-bottom: 8px;
  font-weight: 500;
}
.form-control {
  width: 100%;
  height: var(--input-h);
  background: #FFFFFF;
  border: 1px solid var(--border);
  border-radius: 12px;
  color: var(--text);
  padding: 0 16px;
  font-family: var(--sans);
  font-size: 0.9375rem;
  outline: none;
  transition: border-color .25s ease, box-shadow .25s ease, background .25s ease;
  -webkit-appearance: none;
}
.form-control:hover { border-color: #D1D5DB; }
.form-control:focus { border-color: var(--color-accent); background: #fff; box-shadow: 0 0 0 4px rgba(159,41,66,0.18); }
.form-control::placeholder { color: var(--text-faint); }

/* Read-only value rendered in place of a form input. Deliberately looks
   nothing like an editable field so the user doesn't try to click into it. */
.readonly-value {
    display: block;
    padding: 9px 12px;
    background: transparent;
    border: 0;
    border-bottom: 1px dashed var(--border);
    color: var(--text-sub);
    font-size: 13px;
    min-height: 20px;
    line-height: 1.5;
    cursor: default;
    user-select: text;
}
.readonly-value.readonly-empty { color: var(--text-muted); font-style: italic; }
.readonly-list { margin: 0; padding: 0; list-style: none; }
.readonly-list li {
    padding: 6px 0;
    border-bottom: 1px dashed var(--border);
    font-size: 13px;
    color: var(--text-sub);
}
.readonly-list li:last-child { border-bottom: 0; }
.readonly-list li::before { content: "•  "; color: var(--text-muted); }
textarea.form-control { height: auto; resize: vertical; min-height: 96px; padding: 14px 18px; line-height: 1.55; }
/* Native <select>: inline-SVG caret on the right, OS arrow hidden.
   The dropdown panel itself is still drawn by the browser/OS — full
   theming there would need a JS replacement. */
select.form-control {
  padding-right: 40px;
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'><path d='M1 1L6 6L11 1' stroke='%236B7280' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-position: right 16px center;
  background-size: 12px 8px;
  cursor: pointer;
}
select.form-control:focus { background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'><path d='M1 1L6 6L11 1' stroke='%239F2942' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/></svg>"); }
select.form-control::-ms-expand { display: none; }

/* ── Custom <select> picker (assets/js/custom-select.js) ─────────
   The native <select> is moved off-screen but kept in DOM for form
   submit; a button + listbox sits in its place. The toggle inherits
   every class from the original select (.form-control, .contact-
   type-select, …) so pre-existing sizing rules already style it. */
.js-select { position: relative; display: block; }
.js-select-native {
  position: absolute !important;
  width: 1px !important; height: 1px !important;
  padding: 0 !important; margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0,0,0,0) !important;
  white-space: nowrap !important;
  border: 0 !important;
  pointer-events: none !important;
  opacity: 0 !important;
}
.js-select-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  text-align: left;
  cursor: pointer;
  background-color: #FFFFFF;
  background-image: none !important;
  font-family: var(--sans);
  color: var(--text);
  padding-right: 14px;
  gap: 12px;
}
/* Baseline appearance for <select>s that didn't have .form-control
   on the source element (e.g. /articles filter toolbar). Adds
   border + radius + height so the toggle reads as a styled control
   instead of falling through to the OS button default. Scoped via
   :not(.form-control) so .form-control selects keep their own
   sizing tokens untouched. */
.js-select-toggle:not(.form-control) {
  height: 36px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 0.875rem;
}
.js-select-toggle:hover { border-color: #D1D5DB; }
.js-select.is-open > .js-select-toggle,
.js-select-toggle:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 4px rgba(159,41,66,0.18);
}
.js-select-toggle[disabled],
.js-select.is-disabled .js-select-toggle {
  background: var(--bg-secondary);
  color: var(--text-muted);
  cursor: not-allowed;
}
.js-select-label {
  flex: 1; min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.js-select-label.is-placeholder { color: var(--text-faint); }
.js-select-chevron {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  color: var(--text-muted);
  transition: transform .25s ease, color .25s ease;
}
.js-select.is-open > .js-select-toggle .js-select-chevron {
  transform: rotate(180deg);
  color: var(--accent);
}

.js-select-menu {
  /* position:fixed so the menu escapes any overflow:hidden ancestor
     (cards, modals, scroll containers). JS writes inline left/top
     /bottom/width based on the toggle's getBoundingClientRect each
     time the menu opens, and re-runs on scroll / resize so the
     menu stays anchored. */
  display: none;
  position: fixed;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow-md);
  padding: 6px;
  z-index: 1000;
  /* Floor for tiny filter toggles so the menu stays readable.
     The hard cap is the viewport — JS sets the inline width to
     match the toggle, so a full-width <select> (e.g. the device
     picker on /request-new) opens a full-width menu and option
     labels render in full instead of truncating mid-word. */
  min-width: 200px;
  max-width: calc(100vw - 24px);
  max-height: 280px;
  overflow-y: auto;
  font-family: var(--sans);
  font-size: 0.9375rem;
  transform-origin: top center;
}
.js-select-menu.is-open { display: block; animation: js-select-pop .14s ease-out; }
.js-select-menu.is-up { transform-origin: bottom center; }
@keyframes js-select-pop {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}

.js-select-option {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px;
  border-radius: 8px;
  color: var(--text);
  /* Absolute font-size so iOS Safari can't decide to auto-bump
     option labels to 30+px because they "look small" inside a
     position:fixed popover. */
  font-size: 15px;
  line-height: 1.35;
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.js-select-option:hover,
.js-select-option.is-active { background: var(--bg-secondary); }
.js-select-option[aria-selected="true"] {
  color: var(--accent);
  font-weight: 500;
  background: var(--accent-light);
}
.js-select-option[data-disabled="true"] {
  color: var(--text-faint);
  cursor: not-allowed;
}
.js-select-option[data-disabled="true"]:hover { background: transparent; }

/* ── Custom checkbox + radio ─────────────────────────────────
   Strip the native control and rebuild it in brand chrome —
   square 18px box with a wine fill + white tick when checked,
   round 18px ring with an inset wine dot for radios. Keeps the
   native focusring replaced with our 4px wine focus ring.
   .nl-item explicitly opts back into the native look further
   down (it uses accent-color:green for the dashboard newsletter
   list and we don't want to break that). */
input[type="checkbox"],
input[type="radio"] {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  display: inline-block;
  vertical-align: middle;
  margin: 0;
  padding: 0;
  background: #FFFFFF;
  border: 1.5px solid #D1D5DB;
  cursor: pointer;
  position: relative;
  transition: background-color .2s ease, border-color .2s ease, box-shadow .2s ease;
}
input[type="checkbox"] { border-radius: 5px; }
input[type="radio"]    { border-radius: 50%; }

input[type="checkbox"]:hover,
input[type="radio"]:hover { border-color: var(--accent); }

input[type="checkbox"]:focus-visible,
input[type="radio"]:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 4px rgba(159,41,66,0.18);
}

input[type="checkbox"]:checked {
  background: var(--accent);
  border-color: var(--accent);
}
/* White tick — drawn with a rotated rectangle border so it scales
   crisply at 18px without an SVG mask. */
input[type="checkbox"]:checked::after {
  content: '';
  position: absolute;
  left: 5px; top: 1px;
  width: 5px; height: 10px;
  border-right: 2px solid #FFFFFF;
  border-bottom: 2px solid #FFFFFF;
  transform: rotate(45deg);
}

input[type="radio"]:checked {
  border-color: var(--accent);
}
input[type="radio"]:checked::after {
  content: '';
  position: absolute;
  inset: 3px;
  border-radius: 50%;
  background: var(--accent);
}

input[type="checkbox"]:disabled,
input[type="radio"]:disabled {
  background: var(--bg-secondary);
  border-color: var(--border);
  cursor: not-allowed;
  opacity: 0.6;
}

/* Plain-text value that sits in the slot a .form-control input would
   occupy, for fields that can't be edited on the form (snapshot copy
   of something chosen elsewhere). No border, no background — reads as
   body text while the mono-caps label above still marks it as a field. */
.form-readonly {
  padding: 10px 0;
  font-size: 14px;
  color: var(--text);
  line-height: 1.5;
  word-break: break-word;
  overflow-wrap: anywhere;
  min-height: 24px;
}
/* Reads more like a primary value (bold, slightly larger) and sits
   tight against its label — used for the buyer's name on the
   checkout contact card so it doesn't drift halfway down the field
   under the default 10px top padding. */
.form-readonly-strong {
  padding-top: 2px;
  font-size: 15px;
  font-weight: 600;
}

/* ── Login Page ── */
.login-page {
  /* min-height is no longer needed — body is a flex column with
     min-height:100vh and .login-page has flex:1, so it stretches to
     exactly fill the space left over above the footer. */
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: var(--bg);
}
.login-box { width: 100%; max-width: 380px; }
.login-brand { text-align: center; margin-bottom: 28px; }
.login-brand .brand-name { font-size: 26px; font-weight: 700; color: var(--text); }
.login-brand .brand-name span { color: var(--accent); }
.login-brand p { font-size: 13px; color: var(--text-muted); margin-top: 6px; }
.login-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: 16px; padding: 28px; box-shadow: var(--shadow-md); max-width: var(--max-form); margin: 0 auto; }
.login-links { display: flex; justify-content: space-between; margin-top: 14px; font-size: 12px; }
.login-links a { color: var(--text-muted); }
.login-links a:hover { color: var(--accent); }

/* ── Companies ── */
.company-item { padding: 13px 0; border-bottom: 1px solid var(--border-light); }
.company-item:last-child { border-bottom: none; }
.company-name { font-size: 13.5px; font-weight: 600; color: var(--text); }
.company-meta { font-size: 12px; color: var(--text-muted); margin-top: 3px; line-height: 1.5; }

/* ── Admin ── */
.admin-reg-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius); padding: 20px; margin-bottom: 12px; box-shadow: var(--shadow-sm); }
.admin-reg-header { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 14px; gap: 12px; flex-wrap: wrap; }
.admin-reg-name { font-size: 15px; font-weight: 650; color: var(--text); }
.admin-reg-meta { font-size: 12px; color: var(--text-muted); margin-top: 3px; }
.admin-reg-actions { display: flex; gap: 8px; margin-top: 14px; flex-wrap: wrap; }
.bitrix-id-field { display: flex; gap: 8px; }
.bitrix-id-field .form-control { flex: 1; }

/* ── Alerts ── */
.alert { padding: 12px 16px; border-radius: 12px; font-size: 13px; margin-bottom: 16px; line-height: 1.5; }
.alert-info    { background: var(--info-bg);    border: 1px solid rgba(29,78,216,.15);  color: #1e40af; }
.alert-success { background: var(--success-bg); border: 1px solid rgba(21,128,61,.15);  color: #166534; }
.alert-warning { background: var(--warning-bg); border: 1px solid rgba(180,83,9,.15);   color: #92400e; }

/* "Ask on WhatsApp" CTA inside the cart shortfall alert. The default
   alert link colour matches the surrounding text and gets lost in a
   long sentence; a stronger underline makes it read as the
   actionable element of the warning. */
.cart-warn-cta {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 2px;
  white-space: nowrap;
}
.cart-warn-cta:hover { color: var(--accent); }

/* ── Divider ── */
.divider { height: 1px; background: var(--border-light); margin: 22px 0; }

/* ── Empty State ── */
.empty-state { text-align: center; padding: 40px 20px; color: var(--text-muted); }
.empty-state p { font-size: 13.5px; }

/* ── Welcome tour ── */
.welcome-tour-card {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(520px, 92vw);
  background: var(--bg-card);
  border: 1px solid var(--border);
  padding: 28px 28px 22px;
  box-shadow: 0 12px 48px rgba(0, 0, 0, .35);
}
.welcome-tour-step { display: none; line-height: 1.55; }
.welcome-tour-step.is-active { display: block; }
.welcome-tour-counter {
  font-size: 11px;
  letter-spacing: .8px;
  text-transform: uppercase;
  color: var(--text-muted);
  font-family: var(--mono);
  margin-bottom: 8px;
}
.welcome-tour-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  margin-top: 22px;
  padding-top: 16px;
  border-top: 1px solid var(--border-light);
  flex-wrap: wrap;
}

/* ── Onboarding checklist (dashboard) ── */
.onboarding-card { border-color: var(--accent); }
.onboarding-bar {
  height: 4px;
  background: var(--bg);
  border: 1px solid var(--border-light);
  margin-bottom: 14px;
  overflow: hidden;
}
.onboarding-bar-fill {
  height: 100%;
  background: var(--accent);
  transition: width .3s;
}
.onboarding-list { display: flex; flex-direction: column; gap: 6px; }
.onboarding-row {
  display: grid;
  grid-template-columns: 28px 1fr auto;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border: 1px solid var(--border-light);
  background: var(--bg-card);
  text-decoration: none;
  color: var(--text);
  font-size: 13.5px;
  transition: border-color .12s, background .12s;
}
.onboarding-row:hover { border-color: var(--accent); }
.onboarding-row.is-done { color: var(--text-muted); background: var(--bg); }
.onboarding-row.is-done .onboarding-label { text-decoration: line-through; }
.onboarding-check {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border: 1px solid var(--border);
  font-family: var(--mono);
  font-size: 13px;
}
.onboarding-row.is-done .onboarding-check {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.onboarding-cta {
  font-size: 11.5px;
  font-family: var(--mono);
  letter-spacing: .4px;
  color: var(--accent);
  text-transform: uppercase;
}
.onboarding-row.is-done .onboarding-cta { color: var(--text-muted); }

/* ── FAQ / help centre ── */
.faq-cat-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 16px 0 8px;
}
.faq-cat-pill {
  display: inline-block;
  padding: 5px 12px;
  border: 1px solid var(--border);
  background: var(--bg-card);
  color: var(--text-sub);
  font-size: 12px;
  letter-spacing: .2px;
  text-decoration: none;
  transition: color .12s, border-color .12s, background .12s;
}
.faq-cat-pill:hover { color: var(--text); border-color: var(--text); }
.faq-cat-pill.is-active {
  color: #fff;
  background: var(--accent);
  border-color: var(--accent);
}
.faq-cat-heading {
  font-size: 11px;
  font-family: var(--mono);
  text-transform: uppercase;
  letter-spacing: .8px;
  color: var(--text-muted);
  margin: 22px 2px 8px;
}
.faq-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.faq-list-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 12px 16px;
  border: 1px solid var(--border-light);
  background: var(--bg-card);
  text-decoration: none;
  color: var(--text);
  transition: border-color .12s, background .12s;
}
.faq-list-row:hover { border-color: var(--accent); }
.faq-list-row-title { font-size: 14px; font-weight: 600; }
.faq-list-row-meta  { font-size: 11.5px; color: var(--text-muted); }

.faq-article-body { font-size: 14.5px; line-height: 1.65; color: var(--text); }
.faq-article-body h2 { font-size: 19px; margin: 22px 0 8px; }
.faq-article-body h3 { font-size: 16px; margin: 18px 0 6px; }
.faq-article-body h4 { font-size: 14px; margin: 14px 0 4px; color: var(--text-sub); text-transform: uppercase; letter-spacing: .3px; }
.faq-article-body p { margin: 0 0 12px; }
.faq-article-body ul,
.faq-article-body ol { margin: 0 0 12px 22px; }
.faq-article-body li { margin-bottom: 4px; }
.faq-article-body a  { color: var(--accent); }
.faq-article-body code {
  background: var(--bg);
  padding: 1px 5px;
  font-family: var(--mono);
  font-size: 12.5px;
  border: 1px solid var(--border-light);
}
.faq-article-body img,
.faq-article-body video,
.faq-article-body iframe {
  max-width: 100%;
  height: auto;
  border: 1px solid var(--border-light);
  margin: 8px 0;
}
.faq-article-body iframe { aspect-ratio: 16 / 9; height: auto; }
.faq-tag {
  display: inline-block;
  padding: 2px 8px;
  font-size: 11px;
  letter-spacing: .2px;
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--text-sub);
}
/* Quill editor — make sure the toolbar + canvas line up with the
   surrounding form-control style. */
#quill-toolbar { border: 1px solid var(--border); border-bottom: 0; background: var(--bg-card); }
#quill-editor  { border: 1px solid var(--border); }

/* ── Breadcrumb ── */
.breadcrumb { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--text-muted); margin-bottom: 18px; flex-wrap: wrap; }
.breadcrumb a { color: var(--text-muted); }
.breadcrumb a:hover { color: var(--text); }
.breadcrumb .sep { color: var(--border); }
.breadcrumb .current { color: var(--text); }

/* ── Profile Edit ── */
.contact-edit-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  padding: 6px 0;
  border-bottom: 1px solid var(--border-light);
}
.contact-edit-row:last-child { border-bottom: none; }
.contact-type-select { width: 110px; flex-shrink: 0; }
.contact-cc-select   { width: 150px; flex-shrink: 0; }

/* ── Phone country-code combobox ──
   Narrow visible input ("+372"-wide) backed by a hidden input that
   carries the actual posted value. Click the visible input → list
   pops below; type to filter by country name OR dial code; click an
   option to select. JS in /assets/js/portal.js handles the
   open/close/filter/pick wiring (.cc-combobox handler). */
.phone-input-row {
  display: flex;
  /* The CC combobox + local input must always render on a single
     row — wrapping made the local input drop under the CC on
     narrow phones, which read as a broken layout. nowrap forces
     them to share a line; cc-display stays at its 90px and the
     local input (min-width:0) absorbs the remaining space. */
  flex-wrap: nowrap;
  gap: 6px;
  align-items: stretch;
}
.phone-input-row .phone-local { flex: 1; min-width: 0; }
.cc-combobox { position: relative; flex-shrink: 0; }
/* When the combobox is open, lift it above the next card so the
   dropdown isn't clipped by the email-addresses block painted on
   top of it. JS toggles .is-open on the wrapper. */
.cc-combobox.is-open { z-index: 1000; }
.cc-combobox .cc-display {
  width: 90px;
  font-family: var(--mono);
  text-align: center;
  cursor: pointer;
}
.cc-list {
  /* JS portals the .cc-list onto <body> on open() to escape any
     ancestor's overflow:hidden / transform / contain rules that
     iOS Safari was happily using to clip the dropdown.
     position:absolute + page-relative coordinates (top = scrollY +
     rect.bottom) keep the menu glued to the row in DOCUMENT space —
     when iOS auto-scrolls the page on input focus, the row and the
     dropdown move together instead of the dropdown drifting in
     viewport coordinates as position:fixed used to. max-height
     caps at ~6 rows; the rest scrolls inside. */
  position: absolute;
  width: 260px;
  max-height: 212px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  background: var(--bg-card);
  border: 1px solid var(--border);
  box-shadow: 0 6px 16px rgba(15,20,24,.12);
  z-index: 10000;
  padding: 4px 0;
}
.cc-list[hidden] { display: none !important; }
.cc-option {
  display: block;
  width: 100%;
  padding: 7px 12px;
  border: 0;
  background: transparent;
  text-align: left;
  font-family: var(--sans);
  font-size: 13px;
  color: var(--text);
  cursor: pointer;
}
.cc-option:hover,
.cc-option[aria-selected="true"] {
  background: var(--accent-light);
  color: var(--accent);
}
.cc-empty {
  padding: 10px 12px;
  font-size: 12px;
  color: var(--text-muted);
}

/* ── Field-level error states for phone / email JS validation ── */
.form-control.is-invalid,
.cc-combobox.is-invalid .cc-display {
  border-color: var(--danger);
  background: var(--danger-bg);
}
.field-feedback {
  font-size: 11.5px;
  color: var(--danger);
  margin-top: 4px;
  display: none;
  /* When the feedback lives inside a flex container (e.g. a phone
     repeater row), force it onto its own line under the input
     instead of becoming a flex sibling pushed to the right. */
  flex-basis: 100%;
  width: 100%;
  order: 99;
}
.field-feedback.is-shown {
  display: block;
}
.contact-edit-row .form-control:not(.contact-type-select) { flex: 1; }
.btn-remove {
  width: 28px; height: 28px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: none;
  color: var(--text-muted);
  font-size: 16px; line-height: 1;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  transition: all .12s;
}
.btn-remove:hover { background: var(--danger-bg); border-color: var(--danger); color: var(--danger); }

.newsletter-edit-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.nl-item {
  display: flex !important;
  width: 100%;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border-radius: 7px;
  border: 1px solid var(--border);
  cursor: pointer;
  transition: border-color .12s, background .12s;
  user-select: none;
  box-sizing: border-box;
}
.nl-item:hover { border-color: #bbb; background: #faf9f7; }
.nl-item:has(input[type="checkbox"]:checked) {
  border-color: var(--success);
  background: var(--success-bg);
}
.nl-item input[type="hidden"]   { display: none; }
.nl-item input[type="checkbox"] {
  /* Opt back into the native checkbox so accent-color tints the
     OS-drawn check green — overrides the global appearance:none
     custom box defined in the form-controls section above. */
  appearance: auto;
  -webkit-appearance: auto;
  -moz-appearance: auto;
  background: transparent;
  border: 0;
  width: 17px; height: 17px;
  flex-shrink: 0;
  cursor: pointer;
  accent-color: var(--success);
  margin: 0;
}
.nl-item input[type="checkbox"]::after { content: none; }
.nl-item span {
  font-size: 13.5px;
  color: var(--text);
}
.nl-item:has(input[type="checkbox"]:checked) span {
  color: var(--success);
  font-weight: 500;
}

/* ── Section anchor offset ── */
.section-anchor { scroll-margin-top: 24px; }

/* ════════════════════════════════
   RESPONSIVE
   ════════════════════════════════ */

/* Prevent any horizontal overflow globally. We use `overflow-x: clip`
   (not `hidden`) because `hidden` creates a scroll container on the
   <html>/<body> element, which silently breaks `position: sticky` on
   the topbar. `clip` just clips the overflow without turning the
   element into a scroll container. Older Safari falls back to hidden. */
html  { max-width: 100vw; overflow-x: clip; }
body  { max-width: 100vw; overflow-x: clip; }
@supports not (overflow: clip) {
  html, body { overflow-x: hidden; }
}
.layout, .main-content, .page-inner { min-width: 0; }

/* Cards and flex children should never overflow */
.card, .stat-card, .device-card, .admin-reg-card { min-width: 0; overflow: hidden; }

/* ── Adaptive topbar collapse ──────────────────────────────────
   Sits AFTER the base .topbar-user / .topbar-cta / nav rules so
   the @media display:none rules below actually override the base
   display:flex (an earlier placement let the base rule win at
   equal specificity, so the email never disappeared).

   Sequence (per the user-set rules):
     ≤1280  drop email + role tile
     ≤1080  swap wide BALTIC LASERS wordmark for the square favicon
     ≤1020  collapse priority-5 items (Service Cases) into More
     ≤960   collapse priority-4 (Companies)
     ≤900   collapse priority-3 (Devices)
     ≤840   collapse priority-2 (Shop)
     ≤768   burger takes over (handled by the next @media block)

   The "New service request" CTA stays visible all the way down to
   the burger breakpoint — the user wants it reachable from any
   desktop-class viewport.
*/
.brand-icon         { display: none; height: 28px; width: auto; }

/* ── Measure-based topbar collapse ───────────────────────────
   The legacy priority-based @media rules are gone. fitTopbarNav() in
   portal.js measures every nav item on load + resize and toggles
   .is-overflow-collapsed (on the bar item) and .is-overflow-revealed
   (on the matching duplicate inside the More dropdown). The .is-visible
   class on .topbar-nav-more shows the More trigger only when at least
   one item has been pushed off the bar. */
.topbar-nav-more { display: none; }
.topbar-nav-more.is-visible { display: inline-flex; }
.topbar-nav-item.is-overflow-collapsed,
.topbar-nav-group.is-overflow-collapsed { display: none !important; }
.topbar-nav-more .topbar-dropdown-item { display: none; }
.topbar-nav-more .topbar-dropdown-item.is-overflow-revealed { display: flex; }

/* Adaptive desktop topbar — three staged thresholds so we always free
   up real estate in the same order before JS starts collapsing items
   into the More dropdown:
     1. ≤1240  swap full wordmark for the square icon (saves ~120px).
               Anything wider — including standard 1280 / 1366 / 1440
               laptop widths — keeps the wordmark.
     2. ≤1180  drop the email + role chip (saves ~250px). Its only
               purpose is account reassurance, available in one click
               on Dashboard.
     3. ≤1024  drop the New-service-request CTA. Same page is still
               reachable from Requests or any device detail.
   Thresholds sized so each step completes before fitTopbarNav has a
   chance to push items into More — by the time the bar has actually
   run out of room, the brand icon mode and the chip-hide have done
   their work. Everything below 768px goes into the burger menu
   (handled later in this file). */
@media (max-width: 1240px) and (min-width: 769px) {
  .topbar-brand .brand-logo { display: none; }
  .topbar-brand .brand-icon { display: block; }
}
@media (max-width: 1100px) {
  .topbar-user { display: none; }
}
@media (max-width: 1024px) {
  .topbar-cta { display: none; }
}

@media (max-width: 768px) {
  /* ── Topbar: collapse to hamburger + slide-out panel ── */
  .topbar-inner        { padding: 0 18px; gap: 12px; min-height: 56px; }
  .topbar-brand .brand-logo { height: 28px; }
  .topbar-nav          {
    display: none; position: absolute;
    top: 56px; left: 0; right: 0;
    background: var(--bg-card);
    border-bottom: 1px solid var(--border);
    flex-direction: column; margin-left: 0; gap: 0;
    z-index: 45;
  }
  body.sidebar-open .topbar-nav { display: flex; }
  .topbar-nav-item {
    height: auto; padding: 14px 20px;
    border-bottom: 1px solid var(--border-light);
  }
  .topbar-nav-item.is-active {
    background: var(--accent-light);
    color: var(--accent);
    border-left: 3px solid var(--accent);
    padding-left: 17px;
  }

  /* Dropdown-bearing items (Shop) integrate inline with the stacked
     mobile menu instead of floating absolutely. The group becomes a
     full-width row, hover doesn't auto-open (no real hover on touch),
     and the dropdown only appears once JS toggles .is-open. */
  .topbar-nav-group {
    display: block;
    width: 100%;
  }
  .topbar-nav-group > .topbar-nav-item {
    display: flex;
    justify-content: flex-start;
    width: 100%;
  }
  .topbar-nav-group > .topbar-nav-item .topbar-nav-caret {
    margin-left: auto;
  }
  /* Mobile dropdown handling. Use a body-prefixed selector to
     guarantee higher specificity than any base rule (priorty
     0-2-0 vs 0-1-0), and !important on the layout properties so
     even an aggressive cascade or cached desktop styles can't put
     the dropdown back into absolute-positioned float-right mode.

     Hover never auto-opens (touch has no real hover); the menu
     only appears once JS toggles .is-open on the parent group. */
  body .topbar-nav .topbar-nav-group {
    position: static !important;
    display: block !important;
    width: 100% !important;
  }
  body .topbar-nav .topbar-nav-group .topbar-dropdown {
    position: static !important;
    top: auto !important;
    left: auto !important;
    right: auto !important;
    width: 100% !important;
    min-width: 0 !important;
    max-width: 100% !important;
    box-shadow: none !important;
    border: 0 !important;
    border-top: 1px solid var(--border-light) !important;
    background: var(--bg);
    padding: 0;
    z-index: auto;
  }
  body .topbar-nav .topbar-nav-group:not(.is-open) .topbar-dropdown {
    display: none !important;
  }
  body .topbar-nav .topbar-nav-group.is-open .topbar-dropdown {
    display: block !important;
  }
  .topbar-dropdown-item {
    padding: 13px 20px 13px 38px;
    font-size: 13px;
    border-bottom: 1px solid var(--border-light);
  }
  .topbar-dropdown-item:last-child { border-bottom: 0; }

  /* Burger panel shows every nav item inline regardless of priority,
     so the desktop "More" group is irrelevant here — collapse it
     and force priority-collapsed items back on. body-prefixed so
     this beats the body .topbar-nav .topbar-nav-group rule above
     (which would otherwise force-show .topbar-nav-more as a block). */
  body .topbar-nav .topbar-nav-more { display: none !important; }
  /* JS may have flagged items as collapsed before the viewport
     dropped into the burger range — ignore those flags here so the
     stacked panel always shows everything inline. */
  .topbar-nav .topbar-nav-item.is-overflow-collapsed { display: flex !important; }
  .topbar-nav .topbar-nav-group.is-overflow-collapsed { display: block !important; }
  /* Burger view always uses the full wordmark — no icon swap. */
  .topbar-brand .brand-icon { display: none !important; }
  .topbar-brand .brand-logo { display: block !important; }

  /* The desktop ::after underline has no place in the stacked
     mobile menu — hide it so we don't get a phantom horizontal
     line across the bottom of the active menu row. */
  .topbar-nav-item.is-active::after { display: none; }
  /* No room for the email+role chip on a phone, and the avatar is
     gone now too — collapse the whole tile. */
  .topbar-user         { display: none; }
  /* Topbar CTA is hidden too — the user can reach the same page via
     My Requests → New service request, or the Request service button
     on any device detail. Keeps the phone header uncluttered. */
  .topbar-cta          { display: none; }
  /* Keep the logout icon visible on mobile; hide the label so the
     tile doesn't eat the hamburger's real estate. */
  .topbar-logout-btn      { padding: 7px; }
  .topbar-logout-label    { display: none; }
  .topbar-menu-toggle  { display: flex; }
  .main-content        { max-width: 100vw; overflow-x: hidden; }
  .page-inner          { padding: 20px 16px 36px; width: 100%; max-width: 100%; box-sizing: border-box; overflow-x: hidden; }

  /* ── Site footer: stack to a single column on phones. At 4 cols
        (or even 2) on a 390px-wide phone each column is so narrow
        that titles wrap awkwardly and lines like "Medical Management
        OÜ" break mid-word. One clean stack reads much better.
        !important because the root-level .site-footer-inner base
        rule (with repeat(4, 1fr)) is defined LATER in the file and
        would otherwise win on equal specificity. ── */
  .site-footer        { padding: 32px 20px 20px; }
  .site-footer-inner  { grid-template-columns: 1fr !important; gap: 24px !important; }
  .site-footer-bottom { flex-direction: column; align-items: flex-start; margin-top: 24px; }

  /* ── Stats: layout only — value size + card padding live in tokens ── */
  .stats-row { grid-template-columns: 1fr 1fr; max-width: 100%; }

  /* ── Cards: padding handled by --space-card. Just tighten the
        admin registration card and tune card-header wrap behaviour. */
  .admin-reg-card  { padding: 18px; }
  .card-header     { flex-wrap: wrap; gap: 8px; }
  .card-header .btn { flex-shrink: 0; }
  /* When a card-header has a sibling action element (a form with
     input + button, or an action div with a row of buttons) next to
     the title block, the title block has flex:1 1 0 + min-width:0 and
     shrinks to nothing to make room — squeezing the subtitle to a
     handful of characters per line. Force these action siblings onto
     their own row on phones so the title block can use the full width.
     Single-button card-headers are unaffected because .btn keeps its
     natural width via the flex-shrink:0 rule above. */
  .card-header > form { flex-basis: 100%; }

  /* ── Grids ── */
  /* !important to beat form-specific rules that hoist .info-grid
     cells back to side-by-side in some contexts. Country + Address
     stay stacked vertically on a 390px-wide phone where the two
     side-by-side inputs were unreadable. */
  .info-grid         { grid-template-columns: 1fr !important; gap: 10px 0; }
  .device-cards-grid { grid-template-columns: 1fr; }
  .device-grid       { grid-template-columns: 1fr 1fr; }

  /* ── Page header — keep title + action buttons on a single row,
        wrapping the buttons to a new line only when there really
        isn't space. align-items: flex-start so the Edit button on
        the device / company detail pages stays level with the h1
        title at the top (was center, which floated it down to the
        middle of a tall title block containing h1 + subtitle +
        Request Service). */
  /* h1 size handled by --fs-h1 — no pixel override needed. */
  .page-header     { gap: 12px; align-items: flex-start; }
  .page-header .btn { padding: 8px 14px; font-size: 12px; }
  .breadcrumb      { font-size: 11px; }

  /* ── Tables: scroll inside wrapper, never stretch page ── */
  .table-wrap {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    max-width: 100%;
  }
  .table-wrap table { min-width: 500px; width: max-content; max-width: none; }

  /* ── Device rows ── */
  .device-row         { flex-wrap: wrap; gap: 8px; }
  .device-row-actions { flex-wrap: wrap; gap: 6px; }
  .device-row-actions .btn { font-size: 12px; padding: 5px 10px; }

  /* ── Contact edit ──
     Mobile: keep flex-row + wrap so the X button stays attached to
     its input. Type-select wraps to its own full-width row via
     flex-basis 100%; input(s) on next row share with the X. */
  .contact-edit-row    { flex-wrap: wrap; align-items: center; }
  .contact-edit-row > .contact-type-select,
  .contact-edit-row > .js-select {
    flex: 0 0 100%;
    width: 100%;
    min-width: 0;
  }
  .contact-edit-row > .form-control:not(.contact-type-select),
  .contact-edit-row > .phone-input-row {
    flex: 1 1 0;
    min-width: 0;
  }
  .contact-edit-row > .btn-remove { flex: 0 0 auto; }

  /* ── Company meta: allow wrap ── */
  .company-meta { word-break: break-word; overflow-wrap: anywhere; }

  /* ── Login ── */
  .login-box  { max-width: 100%; }
  .login-card { padding: 18px 16px; }

  /* ── Admin ── */
  .bitrix-id-field { flex-wrap: wrap; }
  .bitrix-id-field .form-control { width: 100%; }
}

@media (max-width: 480px) {
  .page-inner { padding: 12px 10px; }

  /* ── Stats — only layout. Value size handled by --fs-stat. ── */
  .stats-row  { gap: 8px; grid-template-columns: 1fr; }

  /* ── Device cards ── */
  .device-grid { grid-template-columns: 1fr; }
  .device-card { padding: 12px; }
  .device-card-header { flex-direction: column; gap: 6px; }

  /* ── Device rows ── */
  .device-row         { flex-direction: column; align-items: flex-start; }
  .device-row-info    { width: 100%; }
  .device-row-actions { width: 100%; }

  /* ── Contact edit ──
     ≤480: keep the wrap layout from the ≤768 rule above. The
     type-select wrapper still takes its own full-width row,
     input + X share the next row. No width:100% override on
     direct children — that would balloon the 28px X button into
     a full-width pill. */
  .contact-edit-row { gap: 6px; }

  /* h1 size handled by --fs-h1 — no override needed at this breakpoint. */
  .breadcrumb     { display: none; }

  /* ── Tables ── */
  th, td { padding: 8px 10px; font-size: 12px; }

  /* The base .card-header rule already uses flex with flex-wrap,
     so card titles + their action buttons keep flowing on one row
     when there's space and naturally wrap to a second row when
     there isn't. The previous override here forced flex-direction:
     column on every card header at ≤480px, which broke the
     "Edit profile" button on the contact card (stacked under the
     title) and made checkout's "Billing company" header center
     because the inline align-items:center on that card became a
     cross-axis center for a column layout. Letting the base row
     layout stand fixes both. */
}

/* ══════════════════════════════════════════════════════════════
   Site footer — Clinical Precision: charcoal 4-column
══════════════════════════════════════════════════════════════ */
.site-footer {
    background: #111417;
    color: #C9CDD2;
    padding: 48px 40px 28px;
    font-size: 13px;
    margin-top: auto;
}
.site-footer-inner {
    max-width: 1400px;
    margin: 0 auto;
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 40px;
}
.site-footer-title {
    font-family: var(--mono);
    font-size: 10px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.22em;
    color: #7B828A;
    margin-bottom: 14px;
}
.site-footer-company {
    color: #fff;
    font-weight: 600;
    margin-bottom: 6px;
}
.site-footer-lines {
    color: #9098A0;
    line-height: 1.7;
}
.site-footer a {
    color: #C9CDD2;
    text-decoration: none;
    border: none;
    transition: color 0.15s;
}
.site-footer a:hover { color: #fff; }
.site-footer-links {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.site-footer-bottom {
    max-width: 1400px;
    margin: 36px auto 0;
    padding-top: 20px;
    border-top: 1px solid #23272B;
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    color: #7B828A;
    font-size: 11.5px;
}
.site-footer-reg {
    font-family: var(--mono);
    letter-spacing: 0.1em;
    font-size: 10.5px;
}

/* ── Static content pages (privacy/terms/contact) ─────────── */
.static-page {
    max-width: 760px;
    margin: 0 auto;
    padding: 32px 24px 40px;
    background: #fff;
    border-radius: 8px;
    line-height: 1.65;
    color: var(--text);
}
.static-page h1 { font-size: 28px; margin: 0 0 6px; }
.static-page .static-page-sub { color: var(--text-muted); font-size: 13px; margin: 0 0 22px; }
.static-page h2 { font-size: 18px; margin: 28px 0 8px; }
.static-page p  { margin: 0 0 12px; }
.static-page ul { padding-left: 20px; margin: 0 0 14px; }
.static-page li { margin-bottom: 4px; }
.static-page a  { color: var(--accent); text-decoration: none; }
.static-page a:hover { text-decoration: underline; }
.static-page-wrap {
    background: var(--bg);
    min-height: 100vh;
    padding: 24px 16px;
}

/* Team roster on /contact.php — small responsive cards keyed by
   member name. Scales 1/2/3 columns based on width. Cards are
   intentionally low-chrome (just a subtle border) so the page
   stays text-first like the rest of the static pages. */
.team-group-title {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin: 18px 0 10px;
}
.team-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 12px;
  margin: 0 0 22px;
}
.team-card {
  border: 1px solid var(--border-light);
  padding: 12px 14px;
  background: var(--bg-card);
}
.team-name { font-weight: 600; font-size: 14px; color: var(--text); }
.team-role { font-size: 12px; color: var(--text-muted); margin-top: 2px; line-height: 1.4; }
.team-line { font-size: 12.5px; margin-top: 6px; word-break: break-word; }
.team-line a { color: var(--accent); text-decoration: none; }
.team-line a:hover { text-decoration: underline; }
.team-langs {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--text-muted);
  letter-spacing: 0.06em;
  margin-top: 6px;
  text-transform: uppercase;
}

/* ══════════════════════════════════════════════════════════════════
   Final-pass mobile overrides — kept at the very end of the file
   so nothing defined later can re-promote these grids back to two
   columns. The earlier @media block sits above the root-level
   .site-footer-inner rule, and on equal specificity the later root
   rule was winning on phones.

   Also bumps the breakpoint to 900px because Country + Address
   side-by-side at 769–900px (small tablets, big phones in
   landscape) is still painfully cramped.
══════════════════════════════════════════════════════════════════ */
@media (max-width: 900px) {
  /* Body-prefixed for higher specificity than any plain class
     selector that may appear earlier in the file. */
  body .info-grid {
    grid-template-columns: 1fr !important;
    gap: 12px 0 !important;
  }
  body .site-footer-inner {
    grid-template-columns: 1fr !important;
    gap: 24px !important;
  }
}

/* Service-request form has its OWN grid class (`.sr-grid`) instead
   of reusing .info-grid, because the cascade fight with later rules
   in the file kept resurrecting two columns on phones. Auto-fit +
   minmax means the layout collapses naturally without a media query
   the moment the container can't fit two ≥220px tracks side by
   side, so even an aggressive iPhone Safari CSS cache can't show
   it side-by-side on a 390px screen. */
.sr-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  /* Row gap matches the default .form-group bottom margin so a
     stacked grid (mobile) reads at the exact same vertical rhythm
     as the standalone fields above it. */
  gap: 18px 24px;
  /* Match the .form-group bottom margin so a field sitting right
     after the grid (e.g. Serial Number under the Brand/Model
     row on the external-device branch) has the same breathing
     room as any other vertically-stacked field. The inner cells
     reset their own margin-bottom below, so the grid itself owns
     the spacing to the next sibling. */
  margin-bottom: 18px;
}
/* …and we suppress the form-group's own bottom margin while it's
   inside the grid, otherwise that 18px gets added on top of the
   grid row-gap and the spacing balloons out compared to the rest
   of the form. */
.sr-grid > .form-group { margin-bottom: 0; }

/* ── Shop ──────────────────────────────────────────────────────
   The Shop block follows the same clinical aesthetic as the rest of
   the portal (sharp corners, monospace mini-labels, burgundy accents).
   Section is split into:
     · catalog grid    (.shop-grid / .shop-card)
     · product detail  (.product-detail)
     · cart            (.cart-layout)
     · checkout        (.checkout-layout)
     · order detail    (.order-detail-layout)
*/

/* "Cart" button rendered top-right of the shop page header, so the
   user has a second way into the cart without opening the dropdown.
   Solid burgundy when the cart isn't empty (mirrors the menu badge),
   ghost outline otherwise. */
.shop-cart-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 16px;
  border: 1px solid var(--border);
  background: var(--bg-card);
  color: var(--text);
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 500;
  text-decoration: none;
  transition: border-color .12s, background .12s, color .12s;
  white-space: nowrap;
}
.shop-cart-link:hover {
  border-color: var(--text);
  color: var(--text);
}
.shop-cart-link.has-items {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.shop-cart-link.has-items:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
  color: #fff;
}
.shop-cart-link svg { flex-shrink: 0; }
.shop-cart-link-badge {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0;
  font-weight: 600;
  padding: 1px 7px;
  background: rgba(255,255,255,.22);
  color: #fff;
}

/* Catalog pager — sits below the grid once there's more than one
   page worth of products. Shape matches the chip row above so the
   page feels coherent (sharp corners, mono-flavoured numerals). */
.shop-pager {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 6px;
  margin: 8px 0 24px;
}
.shop-pager-btn {
  min-width: 38px;
  padding: 7px 12px;
  border: 1px solid var(--border);
  background: var(--bg-card);
  color: var(--text-muted);
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.04em;
  cursor: pointer;
  transition: color .12s, border-color .12s, background .12s;
}
.shop-pager-btn:hover:not([disabled]):not(.is-active) {
  color: var(--text);
  border-color: var(--text);
}
.shop-pager-btn.is-active {
  color: #fff;
  background: var(--accent);
  border-color: var(--accent);
  cursor: default;
}
.shop-pager-btn[disabled] {
  opacity: .35;
  cursor: not-allowed;
}

/* Live search input above the chip row. Magnifier icon overlaps the
   left padding of the input. Full width on mobile, capped on
   desktop so it doesn't stretch comically across a 1400px page. */
.shop-search-row {
  position: relative;
  flex: 1;
  min-width: 220px;
  /* Generous max-width so the input occupies most of the middle
     column on desktop. The toolbar grid below caps it further if
     the page is narrower. */
  max-width: 900px;
}
.shop-search-icon {
  position: absolute;
  top: 50%;
  left: 12px;
  transform: translateY(-50%);
  /* Solid ink instead of muted grey — the magnifier was disappearing
     against the input's white background. */
  color: var(--text);
  pointer-events: none;
}
.shop-search-input {
  padding-left: 36px;
  /* Stronger border so the field reads as interactive on white
     panels, plus darker placeholder text and full-ink typed text. */
  border: 1px solid var(--text-muted);
  color: var(--text);
}
.shop-search-input::placeholder {
  color: var(--text-muted);
  opacity: 1;
}
.shop-search-input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-light);
  outline: none;
}
/* Hide the default WebKit search clear-button (Safari, Chrome) — it
   clashes with our visual style. Users can clear via Backspace. */
.shop-search-input::-webkit-search-cancel-button { -webkit-appearance: none; }

/* Filter chips above the catalog. One chip per unique brand+model the
   client owns, plus an "All my devices" reset. Active chip = burgundy. */
/* Toolbar that holds the device-filter chips and the grid/list
   view toggle on one row. Wraps cleanly at narrow widths. */
.shop-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}
/* On desktop the toolbar uses a 1fr · auto · 1fr grid so the
   search field lands at the page's horizontal centre — the two
   1fr tracks balance the left (Filters+Sort) and right (view
   toggle) clusters regardless of their actual widths. Mobile
   keeps the flex / wrap fallback. */
@media (min-width: 768px) {
  .shop-toolbar {
    display: grid;
    /* auto · 1fr · auto: side clusters take only the width they
       actually need, the middle (search) gets every leftover pixel.
       With max-width:900px on the search row the input still caps
       on huge screens; on a 1280-1600px laptop it spans almost the
       full mid-section, leaving the small empty pockets matching
       the side clusters' widths. */
    grid-template-columns: auto 1fr auto;
    flex-wrap: nowrap;
  }
  .shop-toolbar-left { justify-self: start; }
  .shop-toolbar > .shop-view-toggle { justify-self: end; }
  .shop-toolbar > .shop-search-row {
    justify-self: stretch;
    width: 100%;
    max-width: 900px;
    margin: 0 auto;
  }
}
.shop-filter-row {
  display: flex; gap: 8px; flex-wrap: wrap;
  margin-bottom: 0;
  flex: 1;
  min-width: 0;
}
.shop-view-toggle {
  display: inline-flex;
  border: 1px solid var(--border);
  background: var(--bg-card);
}
.shop-view-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  background: transparent;
  border: 0;
  color: var(--text-muted);
  font-family: var(--sans);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color .12s, background .12s;
}
.shop-view-btn + .shop-view-btn { border-left: 1px solid var(--border); }
.shop-view-btn:hover { color: var(--text); }
.shop-view-btn.is-active {
  color: #fff;
  background: var(--accent);
}
.shop-view-btn svg { flex-shrink: 0; }

/* ── Filter trigger + collapsible panel ────────────────────── */
.shop-filter-trigger {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 14px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  color: var(--text);
  font-family: var(--sans);
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
  transition: border-color .12s, color .12s;
}
.shop-filter-trigger:hover { border-color: var(--text); }
.shop-filter-trigger.is-open { border-color: var(--accent); color: var(--accent); }
.shop-filter-trigger svg { flex-shrink: 0; }
.shop-filter-caret {
  transition: transform .15s;
}
.shop-filter-trigger.is-open .shop-filter-caret { transform: rotate(180deg); }

/* Sort trigger + dropdown menu. Visually mirrors the Filters
   button so the toolbar reads as a row of related controls. */
/* Filters + Sort sit in a paired group at the toolbar's left edge.
   Their own flex gap is tight (8px) so the two read as related
   controls; the surrounding .shop-toolbar gap (14px) only applies
   between this group and the search / view-toggle that follow. */
.shop-toolbar-left {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.shop-sort {
  position: relative;
  display: inline-flex;
}
.shop-sort-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 20;
  min-width: 200px;
  padding: 6px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(15, 20, 24, .08);
  /* Class-based show/hide. The default rule with display:flex used
     to outrank [hidden]'s UA `display:none`, so the menu rendered
     open from page load. .is-open is now the only state that
     reveals it, and the JS toggles that class on the trigger. */
  display: none;
  flex-direction: column;
  gap: 2px;
}
.shop-sort-menu.is-open { display: flex; }
.shop-sort-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 12px;
  border: none;
  background: transparent;
  border-radius: 6px;
  font: inherit;
  font-size: 13px;
  color: var(--text);
  cursor: pointer;
  text-align: left;
}
.shop-sort-item:hover { background: var(--bg); }
.shop-sort-item.is-active {
  background: var(--accent-light);
  color: var(--accent);
  font-weight: 500;
}
.shop-sort-arrow {
  font-family: var(--mono);
  font-size: 13px;
  min-width: 12px;
  text-align: right;
}
.shop-sort-clear {
  border-top: 1px solid var(--border-light);
  margin-top: 4px;
  padding-top: 10px;
  color: var(--text-muted);
  font-size: 12px;
}
.shop-filter-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 18px;
  padding: 0 6px;
  background: var(--accent);
  color: #fff;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0;
  text-transform: none;
}
/* Honour the `hidden` attribute. Without this the inline-flex
   above outranks the UA `[hidden] { display:none }` rule and the
   counter stays visible (rendering "0") when there are no active
   filters — making the Filters button visibly wider than Sort. */
.shop-filter-count[hidden] { display: none; }

/* Collapsed by default. The Filters trigger flips .is-open which
   reveals the panel. We can't rely on the [hidden] HTML attribute
   alone because `display: grid` here would otherwise override the
   user-agent `display: none` rule and the panel would be visible
   on first paint. */
.shop-filter-panel {
  display: none;
}
.shop-filter-panel.is-open {
  margin: 0 0 18px;
  padding: 18px 20px 14px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-top: 2px solid var(--accent);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 18px 24px;
}
.shop-filter-section { min-width: 0; }
.shop-filter-section-title {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 8px;
  font-weight: 500;
}
.shop-filter-section-hint {
  font-size: 11.5px;
  color: var(--text-muted);
  line-height: 1.5;
  margin-bottom: 8px;
}
.shop-filter-options {
  display: flex; flex-direction: column; gap: 6px;
  max-height: 220px;
  overflow-y: auto;
}
.shop-filter-options-row {
  flex-direction: row;
  flex-wrap: wrap;
  gap: 6px 14px;
  max-height: none;
  overflow: visible;
}
.shop-filter-check,
.shop-filter-radio {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--text);
  cursor: pointer;
  user-select: none;
}
.shop-filter-check input,
.shop-filter-radio input {
  accent-color: var(--accent);
  flex-shrink: 0;
}
.shop-filter-price {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.shop-filter-price label {
  display: grid; gap: 4px;
}
.shop-filter-price label > span {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.shop-filter-price input {
  border: 1px solid var(--border);
  background: var(--bg);
  padding: 9px 12px;
  font-size: 13px;
  font-family: var(--sans);
  width: 100%;
  -moz-appearance: textfield;
}
.shop-filter-price input::-webkit-outer-spin-button,
.shop-filter-price input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.shop-filter-price input:focus { outline: none; border-color: var(--text); }
.shop-filter-actions {
  grid-column: 1 / -1;
  display: flex;
  justify-content: flex-end;
  /* Breath between "Clear all" + "Hide filters" — without this
     the two ghost-buttons read as one merged blob. */
  gap: 8px;
  border-top: 1px solid var(--border-light);
  padding-top: 12px;
  margin-top: 4px;
}
@media (max-width: 600px) {
  .shop-filter-panel { padding: 14px; gap: 14px; }
}

.shop-chip {
  display: inline-flex; align-items: center;
  padding: 6px 12px;
  border: 1px solid var(--border);
  background: var(--bg-card);
  color: var(--text-muted);
  font-size: 12px;
  letter-spacing: 0.02em;
  transition: color .12s, border-color .12s, background .12s;
}
.shop-chip:hover { color: var(--text); border-color: var(--text); }
.shop-chip.is-active {
  color: #fff;
  background: var(--accent);
  border-color: var(--accent);
}

/* Catalog grid + cards */
/* Grid mode (default): repeating square cards. Falls back to
   `.shop-grid` alone for backwards compat with anything that
   doesn't write the explicit .is-grid class. */
.shop-grid,
.shop-grid.is-grid {
  display: grid;
  /* Mobile baseline — two products per row. Hard breakpoint
     ladder so the catalogue never goes wider than four columns
     and prices have room to render without wrapping. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  margin-bottom: 24px;
}
@media (min-width: 1024px) {
  .shop-grid,
  .shop-grid.is-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
}
@media (min-width: 1280px) {
  .shop-grid,
  .shop-grid.is-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 20px; }
}

/* List mode: each card becomes a single horizontal row with a
   small square thumbnail on the left, body text in the middle
   and price + CTA on the right. */
.shop-grid.is-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 24px;
}
.shop-grid.is-list .shop-card {
  flex-direction: row;
  border: 1px solid var(--border);
  background: var(--bg-card);
  align-items: stretch;
  gap: 0;
}
/* List mode lays the card out as image | body, where the body is a
   simple vertical stack of (title, classification rows, action).
   The previous list-view CSS was tuned for the old shop-card
   markup (price / desc / pills cells in a 3×5 grid); the new
   devices card emits N classification rows that aren't part of
   that grid, so the cells collapsed on top of each other. Flex
   removes the explicit placement and lets the content flow. */
.shop-grid.is-list .shop-card-image {
  width: 160px;
  height: 160px;
  flex: 0 0 160px;
  aspect-ratio: 1 / 1;
  align-self: center;
  margin: 14px 0 14px 14px;
  border-right: 1px solid var(--border-light);
  border-bottom: 0;
  font-size: 56px;
}
.shop-grid.is-list .shop-card-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 16px 18px;
}
.shop-grid.is-list .shop-card-title {
  /* Two-line clamp keeps long family names from blowing up the row
     height; the rest of the stack stays predictable. */
  -webkit-line-clamp: 2;
          line-clamp: 2;
}
.shop-grid.is-list .shop-card-action {
  margin-top: auto;
  display: flex;
  flex-direction: row;
  justify-content: flex-end;
  gap: 6px;
}
.shop-grid.is-list .shop-card-action .btn {
  flex: 0 0 auto;
  min-width: 140px;
}
/* Tighten classification rows in list mode: label sits on one line,
   pills wrap below it. Less air per row than the grid card so
   several rows fit without making the row absurdly tall. */
.shop-grid.is-list .shop-card-row { gap: 3px; }

/* In list mode the image is too small to host the Market Position
   stack and the Family flag — they would cover most of the photo
   and crowd each other. Hide both overlays and surface the same
   info inside the body instead (Market Position becomes the first
   classification row; the family caption appears under the title). */
.shop-grid.is-list .shop-card-market-stack,
.shop-grid.is-list .shop-card-family-flag {
  display: none;
}
/* The reverse rule for grid mode: the Market Position row body
   block is hidden because the overlay carries the same labels. */
.shop-grid.is-grid .shop-card-row[data-row="market_position"] {
  display: none;
}
/* Family caption next to the title, list mode only. Grid mode keeps
   the corner flag instead, so this block stays hidden. */
.shop-card-family-sub {
  display: none;
  font-size: 11.5px;
  color: var(--text-muted);
  font-family: var(--sans);
  letter-spacing: 0.02em;
  margin-top: -4px;
}
.shop-grid.is-list .shop-card-family-sub { display: block; }

@media (max-width: 700px) {
  /* Phones + small tablets: smaller thumbnail, less padding, action
     button stretches to the full row width. */
  .shop-grid.is-list .shop-card-image {
    width: 100px; height: 100px; flex: 0 0 100px;
    font-size: 38px;
    margin: 12px 0 12px 12px;
  }
  .shop-grid.is-list .shop-card-body {
    padding: 12px 14px;
    gap: 8px;
  }
  .shop-grid.is-list .shop-card-action { justify-content: stretch; }
  .shop-grid.is-list .shop-card-action .btn { flex: 1; min-width: 0; }
}
@media (max-width: 480px) {
  /* On very narrow screens stack image above the body instead of
     side-by-side — a 100px thumbnail next to multi-row body still
     squeezes the text into thin columns once the rows have pills. */
  .shop-grid.is-list .shop-card { flex-direction: column; }
  .shop-grid.is-list .shop-card-image {
    width: 100%; height: 220px;
    flex: 0 0 auto;
    aspect-ratio: auto;
    margin: 0;
    border-right: 0;
    border-bottom: 1px solid var(--border-light);
  }
}
.shop-card {
  background: var(--bg-card);
  border: 1px solid var(--border);
  display: flex; flex-direction: column;
  transition: border-color .12s, box-shadow .12s;
}
.shop-card:hover { border-color: #d0cdc8; box-shadow: var(--shadow); }
.shop-card.is-out { opacity: .92; }
/* Catalog cover image — always square. Wide images get cropped
   left/right, tall images cropped top/bottom; both cropped from
   the centre via object-fit. The aspect-ratio rule pegs the box
   shape regardless of viewport / column count. Emoji stays
   centred via flex; real <img> stretches to fill the square. */
.shop-card-image {
  display: flex; align-items: center; justify-content: center;
  width: 100%;
  aspect-ratio: 1 / 1;
  /* Card photos are normalised on the server side to JPEGs on a
     white background (the optimizer flattens PNG transparency onto
     white before encoding). Keep the container background the same
     so portrait-aspect photos blend seamlessly into the card edges
     instead of showing the page-grey behind the side gutters. */
  background: #fff;
  border-bottom: 1px solid var(--border-light);
  font-size: 72px;
  text-decoration: none;
  overflow: hidden;
  /* Needed so the Market Position pill and the Family · N flag
     anchor to the card image, not the page. */
  position: relative;
}
.shop-card-image span { line-height: 1; }
.shop-card-image img {
  /* Resting state already at full card height — `height:100%` with
     `width:auto` keeps the photo's native aspect ratio while filling
     the square vertically. Landscape units overflow the sides (clipped
     by the container's overflow:hidden); portrait units sit centred
     with a thin gutter. The hover zoom adds a noticeable scale on top,
     not just a "now-it-fills-the-box" effect. */
  height: 100%;
  width: auto;
  max-width: none;
  display: block;
  transition: transform .6s cubic-bezier(.2, .7, .2, 1);
  will-change: transform;
}
/* Gentle zoom on hover — slow, restrained, premium. The image
   container has overflow:hidden above so the scaled-up edges
   stay clipped inside the square. Only triggers on devices that
   actually report a hover pointer; keeps phones static. */
@media (hover: hover) {
  .shop-card:hover .shop-card-image img { transform: scale(1.1); }
}

/* Market Position overlay — sits top-left over the photo. Market
   Position is a multi-select list in Bitrix, so a single device can
   carry several labels (Best seller + High ROI + Compact, for
   example). The stack wrapper anchors the group; each pill is a
   self-contained badge that sits one under another with a small gap. */
.shop-card-market-stack {
  position: absolute;
  top: 10px; left: 10px;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  pointer-events: none;
  max-width: calc(100% - 20px);
}
.shop-card-market {
  display: inline-flex;
  align-items: center;
  padding: 4px 9px;
  background: var(--accent);
  color: #fff;
  font-family: var(--sans);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  border-radius: 3px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.18);
}
/* Family flag — top-right marker that hints "this card represents
   N devices, click to drill in". Smaller and tonal so the Market
   Position pill stays the primary attention-grabber. */
.shop-card-family-flag {
  position: absolute;
  top: 10px; right: 10px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  padding: 3px 8px;
  background: rgba(255,255,255,0.92);
  border: 1px solid var(--border);
  color: var(--text);
  font-family: var(--sans);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.04em;
  border-radius: 3px;
  pointer-events: none;
}

/* Family aggregate-card variant. The card is the same size as a
   device card so the grid stays even; the differentiator is a
   subtle accent ring + slightly stronger title weight. */
.shop-card-family { border-color: var(--border); }
.shop-card-family .shop-card-title { font-weight: 700; }

/* Classification badge rows under the title — one row per axis,
   spec order:
     Device type / Technologies / Indications / Treatment areas /
     Areas of use / Combination compatibility / Available to.
   Each row is a small uppercase label + a wrapped list of pills.
   Truncation happens server-side; "+N more" is the trailing pill. */
.shop-card-row {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 0;
}
.shop-card-row-label {
  font-family: var(--sans);
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.shop-card-row-values {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 6px;
}
.shop-card-pill {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  background: var(--bg);
  border: 1px solid var(--border-light);
  border-radius: 10px;
  font-family: var(--sans);
  font-size: 10.5px;
  font-weight: 500;
  color: var(--text);
  letter-spacing: 0;
  line-height: 1.5;
}
.shop-card-pill-more {
  background: transparent;
  color: var(--text-muted);
  border-style: dashed;
}
.shop-card-body {
  padding: 14px 16px 16px;
  display: flex; flex-direction: column;
  gap: 8px;
  flex: 1;
}
.shop-card-title {
  font-family: var(--sans);
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--text);
  text-decoration: none;
  line-height: 1.35;
  letter-spacing: 0;
  /* Catalogue titles can run long. Cap at 3 lines so the price
     row + CTA line up across the row even when one product has
     a verbose name. */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
@media (min-width: 1024px) { .shop-card-title { font-size: 1rem; } }
.shop-card-title:hover { color: var(--accent); }
.shop-card-sku {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}
/* Pills row sitting between the title and description. Holds the
   Type pill (Расходник / Косметика / Услуга / Аксессуар) and the
   Audience tier pill (Available to all / Owners only) side-by-side
   on a single line, each sized to its own content. wrap is on for
   narrow cards where both labels can't share one line. */
.shop-card-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 2px 0;
}
.shop-card-type-pill,
.shop-card-aud-pill {
  display: inline-flex;
  align-items: center;
  padding: 1px 7px;
  border-radius: 9px;
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1.5;
}
.shop-card-type-pill {
  background: var(--bg);
  border: 1px solid var(--border-light);
  color: var(--text-muted);
}
.shop-card-aud-pill.is-public {
  background: #EAF2F8;
  border: 1px solid #C9D9E5;
  color: #345A78;
}
.shop-card-aud-pill.is-owners {
  background: var(--accent-light);
  border: 1px solid var(--accent);
  color: var(--accent);
}
.shop-card-desc {
  font-size: 12.5px;
  color: var(--text-sub);
  line-height: 1.5;
  /* Cap the description at four lines on grid view so a long
     manufacturer blurb doesn't make one card three times the
     height of the next. The list-view rule below tightens this
     further to two lines (more rows visible per scroll).
     `display:-webkit-box` is what -webkit-line-clamp needs to
     hook into; `flex:1` would override that display value (the
     card-body is a column flex container), which is why the foot
     anchors to the bottom via .shop-card-foot { margin-top: auto }
     instead of using the desc as a flex spacer. max-height is a
     belt-and-braces cap matching 4 × line-height × font-size for
     the rare engine that doesn't honour line-clamp. */
  display: -webkit-box;
  -webkit-line-clamp: 4;
          line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
  max-height: calc(1.5em * 4);
}
/* When the card carries the out-of-stock warning, the desc gives
   up half its lines so the extra warning paragraph below doesn't
   blow the card's total height much past its in-stock neighbours. */
.shop-card:has(.shop-card-warn) .shop-card-desc {
  -webkit-line-clamp: 2;
          line-clamp: 2;
  max-height: calc(1.5em * 2);
}
.shop-card-foot {
  /* Stack vertically — price on its own line, then the in-stock
     badge underneath. Stops the badge from squeezing the price
     into a wrap on narrow cards (where 1 674.00 € otherwise
     breaks across three lines). */
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  margin-top: auto;
}
.shop-card-price { width: 100%; }
.shop-card-price strong {
  font-family: var(--serif);
  font-size: 1.125rem;
  color: var(--text);
  display: block;
  font-weight: 600;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums lining-nums;
  white-space: nowrap;
}
@media (min-width: 1024px) { .shop-card-price strong { font-size: 1.25rem; } }
@media (min-width: 1280px) { .shop-card-price strong { font-size: 1.375rem; } }
/* Subtitle holds the without-VAT price (or the reverse-charge note).
   Stays in mono so the visual rhythm matches the rest of the labels. */
.shop-card-price span {
  display: block;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-top: 2px;
}
.shop-card-action {
  display: flex; gap: 8px; flex-wrap: wrap;
  margin-top: 6px;
}
.shop-card-action .btn { flex: 1; }
.shop-card-warn {
  font-size: 11.5px;
  color: var(--warning);
  background: var(--warning-bg);
  padding: 8px 10px;
  line-height: 1.5;
}
.shop-card-warn a { color: inherit; text-decoration: underline; font-weight: 600; }

/* Product detail page */
.product-detail {
  display: grid;
  grid-template-columns: minmax(280px, 1fr) 2fr;
  gap: 28px;
  background: var(--bg-card);
  border: 1px solid var(--border);
  padding: 24px;
}
@media (max-width: 760px) {
  .product-detail { grid-template-columns: 1fr; }
}
.product-detail-image {
  display: flex; align-items: center; justify-content: center;
  background: #fff;
  border: 1px solid var(--border-light);
  font-size: 96px;
  width: 100%;
  aspect-ratio: 1 / 1;
  overflow: hidden;
}
.product-detail-image img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center;
  display: block;
  padding: 16px;
  box-sizing: border-box;
}

/* ── Devices gallery (multi-image, /devices/<slug>) ─────────
   The product gallery below was tailored for shop products and
   doesn't fit the devices catalog markup. This is a lighter
   variant: single <img> swapped via src, optional prev/next
   arrows overlaid on the square, and a thumbnail strip below. */
.product-detail-gallery { display: flex; flex-direction: column; gap: 10px; }
.product-detail-gallery .product-detail-image { position: relative; }
.product-detail-gallery .product-detail-image.is-empty {
  font-size: 96px;
}
.device-gallery-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 36px; height: 36px;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(255, 255, 255, 0.85);
  border: 1px solid var(--border);
  border-radius: 50%;
  color: var(--text);
  cursor: pointer;
  transition: background .12s, transform .12s;
}
.device-gallery-nav:hover { background: #fff; transform: translateY(-50%) scale(1.05); }
.device-gallery-nav.prev { left: 10px; }
.device-gallery-nav.next { right: 10px; }
.device-gallery-thumbs {
  display: flex; flex-wrap: wrap; gap: 8px;
}
.device-gallery-thumb {
  width: 60px; height: 60px;
  background: var(--bg);
  border: 1px solid var(--border-light);
  border-radius: 4px;
  overflow: hidden;
  padding: 0;
  cursor: pointer;
  transition: border-color .12s, transform .12s;
}
.device-gallery-thumb:hover { border-color: var(--text); }
.device-gallery-thumb.is-active { border-color: var(--accent); border-width: 2px; }
.device-gallery-thumb img {
  width: 100%; height: 100%;
  object-fit: contain;
  object-position: center;
  padding: 4px;
  box-sizing: border-box;
  display: block;
}
@media (max-width: 480px) {
  .device-gallery-thumb { width: 52px; height: 52px; }
  .device-gallery-nav   { width: 30px; height: 30px; }
}

/* ── Product gallery (multi-image slider) ─────────────────────
   Shown on the detail page when the product has 2+ images. The
   stage stacks every frame on top of each other; only the one
   with `.is-active` is visible. Prev / Next arrows + thumbnails
   below + ←/→ keyboard arrows all flip the active index. */
.product-gallery {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.product-gallery-stage {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  background: var(--bg);
  border: 1px solid var(--border-light);
  overflow: hidden;
}
.product-gallery-frame {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 96px;
  opacity: 0;
  transition: opacity .18s ease-in-out;
  pointer-events: none;
}
.product-gallery-frame.is-active {
  opacity: 1;
  pointer-events: auto;
}
.product-gallery-frame span { line-height: 1; }
.product-gallery-frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
}
.product-gallery-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 36px; height: 36px;
  background: rgba(255,255,255,.92);
  border: 1px solid var(--border);
  color: var(--text);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: background .12s, color .12s, border-color .12s;
  z-index: 2;
}
.product-gallery-arrow:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.product-gallery-arrow-prev { left: 10px; }
.product-gallery-arrow-next { right: 10px; }
.product-gallery-counter {
  position: absolute;
  bottom: 10px;
  right: 10px;
  background: rgba(15,20,24,.78);
  color: #fff;
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.06em;
  padding: 4px 9px;
  z-index: 2;
}
.product-gallery-thumbs {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(64px, 1fr));
  gap: 6px;
}
.product-gallery-thumb {
  aspect-ratio: 1 / 1;
  background: var(--bg);
  border: 1px solid var(--border);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 28px;
  padding: 0;
  overflow: hidden;
  transition: border-color .12s;
}
.product-gallery-thumb:hover { border-color: var(--text); }
.product-gallery-thumb.is-active {
  border-color: var(--accent);
  border-width: 2px;
}
.product-gallery-thumb span { line-height: 1; }
.product-gallery-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
}
.product-detail-title {
  font-family: var(--serif);
  font-size: 1.25rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--text);
  line-height: 1.2;
  margin-bottom: 4px;
}
@media (min-width: 768px) { .product-detail-title { font-size: 1.375rem; } }
@media (min-width: 1024px) { .product-detail-title { font-size: 1.625rem; } }
.product-detail-sku {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  margin-bottom: 18px;
}
/* Two-line price: big number = with-VAT, then a 'incl. VAT' badge,
   and a small without-VAT line stacked under both. */
.product-detail-price {
  display: grid;
  grid-template-columns: auto auto;
  grid-template-rows: auto auto;
  column-gap: 12px;
  row-gap: 4px;
  align-items: baseline;
  margin-bottom: 14px;
  width: max-content;
  max-width: 100%;
}
.product-detail-price strong {
  grid-row: 1; grid-column: 1;
  font-family: var(--serif);
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--text);
  font-variant-numeric: tabular-nums lining-nums;
  white-space: nowrap;
}
@media (min-width: 768px) { .product-detail-price strong { font-size: 1.75rem; } }
@media (min-width: 1024px) { .product-detail-price strong { font-size: 2rem; } }
.product-detail-price span {
  grid-row: 1; grid-column: 2;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-muted);
  align-self: center;
}
.product-detail-price small {
  grid-row: 2; grid-column: 1 / -1;
  color: var(--text-muted);
  font-size: 12px;
}
.product-detail-stock {
  display: flex; align-items: center; gap: 10px;
  flex-wrap: wrap;
  font-size: 12.5px;
  color: var(--text-sub);
  margin-bottom: 18px;
}
.product-detail-stock a { color: var(--accent); text-decoration: underline; }
.product-detail-desc {
  font-size: 13.5px;
  color: var(--text-sub);
  line-height: 1.65;
  margin-bottom: 22px;
}
.product-detail-compat {
  border-top: 1px solid var(--border-light);
  padding-top: 16px;
  margin-bottom: 22px;
}
.product-detail-compat-label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 8px;
}
.product-detail-compat ul {
  list-style: none; padding: 0; margin: 0;
  display: flex; flex-wrap: wrap; gap: 6px;
}
.product-detail-compat li {
  background: var(--bg);
  border: 1px solid var(--border);
  padding: 4px 10px;
  font-size: 12px;
}
.product-detail-action {
  display: flex; align-items: center; gap: 10px;
  flex-wrap: wrap;
  border-top: 1px solid var(--border-light);
  padding-top: 18px;
}
.product-detail-action label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* Cart */
.cart-layout {
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: 24px;
  align-items: start;
}
/* Lets the inner cart-list and summary aside narrow below the
   width of their content — without this, a long product name on
   a 380px phone forces the whole grid wider than the viewport
   and the summary scrolls off-screen. */
.cart-layout > * { min-width: 0; }
/* Threshold set to 1130 — at 1080 the 1fr column was only ~720px
   (1040 viewport − 320 aside − 24 gap), which felt tight for the
   5-col cart-line plus a long product name. 1130 is the minimum
   width that keeps the side-by-side desktop layout feeling
   comfortable; below it we collapse to single-column so the cart
   takes the full row. The cart-line itself doesn't collapse to
   mobile until 820 (see further down), so between 820 and 1130
   the cart gets the full viewport for its desktop 5-col grid. */
@media (max-width: 1130px) {
  .cart-layout { grid-template-columns: 1fr; }
}
.cart-table-wrap {
  background: var(--bg-card);
  border: 1px solid var(--border);
}

/* Grid-driven cart list. Five virtual columns on desktop, single
   stacked card per item on phone (see media query below). */
.cart-list-head,
.cart-line {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 120px 110px 120px 36px;
  gap: 24px;
  align-items: center;
  padding: 14px 16px;
  font-size: 13px;
}
.cart-list-head {
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
  font-weight: 500;
}
.cart-line { border-bottom: 1px solid var(--border-light); }
.cart-line:last-child { border-bottom: none; }

/* All `!important` flags below: PR #30/#31 added the same
   selectors without !important, the CSS file definitely landed
   on the server (verified via curl), but the cart still rendered
   per-char wraps. Whatever cascade is overriding our rules can
   only be beaten by force. If something in the cascade ever
   needs to legitimately undo this it can do so explicitly. */
.cart-line-product {
  display: flex !important;
  flex-direction: row !important;
  flex-wrap: nowrap !important;
  align-items: center !important;
  gap: 12px !important;
  min-width: 0 !important;
  width: 100% !important;
}
.cart-prod-body {
  flex: 1 1 0 !important;
  min-width: 0 !important;
}
.cart-col-num   { text-align: right; }
.cart-line-num  { white-space: nowrap; }

.cart-prod-image {
  width: 56px; height: 56px;
  background: var(--bg);
  border: 1px solid var(--border-light);
  display: flex; align-items: center; justify-content: center;
  font-size: 28px;
  flex-shrink: 0;
  overflow: hidden;
}
.cart-prod-image img {
  width: 100%; height: 100%;
  object-fit: cover; object-position: center;
  display: block;
}
.cart-prod-name {
  font-weight: 600;
  font-size: 13.5px;
  color: var(--text);
  text-decoration: none;
  /* All `!important` for the same reason as `.cart-line-product`
     above. Standard `overflow-wrap: anywhere` breaks only when a
     word genuinely doesn't fit, never per character mid-word.
     `word-break: normal` reverts the legacy `break-word` value
     that some browsers treated as `break-all` (the per-char
     stack). `display: block` so the anchor sits on its own line
     inside the body and consumes the full available width
     instead of being a narrow inline run. */
  display: block !important;
  word-break: normal !important;
  overflow-wrap: anywhere !important;
  white-space: normal !important;
}
.cart-prod-name:hover { color: var(--accent); }
.cart-prod-sku {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--text-muted);
  margin-top: 2px;
  letter-spacing: 0.06em;
}
.cart-prod-warn {
  font-size: 11.5px;
  color: var(--warning);
  margin-top: 4px;
}
.cart-prod-stock {
  display: inline-flex;
  margin-top: 6px;
  align-self: flex-start;
}
/* Qty stepper: −/+ buttons flank a small numeric input that
   keeps acting as the source of truth for the form submission. */
.cart-qty-form {
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--border);
  background: var(--bg-card);
  height: 36px;
}
.cart-qty-btn {
  width: 32px;
  background: transparent;
  border: 0;
  font-family: var(--mono);
  font-size: 18px;
  font-weight: 500;
  color: var(--text);
  cursor: pointer;
  user-select: none;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  transition: background .12s, color .12s;
}
.cart-qty-btn:hover { background: var(--bg); }
.cart-qty-btn:active { background: var(--accent-light); color: var(--accent); }
.cart-qty {
  width: 44px;
  height: 100%;
  border: 0;
  border-left: 1px solid var(--border);
  border-right: 1px solid var(--border);
  border-radius: 0;
  background: transparent;
  text-align: center;
  font-family: var(--mono);
  font-size: 13px;
  color: var(--text);
  padding: 0;
  /* Hide the native spin buttons — our own +/− cover the same job. */
  -moz-appearance: textfield;
  appearance: textfield;
}
.cart-qty::-webkit-outer-spin-button,
.cart-qty::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.cart-qty:focus { outline: none; background: var(--bg); }
.cart-line-remove { display: flex; justify-content: flex-end; }
.cart-table-foot {
  padding: 12px 14px;
  border-top: 1px solid var(--border-light);
  display: flex; justify-content: space-between; align-items: center;
  gap: 10px; flex-wrap: wrap;
}
.cart-summary-row {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: 13px;
  padding: 6px 0;
  gap: 12px;
}
/* The price column must never wrap — translated labels in et / lv /
   lt / fi are long compound words that can break onto two lines, and
   that's fine; the number on the right needs to stay on one line so
   "5 760.77 €" doesn't end up with the currency on its own row. */
.cart-summary-row > :last-child { white-space: nowrap; flex-shrink: 0; }
.cart-summary-row > :first-child { min-width: 0; }
.cart-summary-total {
  border-top: 1px solid var(--border);
  margin-top: 8px;
  padding-top: 12px;
  font-size: 15px;
}
.cart-summary-total strong { font-size: 18px; color: var(--text); white-space: nowrap; }
.cart-summary { position: sticky; top: calc(var(--topbar-h) + 16px); }

/* Phone layout: the five-column grid collapses to image + body
   stack. Header row hides; each cell labels itself inline via the
   data-label attribute, so the user sees "Qty: 2" / "Unit price:
   …" without a header bar. Image keeps its column on the left.

   Three-tier layout:
     >1080px : 1fr cart + 320px summary aside (full desktop)
     820-1080: cart full-width, summary stacked below — but cart-line
               still uses the 5-column desktop grid because the row
               now has the whole viewport to spend on it
     ≤820px  : cart-line collapses to mobile card (this @media)

   820 was chosen as the floor for the 5-col grid: at that width,
   cart-table-wrap is ~780, fixed columns + gaps eat ~578, leaving
   ~200 for the product cell — enough for the image (56) and a
   name like "MATCHA POWER SERUM TDA" on one line. Below 820 the
   product cell shrinks past readable, so the row stacks. */
@media (max-width: 820px) {
  /* Compact mobile cart row, two grid rows:
       row 1 — product (image + name) spanning the price columns,
               remove button on the right
       row 2 — three columns: UNIT PRICE | QTY stepper | TOTAL
     The qty stepper takes its own intrinsic width; unit + total
     get 1fr each of the remaining space, anchored to the outer
     edges so the row reads naturally left-to-right. */
  .cart-list-head { display: none; }
  .cart-line {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    grid-template-areas:
      "product product remove"
      "unit    qty     total";
    column-gap: 12px;
    row-gap: 12px;
    padding: 14px;
  }
  .cart-line-product { grid-area: product; }
  .cart-line-remove {
    grid-area: remove;
    align-self: start;
    justify-content: flex-end;
  }
  .cart-line-unit {
    display: block;
    grid-area: unit;
    justify-self: start;
    text-align: left;
    font-size: 13px;
    color: var(--text);
  }
  .cart-line-qty {
    grid-area: qty;
    justify-self: center;
  }
  .cart-line-total {
    grid-area: total;
    justify-self: end;
    text-align: right;
    white-space: nowrap;
  }

  /* Mono labels — UNIT PRICE / TOTAL — stack above each value.
     Qty doesn't need a label; the −/+ stepper is unmistakable. */
  .cart-line-qty::before { content: none; }
  .cart-line-unit::before,
  .cart-line-total::before {
    content: attr(data-label);
    display: block;
    font-family: var(--mono);
    font-size: 9.5px;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--text-muted);
    font-weight: 500;
    margin-bottom: 3px;
  }
  .cart-line-unit::before  { text-align: left; }
  .cart-line-total::before { text-align: right; }

  /* excl. VAT subtitle aligned to the parent cell. */
  .cart-col-num-sub { width: auto; font-size: 11px; }
  .cart-line-unit  .cart-col-num-sub { text-align: left; }
  .cart-line-total .cart-col-num-sub { text-align: right; }

  /* Trim the inner image a touch so the product cell stays
     readable when the name wraps. */
  .cart-prod-image { width: 52px; height: 52px; font-size: 26px; }
  /* Slightly narrower stepper buttons on tight phones so the
     three-column row breathes. */
  .cart-qty-btn { width: 28px; }
  .cart-qty     { width: 38px; }
}

/* Checkout */
.checkout-layout {
  display: grid;
  grid-template-columns: 1fr 360px;
  gap: 24px;
  align-items: start;
}
/* Both columns of the checkout layout must be allowed to shrink
   below their min-content (long company strings, the Leaflet map
   container, marker clusters etc.); without this the .card
   children's intrinsic width forces the whole grid past the
   viewport on mobile, clipping the right edge. */
.checkout-layout > * { min-width: 0; max-width: 100%; }
.checkout-layout .card { max-width: 100%; min-width: 0; }
/* Threshold set to 1130 — kept in lockstep with cart-layout so the
   user sees the "summary moves below" flip at the same viewport
   width on both screens. At 1080 the main column was ~696px
   (1040 viewport − 360 aside − 24 gap) which felt tight for the
   parcel map + company snapshot + address fields; 1130 gives
   them a full-row layout slightly sooner. */
@media (max-width: 1130px) {
  .checkout-layout { grid-template-columns: 1fr; }
}
.checkout-summary { position: sticky; top: calc(var(--topbar-h) + 16px); }
.checkout-company-snapshot {
  background: var(--bg);
  border: 1px solid var(--border);
  padding: 12px 14px;
  font-size: 12.5px;
  color: var(--text-sub);
  line-height: 1.6;
}
.checkout-company-snapshot strong { color: var(--text); }
.checkout-company-grid {
  display: grid;
  /* `minmax(0, 1fr) minmax(0, 1fr)` — both columns flex AND respect
     parent width. The previous `minmax(110px, max-content) 1fr`
     allowed the first column to grow to its `max-content` (e.g.
     "Raua tn 32 37 10120 Kesklinna linnaosa Tallinn, Estonia ·
     Estonia"), pushing the grid past the viewport on mobile and
     clipping every other field on the right. The `0` minimum
     means a long word still wraps inside the cell instead of
     forcing the column wider. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 4px 14px;
  font-size: 12.5px;
}
@media (max-width: 600px) {
  /* On phones the grid collapses to a single column so the two
     halves stack vertically — Legal name + value, then Reg code +
     value, etc. Avoids cramming "Raua tn 32 …" into a 150px-wide
     cell next to "Reg. code". */
  .checkout-company-grid { grid-template-columns: 1fr; }
}
.checkout-company-label {
  color: var(--text-muted);
  font-size: 10.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  align-self: center;
  white-space: nowrap;
}
.checkout-company-value { color: var(--text); overflow-wrap: anywhere; }
.checkout-vat-note {
  margin-top: 12px;
  padding: 10px 12px;
  background: var(--info-bg);
  color: #1e3a8a;
  font-size: 12px;
  line-height: 1.5;
  border: 1px solid rgba(29,78,216,.12);
}
.checkout-radio,
label.checkout-radio,
.form-group label.checkout-radio {
  display: flex; align-items: flex-start; gap: 10px;
  border: 1px solid var(--border);
  padding: 12px 14px;
  margin-bottom: 8px;
  cursor: pointer;
  background: var(--bg-card);
  transition: border-color .12s, background .12s;
  /* The radio is a <label> sitting inside .form-group, so without
     these resets it inherits the mono-uppercase styling
     `.form-group label` (specificity 0,1,1 — outranks plain
     `.checkout-radio`) uses for field captions. The triple selector
     bumps specificity so the body font wins, and the inner spans
     get their own explicit font rules below as belt-and-suspenders
     against any future global label rule. */
  font-family: var(--sans);
  font-size: 14px;
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
}
.checkout-radio:hover { border-color: var(--text); }
.checkout-radio:has(input:checked) {
  border-color: var(--accent);
  background: var(--accent-light);
}
.checkout-radio input { margin-top: 3px; }
.checkout-radio-body { display: block; }
.checkout-radio-label {
  display: block;
  font-family: var(--sans);
  font-weight: 600;
  color: var(--text);
  font-size: 14px;
  text-transform: none;
  letter-spacing: 0;
}
.checkout-radio-meta {
  display: block;
  margin-top: 2px;
  font-family: var(--sans);
  font-size: 13px;
  color: var(--text-muted);
  text-transform: none;
  letter-spacing: 0;
}
.checkout-pickup {
  background: var(--bg);
  padding: 12px 14px;
  font-size: 12.5px;
  color: var(--text-sub);
}
.checkout-split {
  margin-top: 12px;
  padding-top: 14px;
  border-top: 1px solid var(--border-light);
}
.checkout-split-title {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--warning);
  margin-bottom: 6px;
}
.checkout-split-text { font-size: 13px; color: var(--text-sub); margin-bottom: 10px; }
.checkout-consent {
  display: flex; align-items: flex-start; gap: 10px;
  font-size: 13px;
  cursor: pointer;
  line-height: 1.5;
}
.checkout-consent input { margin-top: 3px; }
.checkout-consent.is-missing {
  background: var(--danger-bg);
  border: 1px solid var(--danger);
  padding: 10px 12px;
  margin: -2px -2px;
  animation: consent-pulse 1.6s ease-out;
}
.card.has-error {
  border-color: var(--danger);
  box-shadow: 0 0 0 3px var(--danger-bg);
}
/* Field-level error highlight. Applied to the .form-group (or any
   block container) when the corresponding $fieldErrors[…] flag was
   set during the place-order POST validation. The label tints red
   too, and any nested .form-control gets a red border so the buyer
   sees exactly which input to fix. */
.form-group.has-error,
.checkout-split.has-error {
  background: var(--danger-bg);
  border-left: 3px solid var(--danger);
  padding: 10px 12px;
  border-radius: 4px;
  animation: consent-pulse 1.6s ease-out;
}
.form-group.has-error label {
  color: var(--danger);
}
.form-group.has-error .form-control,
.form-group.has-error select,
.form-group.has-error textarea {
  border-color: var(--danger);
}
/* Error summary block under the Place-order button — pops out as a
   compact callout so the buyer can scan what to fix without
   scrolling back to the top of the page. */
.checkout-summary-errors {
  margin-top: 12px;
  padding: 10px 12px;
  background: var(--danger-bg);
  border: 1px solid var(--danger);
  color: var(--danger);
  font-size: 12px;
  border-radius: 4px;
  line-height: 1.55;
  animation: consent-pulse 1.6s ease-out;
}
@keyframes consent-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(180,40,50,0); }
  40%      { box-shadow: 0 0 0 6px rgba(180,40,50,0.18); }
}
/* Verify-button highlight on the company-edit form: pops into red
   when the user tries to submit an edited VAT without running a VIES
   check first. Cleared as soon as they press the button or change
   the VAT field. */
.btn.btn-needs-attention {
  border-color: var(--danger);
  color: var(--danger);
  background: var(--danger-bg);
  animation: consent-pulse 1.6s ease-out;
}
.checkout-summary-items {
  display: flex; flex-direction: column;
  gap: 10px;
  margin-bottom: 12px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border-light);
}
.checkout-summary-item {
  display: flex; align-items: flex-start; gap: 10px;
  font-size: 12.5px;
}
.checkout-summary-item-img {
  width: 36px; height: 36px;
  background: var(--bg);
  border: 1px solid var(--border-light);
  display: flex; align-items: center; justify-content: center;
  font-size: 18px;
  flex-shrink: 0;
  overflow: hidden;
}
.checkout-summary-item-img img {
  width: 100%; height: 100%;
  object-fit: cover; object-position: center;
  display: block;
}
.checkout-summary-item-body { flex: 1; min-width: 0; }
.checkout-summary-item-name {
  font-weight: 600;
  color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.checkout-summary-item-meta {
  color: var(--text-muted);
  font-family: var(--mono);
  font-size: 11px;
}
.checkout-summary-item-price {
  white-space: nowrap;
  font-weight: 600;
  color: var(--text);
}

/* Order detail */
.order-detail-layout {
  display: grid;
  grid-template-columns: 1fr 320px;
  gap: 24px;
  align-items: start;
}
@media (max-width: 960px) {
  .order-detail-layout { grid-template-columns: 1fr; }
}
.order-summary-aside { position: sticky; top: calc(var(--topbar-h) + 16px); }
.order-status-row {
  display: flex; align-items: center; gap: 12px;
  flex-wrap: wrap;
}
.order-invoice-row {
  display: flex; align-items: center; justify-content: space-between;
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px dashed var(--border);
  gap: 10px; flex-wrap: wrap;
}
.order-items {
  display: flex; flex-direction: column;
}
.order-item {
  display: grid;
  grid-template-columns: 56px 1fr auto auto;
  gap: 14px;
  align-items: center;
  padding: 12px 0;
  border-bottom: 1px solid var(--border-light);
}
.order-item:last-child { border-bottom: none; }
.order-item-img {
  width: 56px; height: 56px;
  background: var(--bg);
  border: 1px solid var(--border-light);
  display: flex; align-items: center; justify-content: center;
  font-size: 28px;
  overflow: hidden;
  flex-shrink: 0;
}
.order-item-img img {
  width: 100%; height: 100%;
  object-fit: cover; object-position: center;
  display: block;
}
.order-item-name {
  font-weight: 600;
  font-size: 13.5px;
  color: var(--text);
  text-decoration: none;
}
.order-item-name:hover { color: var(--accent); }
.order-item-sku {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--text-muted);
  margin-top: 2px;
  letter-spacing: 0.06em;
}
.order-item-warn {
  font-size: 11.5px;
  color: var(--warning);
  margin-top: 4px;
}
.order-item-qty {
  font-family: var(--mono);
  color: var(--text-muted);
  font-size: 12px;
  white-space: nowrap;
}
.order-item-price {
  font-weight: 600;
  white-space: nowrap;
}

/* Without-VAT subtitle in cart unit / line columns. Sits under the
   bold with-VAT figure in the same cell. */
.cart-col-num-sub {
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--text-muted);
  letter-spacing: 0.04em;
  font-weight: 400;
  margin-top: 2px;
}

/* ── Parcel-machine picker ────────────────────────────────────
   Replaces the native <select> with a search-driven list — scales
   to the hundreds of Omniva machines we'll have in production and
   lets the user type the city or street to narrow it down. */
.parcel-picker {
  border: 1px solid var(--border);
  background: var(--bg-card);
}
.parcel-selected {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px;
  background: var(--accent-light);
  border-bottom: 1px solid var(--border-light);
}
.parcel-selected-body { flex: 1; min-width: 0; }
.parcel-selected-name {
  font-weight: 600;
  font-size: 13.5px;
  color: var(--text);
}
.parcel-selected-addr {
  font-size: 12px;
  color: var(--text-muted);
  margin-top: 2px;
}
/* Country / parcel-machine "selected" pill rendered as a <button>
   so clicking anywhere on it reopens the search. The little hint
   on the right ("↻") replaces the previous × — the entire box is
   the click target now. */
.parcel-selected-btn { border: none; }
.parcel-selected-btn:hover { background: rgba(122, 31, 43, 0.10); }
.parcel-selected-edit-hint {
  font-size: 16px;
  color: var(--text-muted);
  padding: 0 6px;
  flex-shrink: 0;
}
.parcel-search-wrap { padding: 10px; }
.parcel-search-wrap > .form-control { margin-bottom: 8px; }
.parcel-list {
  max-height: 260px;
  overflow-y: auto;
  border: 1px solid var(--border-light);
}
.parcel-item {
  display: block;
  width: 100%;
  text-align: left;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--border-light);
  padding: 10px 12px;
  cursor: pointer;
  font-family: inherit;
  color: var(--text);
  transition: background .12s;
}
.parcel-item:last-child { border-bottom: none; }
.parcel-item:hover { background: var(--bg); }
.parcel-item-name {
  font-weight: 600;
  font-size: 13px;
  color: var(--text);
}
.parcel-item-addr {
  font-size: 11.5px;
  color: var(--text-muted);
  margin-top: 1px;
}
.parcel-empty {
  padding: 20px;
  text-align: center;
  font-size: 12.5px;
  color: var(--text-muted);
}

/* ── Upcoming Events card on the Home dashboard ───────────────
   Each event row has a fixed-width date block on the left
   (DAY / MONTH / YEAR stacked, mono) and the title + summary +
   "Learn more" CTA on the right. Compact enough to slot beneath
   the contact card without dominating the page. */
.events-list {
  display: flex;
  flex-direction: column;
}
.events-item {
  display: grid;
  grid-template-columns: 64px 1fr;
  gap: 18px;
  padding: 16px 24px;
  border-bottom: 1px solid var(--border-light);
}
.events-item:last-child { border-bottom: 0; }
.events-date {
  background: var(--bg);
  border: 1px solid var(--border);
  padding: 8px 4px;
  text-align: center;
  font-family: var(--mono);
  height: max-content;
}
.events-date-day {
  font-size: 22px;
  line-height: 1;
  color: var(--accent);
  font-weight: 600;
}
.events-date-month {
  font-size: 10px;
  letter-spacing: 0.16em;
  color: var(--text);
  margin-top: 4px;
}
.events-date-year {
  font-size: 10px;
  color: var(--text-muted);
  margin-top: 2px;
}
.events-body { min-width: 0; }
.events-title {
  font-weight: 600;
  font-size: 14px;
  color: var(--text);
  line-height: 1.35;
}
.events-when {
  font-size: 12.5px;
  color: var(--text-sub);
  margin-top: 4px;
}
.events-location {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-top: 4px;
}
.events-summary {
  font-size: 12.5px;
  color: var(--text-sub);
  line-height: 1.55;
  margin-top: 8px;
}
.events-cta {
  margin-top: 12px;
}
.events-cta svg { flex-shrink: 0; }
@media (max-width: 480px) {
  .events-item { grid-template-columns: 56px 1fr; gap: 12px; padding: 14px 18px; }
  .events-date-day { font-size: 18px; }
}

/* ════════════════════ Articles section ════════════════════ */

/* List page (`/articles`) — card grid with cover, meta, title, excerpt. */
.articles-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 18px;
  margin-bottom: 24px;
}
.articles-card {
  display: flex; flex-direction: column;
  background: var(--card, #fff);
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
  text-decoration: none; color: inherit;
  transition: transform .12s ease, box-shadow .12s ease;
}
.articles-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 20px rgba(0,0,0,0.06);
}
.articles-card-cover {
  aspect-ratio: 16 / 9;
  background: var(--surface-muted, #f1f1f1);
  overflow: hidden;
}
.articles-card-cover img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
.articles-card-body { padding: 16px 18px; flex: 1; display: flex; flex-direction: column; }
.articles-card-meta {
  font-size: 12px; color: var(--text-muted);
  text-transform: uppercase; letter-spacing: 0.06em;
}
.articles-card-title {
  margin: 8px 0 0;
  font-size: 17px; line-height: 1.35;
  font-weight: 600; color: var(--text);
}
.articles-card-excerpt {
  margin: 8px 0 0;
  font-size: 13.5px; line-height: 1.5; color: var(--text-muted);
}

/* Pagination */
.articles-pager {
  display: flex; gap: 12px; align-items: center; justify-content: center;
  padding: 18px 0; margin-bottom: 18px;
}
.articles-pager-link {
  padding: 8px 14px;
  border: 1px solid var(--border); border-radius: 6px;
  text-decoration: none; color: var(--text);
  font-size: 13px;
}
.articles-pager-link:hover { background: var(--surface-hover, rgba(0,0,0,0.04)); }
.articles-pager-link.is-disabled { color: var(--text-muted); pointer-events: none; opacity: 0.5; }
.articles-pager-page { font-size: 13px; color: var(--text-muted); }

/* Detail page (`/article/<slug>`) */
.article-page { max-width: 760px; margin: 0 auto; }
.article-breadcrumbs {
  font-size: 13px; color: var(--text-muted); margin-bottom: 12px;
}
.article-breadcrumbs a { color: var(--text-muted); text-decoration: none; }
.article-breadcrumbs a:hover { text-decoration: underline; }
.article-breadcrumbs .sep { margin: 0 6px; }
.article-hero {
  margin: 0 0 18px;
  border-radius: 8px; overflow: hidden;
  aspect-ratio: 16 / 9; background: var(--surface-muted, #f1f1f1);
}
.article-hero img { width: 100%; height: 100%; object-fit: cover; display: block; }
.article-title {
  font-size: var(--fs-h1); line-height: 1.05; margin: 8px 0 6px; font-weight: 600;
}
.article-meta {
  font-size: 13px; color: var(--text-muted); margin-bottom: 18px;
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
}
.article-tag-chip {
  display: inline-block; padding: 2px 8px; margin-left: 4px;
  border: 1px solid var(--border); border-radius: 999px;
  font-size: 11px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em;
}
.article-youtube {
  position: relative; padding-top: 56.25%; margin: 18px 0;
  background: #000; border-radius: 8px; overflow: hidden;
}
.article-youtube iframe {
  position: absolute; inset: 0; width: 100%; height: 100%; border: 0;
}
.article-body {
  font-family: var(--body); font-size: 16px; line-height: 1.6; color: var(--text);
}
.article-body h2 { font-size: 22px; margin: 28px 0 10px; }
.article-body h3 { font-size: 18px; margin: 22px 0 8px;  }
.article-body h4 { font-size: 16px; margin: 18px 0 6px; }
.article-body p,
.article-body ul,
.article-body ol,
.article-body blockquote { margin: 0 0 14px; }
.article-body img { max-width: 100%; height: auto; border-radius: 4px; margin: 12px 0; }
.article-body blockquote {
  border-left: 3px solid var(--accent, #888);
  padding: 4px 0 4px 16px; color: var(--text-muted);
}
.article-body a { color: var(--accent, #1565c0); }
.article-body ul, .article-body ol { padding-left: 22px; }

/* Quiet-Premium: legacy articles may have inline font-family
   overrides saved into block markup. Force them back to the
   inherited body font so the page typography stays pure. */
.article-body [style*="font-family"] { font-family: inherit !important; }

.article-related-devices {
  margin: 28px 0 8px; padding: 14px 18px;
  background: var(--surface-muted, #f7f7f8);
  border-radius: 8px;
}
.article-related-devices-label {
  font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-muted); margin-bottom: 6px;
}
.article-related-devices ul { margin: 0; padding-left: 18px; }
.article-related-devices li { font-size: 14px; }

.article-footer { margin: 32px 0 12px; }

/* Gallery — strip + lightbox */
.article-gallery {
  position: relative; margin: 18px 0;
  display: flex; align-items: center; gap: 6px;
}
.article-gallery-strip {
  display: flex; gap: 8px;
  overflow-x: auto; scroll-behavior: smooth;
  scroll-snap-type: x mandatory;
  flex: 1; min-width: 0;
}
.article-gallery-thumb {
  flex: 0 0 auto;
  width: 160px; height: 110px;
  border: 0; padding: 0; background: transparent; cursor: pointer;
  border-radius: 6px; overflow: hidden;
  scroll-snap-align: start;
}
.article-gallery-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.article-gallery-nav {
  width: 36px; height: 110px;
  border: 1px solid var(--border); background: #fff; cursor: pointer;
  border-radius: 6px; font-size: 22px; color: var(--text-muted);
  flex: 0 0 auto;
}
.article-gallery-nav:hover { background: var(--surface-hover, rgba(0,0,0,0.04)); }

.article-lightbox {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.85);
  display: none; align-items: center; justify-content: center;
  z-index: 9999;
}
.article-lightbox.is-open { display: flex; }
.article-lightbox-img { max-width: 92vw; max-height: 88vh; object-fit: contain; }
.article-lightbox-close,
.article-lightbox-nav {
  position: absolute; background: rgba(255,255,255,0.1);
  border: 0; color: #fff; cursor: pointer;
  font-size: 32px; line-height: 1;
  width: 48px; height: 48px; border-radius: 50%;
}
.article-lightbox-close:hover,
.article-lightbox-nav:hover { background: rgba(255,255,255,0.22); }
.article-lightbox-close { top: 14px; right: 14px; font-size: 26px; }
.article-lightbox-nav.is-prev { left: 16px; top: 50%; transform: translateY(-50%); }
.article-lightbox-nav.is-next { right: 16px; top: 50%; transform: translateY(-50%); }

/* Phone breakpoint — single-column list, smaller hero. Title +
   body sizes already scale via --fs-h1 / --fs-body tokens. */
@media (max-width: 720px) {
  .articles-grid { grid-template-columns: 1fr; }
  .article-gallery-thumb { width: 120px; height: 90px; }
  .article-gallery-nav   { height: 90px; }
}

/* Dashboard widget — three latest articles + see-all link. */
.articles-widget-list { padding: 6px 0; }
.articles-widget-row {
  display: flex; gap: 12px; align-items: center;
  padding: 12px 24px;
  text-decoration: none; color: inherit;
  border-bottom: 1px solid var(--border);
  transition: background-color .12s ease;
}
.articles-widget-row:last-child { border-bottom: 0; }
.articles-widget-row:hover { background: var(--surface-hover, rgba(0,0,0,0.04)); }
.articles-widget-thumb {
  width: 56px; height: 56px;
  object-fit: cover; border-radius: 4px; flex-shrink: 0;
  background: var(--surface-muted, #f1f1f1);
}
.articles-widget-meta { min-width: 0; }
.articles-widget-title {
  font-size: 14px; font-weight: 500; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.articles-widget-date {
  font-size: 12px; color: var(--text-muted); margin-top: 2px;
}

/* Equipment-detail cross-link — articles related to this device. */
.articles-related-list { padding: 4px 0; }
.articles-related-row {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 14px 24px;
  text-decoration: none; color: inherit;
  border-bottom: 1px solid var(--border);
  transition: background-color .12s ease;
}
.articles-related-row:last-child { border-bottom: 0; }
.articles-related-row:hover { background: var(--surface-hover, rgba(0,0,0,0.04)); }
.articles-related-thumb {
  width: 72px; height: 54px;
  object-fit: cover; border-radius: 4px; flex-shrink: 0;
  background: var(--surface-muted, #f1f1f1);
}
.articles-related-meta { min-width: 0; flex: 1; }
.articles-related-title {
  font-size: 14.5px; font-weight: 500; color: var(--text);
}
.articles-related-excerpt {
  font-size: 13px; color: var(--text-muted); margin-top: 3px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.articles-related-date {
  font-size: 12px; color: var(--text-muted); margin-top: 4px;
}

/* Device-checkbox picker — replaces the awkward <select multiple> in
   the article admin form. Scrollable, comma-friendly hover rows. */
.device-checkbox-list {
  max-height: 240px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 4px;
  background: var(--surface, #fff);
}
.device-checkbox-row {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 8px;
  font-size: 12.5px; line-height: 1.3;
  font-family: var(--mono);
  cursor: pointer;
  border-radius: 4px;
}
.device-checkbox-row:hover { background: var(--surface-hover, rgba(0,0,0,0.04)); }
.device-checkbox-row input[type="checkbox"] { flex-shrink: 0; }
.device-checkbox-row span { word-break: break-word; }

/* Quill: ensure the editor surface has a real minimum height even
   when the article body is empty, so click-on-empty-space focus
   has somewhere to land. */
.ql-editor { min-height: 280px; }

/* Quill font picker — Quiet-Premium typography is enforced
   globally, so any per-paragraph font override (whether saved in
   legacy articles or chosen via the picker) is absorbed back into
   the page font. The picker stays in the toolbar for back-compat
   but every value resolves to the inherited body face. */
[class*="ql-font-"] { font-family: inherit; }
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
.ql-snow .ql-picker.ql-font .ql-picker-item::before { content: attr(data-value); font-family: inherit; }
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=""]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=""]::before { content: 'Default'; }

/* ────────────────────────────────────────────────────────────────────
   /articles — public list page (toolbar + list rows + highlight)
   Replaces the old card-grid look. Mirrors the shop list-view shape:
   thumbnail on the left, title + 2-line excerpt + meta on the right.
   ──────────────────────────────────────────────────────────────────── */
.articles-toolbar {
  background: var(--surface, #fff);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 14px 18px;
  margin-bottom: 18px;
}
.articles-search-row {
  display: flex; gap: 10px; align-items: center;
  position: relative;
  margin-bottom: 12px;
}
.articles-search-icon {
  position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
  color: var(--text-muted); pointer-events: none;
}
.articles-search-input {
  flex: 1; min-width: 0;
  padding: 9px 12px 9px 36px;
  font-size: 14px;
  border: 1px solid var(--border); border-radius: 6px;
  background: var(--surface, #fff);
}
.articles-search-input:focus { outline: none; border-color: var(--accent); }
.articles-filter-row {
  display: flex; flex-wrap: wrap; gap: 14px; align-items: center;
}
.articles-filter {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 13px; color: var(--text-muted);
}
.articles-filter select {
  font-size: 13px; padding: 6px 10px;
  border: 1px solid var(--border); border-radius: 6px;
  background: var(--surface, #fff);
}
.articles-filter-clear {
  font-size: 13px; color: var(--accent); text-decoration: none;
}
.articles-filter-clear:hover { text-decoration: underline; }
.articles-filter-count {
  margin-left: auto;
  font-size: 12px; color: var(--text-muted);
}

/* List rows — replace the old .articles-grid card layout. */
.articles-list { display: flex; flex-direction: column; gap: 0; }
.articles-row {
  display: flex; gap: 18px; align-items: stretch;
  padding: 14px 18px;
  background: var(--surface, #fff);
  border: 1px solid var(--border);
  border-radius: 8px;
  text-decoration: none; color: inherit;
  margin-bottom: 12px;
  transition: border-color .12s ease, box-shadow .12s ease;
}
.articles-row:hover {
  border-color: var(--accent);
  box-shadow: 0 1px 6px rgba(0,0,0,0.05);
}
.articles-row-cover {
  flex-shrink: 0;
  width: 180px;
  aspect-ratio: 16 / 10;
  background: var(--surface-muted, #f1f1f1);
  border-radius: 6px;
  overflow: hidden;
}
.articles-row-cover img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
.articles-row-cover-blank {
  background: linear-gradient(135deg, #f5f5f5, #ececec);
}
.articles-row-body {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column; gap: 6px;
}
.articles-row-meta {
  display: inline-flex; flex-wrap: wrap; gap: 6px;
  font-size: 12px; color: var(--text-muted);
}
.articles-row-cat::after {
  content: '·'; margin: 0 0 0 6px;
}
.articles-row-title {
  font-size: 17px; font-weight: 600; line-height: 1.3;
  margin: 0; color: var(--text);
}
.articles-row-excerpt {
  font-size: 14px; line-height: 1.45; color: var(--text-muted);
  margin: 0;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Search-term highlight — works for /articles AND /faq.php. */
mark {
  background: rgba(168, 36, 32, 0.15);
  color: inherit;
  padding: 0 2px;
  border-radius: 2px;
}

/* Mobile: stack cover above text, shrink cover. */
@media (max-width: 600px) {
  .articles-row { flex-direction: column; gap: 12px; }
  .articles-row-cover { width: 100%; aspect-ratio: 16/9; }
  .articles-filter-count { margin-left: 0; }
}

/* FAQ row: add room for the new excerpt + tighten the existing meta. */
.faq-list-row-excerpt {
  font-size: 13px; line-height: 1.45; color: var(--text-muted);
  margin-top: 4px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ────────────────────────────────────────────────────────────────────
   Public article body — render of EditorJS blocks. Mirrors the
   spacing/typography rhythm of the rest of the portal. Loaded on
   every page (lives in portal.css).
   ──────────────────────────────────────────────────────────────────── */
.article-block-h {
  margin: 32px 0 12px;
  font-weight: 600; line-height: 1.25;
}
.article-body h2.article-block-h { font-size: 24px; }
.article-body h3.article-block-h { font-size: 19px; }
.article-body h4.article-block-h { font-size: 16px; }

.article-block-p {
  margin: 0 0 14px; line-height: 1.65; font-size: 16px;
}

.article-block-list { margin: 0 0 14px; padding-left: 24px; }
.article-block-list li { margin-bottom: 6px; }

.article-block-quote {
  border-left: 4px solid var(--accent, #a82420);
  padding: 6px 16px; margin: 16px 0;
  color: var(--text);
  background: rgba(168,36,32,0.04);
  border-radius: 0 4px 4px 0;
}
.article-block-quote p   { margin: 0 0 6px; font-style: italic; }
.article-block-quote cite { font-size: 13px; color: var(--text-muted); font-style: normal; }

.article-block-delimiter {
  border: 0; height: 1px; background: var(--border);
  margin: 24px auto; width: 60%;
}

.article-block-image { margin: 18px 0; text-align: center; }
.article-block-image img {
  max-width: 100%; height: auto; border-radius: 4px;
  display: block; margin: 0 auto;
}
.article-block-image.is-bordered img { border: 1px solid var(--border); }
.article-block-image.is-bg { padding: 14px; background: rgba(0,0,0,0.03); border-radius: 6px; }
.article-block-image.is-stretched img { width: 100%; max-width: none; }
.article-block-image figcaption {
  font-size: 13px; color: var(--text-muted);
  margin-top: 8px; line-height: 1.4;
}

.article-block-embed { margin: 18px 0; }
.article-block-embed-frame {
  position: relative; width: 100%; padding-top: 56.25%; /* 16:9 */
  background: #000; border-radius: 6px; overflow: hidden;
}
.article-block-embed-frame iframe {
  position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0;
}
.article-block-embed figcaption {
  font-size: 13px; color: var(--text-muted);
  margin-top: 8px; text-align: center;
}

.article-block-gallery {
  position: relative; margin: 18px 0;
  display: flex; align-items: center; gap: 6px;
}


/* Public render of EditorJS columns block — side-by-side cells. */
.article-block-columns {
  display: grid;
  grid-template-columns: repeat(var(--cols, 2), 1fr);
  gap: 24px;
  margin: 24px 0;
}
.article-block-columns[data-cols="3"] { grid-template-columns: repeat(3, 1fr); }
.article-block-column { min-width: 0; }
@media (max-width: 720px) {
  .article-block-columns,
  .article-block-columns[data-cols="3"] { grid-template-columns: 1fr; }
}

/* Block-level alignment wrapper. */
.article-block-align.is-center  { text-align: center; }
.article-block-align.is-right   { text-align: right; }
.article-block-align.is-justify { text-align: justify; }
.article-block-align.is-center .article-block-list,
.article-block-align.is-right  .article-block-list { display: inline-block; text-align: left; }


/* Long unbreakable strings inside public column blocks — same shrink-
   fit + break-word fix as the editor side. */
.article-block-columns { min-width: 0; }
.article-block-column {
  min-width: 0;
  overflow-wrap: anywhere;
  word-break: break-word;
}
.article-block-column > * { max-width: 100%; }

/* ── Topbar language selector ─────────────────────────────────
   Globe-icon toggle sitting inside .topbar-user-area, just before
   the user / logout block. Menu reuses the custom-select picker's
   fixed-position trick so it escapes any overflow:hidden ancestor. */
.topbar-lang { position: relative; display: inline-flex; }
.topbar-lang-toggle {
  display: inline-flex; align-items: center; gap: 6px;
  height: 36px; padding: 0 12px;
  background: transparent; border: 1px solid transparent;
  border-radius: 10px;
  color: var(--text-muted);
  font-family: var(--sans);
  font-size: 0.9375rem; font-weight: 500;
  cursor: pointer;
  transition: background-color .25s ease, color .25s ease, border-color .25s ease;
}
.topbar-lang-toggle:hover    { color: var(--text); background: var(--bg-secondary, #F1F4F8); }
.topbar-lang-toggle:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 4px rgba(159,41,66,0.18);
}
.topbar-lang.is-open .topbar-lang-toggle { color: var(--accent); background: var(--accent-light); }
.topbar-lang-toggle svg { display: block; width: 16px; height: 16px; }
.topbar-lang-toggle .topbar-lang-chevron { width: 10px; height: 6px; transition: transform .25s ease; }
.topbar-lang.is-open .topbar-lang-toggle .topbar-lang-chevron { transform: rotate(180deg); }
.topbar-lang-code { font-variant: small-caps; letter-spacing: 0.04em; }

.topbar-lang-menu {
  display: none;
  position: fixed;
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow-md);
  padding: 6px;
  z-index: 1000;
  min-width: 200px;
  max-width: calc(100vw - 24px);
  font-family: var(--sans);
  font-size: 15px;
  transform-origin: top right;
}
.topbar-lang-menu.is-open  { display: block; animation: js-select-pop .14s ease-out; }
.topbar-lang-menu.is-up    { transform-origin: bottom right; }
.topbar-lang-menu a {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 9px 12px;
  border-radius: 8px;
  color: var(--text);
  text-decoration: none;
  transition: background-color .15s ease, color .15s ease;
}
.topbar-lang-menu a:hover { background: var(--bg-secondary, #F1F4F8); color: var(--text); }
.topbar-lang-menu a.is-active {
  color: var(--accent);
  font-weight: 500;
  background: var(--accent-light);
}
.topbar-lang-menu a > :last-child {
  font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-faint);
}
.topbar-lang-menu a.is-active > :last-child { color: var(--accent); }

@media (max-width: 768px) {
  .topbar-lang-toggle { padding: 0 8px; height: 32px; }
  .topbar-lang-toggle svg:first-child { width: 18px; height: 18px; }
  .topbar-lang-code { display: none; }
  .topbar-lang-toggle .topbar-lang-chevron { display: none; }
}
