/*
 * TuningBot File Desk — styles (mobile first).
 * Copyright TuningBot.com
 * Rules: 8px corners (no pill shapes), whole rows/cards clickable, tap targets >= 44px,
 * text never under 12px, inputs 16px (no iOS zoom), one column under 760px, no horizontal scroll.
 */
/* Fonts (self-hosted, SIL OFL: see /static/fonts/LICENSE-*): Barlow, a grotesk drawn from road
   signage (legible at a glance), its semi-condensed cut for headings and numbers, IBM Plex Mono for
   ECU codes and file names only. */
@font-face { font-family: 'Barlow'; font-style: normal; font-weight: 400; font-display: swap; src: url('/static/fonts/barlow-latin-ext-400-normal.woff2') format('woff2'); unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family: 'Barlow'; font-style: normal; font-weight: 400; font-display: swap; src: url('/static/fonts/barlow-latin-400-normal.woff2') format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'Barlow'; font-style: normal; font-weight: 500; font-display: swap; src: url('/static/fonts/barlow-latin-ext-500-normal.woff2') format('woff2'); unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family: 'Barlow'; font-style: normal; font-weight: 500; font-display: swap; src: url('/static/fonts/barlow-latin-500-normal.woff2') format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'Barlow'; font-style: normal; font-weight: 600; font-display: swap; src: url('/static/fonts/barlow-latin-ext-600-normal.woff2') format('woff2'); unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family: 'Barlow'; font-style: normal; font-weight: 600; font-display: swap; src: url('/static/fonts/barlow-latin-600-normal.woff2') format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'Barlow'; font-style: normal; font-weight: 700; font-display: swap; src: url('/static/fonts/barlow-latin-ext-700-normal.woff2') format('woff2'); unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family: 'Barlow'; font-style: normal; font-weight: 700; font-display: swap; src: url('/static/fonts/barlow-latin-700-normal.woff2') format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'Barlow Semi Condensed'; font-style: normal; font-weight: 600; font-display: swap; src: url('/static/fonts/barlow-semi-condensed-latin-ext-600-normal.woff2') format('woff2'); unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family: 'Barlow Semi Condensed'; font-style: normal; font-weight: 600; font-display: swap; src: url('/static/fonts/barlow-semi-condensed-latin-600-normal.woff2') format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'Barlow Semi Condensed'; font-style: normal; font-weight: 700; font-display: swap; src: url('/static/fonts/barlow-semi-condensed-latin-ext-700-normal.woff2') format('woff2'); unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family: 'Barlow Semi Condensed'; font-style: normal; font-weight: 700; font-display: swap; src: url('/static/fonts/barlow-semi-condensed-latin-700-normal.woff2') format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 400; font-display: swap; src: url('/static/fonts/ibm-plex-mono-latin-ext-400-normal.woff2') format('woff2'); unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 400; font-display: swap; src: url('/static/fonts/ibm-plex-mono-latin-400-normal.woff2') format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 500; font-display: swap; src: url('/static/fonts/ibm-plex-mono-latin-ext-500-normal.woff2') format('woff2'); unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 500; font-display: swap; src: url('/static/fonts/ibm-plex-mono-latin-500-normal.woff2') format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
:root {
  --ink: #13212e; --muted: #4b5d6b; --line: #d7e1ea; --line-2: #e8eef3; --bg: #edf2f6; --card: #fff;
  --brand: #005a87; --brand-dark: #003f5f; --brand-2: #0073aa; --top: #0b2a3f; --top-2: #16496a;
  --ok-bg: #e3f4ea; --ok: #14532d; --warn-bg: #fdf0dc; --warn: #7a3f00; --info-bg: #e0eef8; --info: #0b4a6f;
  --err-bg: #fde8e6; --err: #8a1c12; --note-bg: #fff8e1; --note-line: #c99a2e;
  --turn: #f2a516; --turn-bg: #fff4dd; --turn-ink: #6b3f00; --go: #1d7a46; --go-dark: #155c34;
  --font: "Barlow", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-c: "Barlow Semi Condensed", "Barlow", system-ui, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  --shadow: 0 1px 2px rgba(11, 42, 63, .06), 0 4px 14px rgba(11, 42, 63, .05);
}
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body { margin: 0; background: var(--bg); color: var(--ink); font: 16px/1.5 var(--font); overflow-wrap: break-word; -webkit-font-smoothing: antialiased; }
a { color: var(--brand); }
a:hover { color: var(--brand-dark); }
h1, h2, h3 { line-height: 1.2; margin: 0; font-family: var(--font-c); font-weight: 700; letter-spacing: .005em; }
h1 { font-size: 28px; }
h2 { font-size: 20px; font-weight: 600; margin-bottom: 10px; }
h3 { font-size: 16px; font-weight: 600; margin-bottom: 8px; }
p { margin: 0 0 10px; }
.mono { font-family: var(--mono); }
.muted { color: var(--muted); }
.hide { display: none !important; }
.sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }

/* ---------- top bar ---------- */
.top { background: var(--top); color: #fff; }
.top-in { max-width: 1392px; margin: 0 auto; padding: 8px 16px; display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; min-height: 60px; }
.brand { display: flex; align-items: center; gap: 10px; color: #fff; font-weight: 700; text-decoration: none; margin-right: auto; }
.brand:hover { color: #fff; }
.brand .sub { font-weight: 500; color: #a9cde3; }
.brand-mark { width: 30px; height: 30px; background: var(--brand-2); display: inline-flex; align-items: center; justify-content: center; font-weight: 800; letter-spacing: .02em; }
.nav { display: flex; flex-wrap: wrap; gap: 4px; }
.nav a, .nav button { display: inline-flex; align-items: center; min-height: 44px; padding: 0 12px; border-radius: 8px; color: #d5e6f1; text-decoration: none; background: none; border: 0; font: inherit; cursor: pointer; }
.nav a:hover, .nav button:hover { background: #123e5a; color: #fff; }
.nav a.on { background: var(--top-2); color: #fff; }
.top select { min-height: 44px; border: 1px solid #3d6680; border-radius: 8px; background: #123e5a; color: #fff; padding: 0 8px; font-size: 15px; }
.who { color: #d5e6f1; font-size: 13px; }
/* 0.32.0: "N online" in the staff bar (brand line); the operator's email keeps only the part before the @ on phones.
   0.32.1: a link to /op/online, beside the brand link (one box, so the phone grid sees one cell). */
body.staff .brand-box { display: flex; align-items: center; min-width: 0; margin-right: auto; }
body.staff .brand-box .brand { margin-right: 0; }
.brand-box .online { display: inline-flex; align-items: center; gap: 6px; margin-left: 8px; padding: 6px 4px; font-family: var(--font); font-size: 13px; font-weight: 600; color: #cfe3f3; white-space: nowrap; text-decoration: none; }
.brand-box .online:hover { color: #fff; }
.brand-box .online.on { background: var(--top-2); color: #fff; padding: 6px 8px; border-radius: 8px; } /* 0.36.4: the current page, like a menu entry */
.brand-box .online .dot { width: 8px; height: 8px; border-radius: 50%; background: #3ddc84; box-shadow: 0 0 0 2px rgba(61, 220, 132, .25); }
.who-mail .wm-short { display: none; }
@media (max-width: 759px) { .who-mail .wm-full { display: none; } .who-mail .wm-short { display: inline; } }
/* Pop-up alerts (web push) for customers: bell in the top bar with a small menu. */
.bell { position: relative; }
.bell-btn { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; border-radius: 8px; border: 1px solid #3d6680; background: #123e5a; line-height: 1; cursor: pointer; }
.bell-btn:hover, .bell-btn[aria-expanded="true"] { background: var(--top-2); }
.bell-dot { position: absolute; border-radius: 50%; border: 2px solid #123e5a; background: #8aa4b5; }
.bell[data-state="on"] .bell-dot { background: #22c55e; }
.bell[data-state="none"] .bell-dot { background: #f59e0b; }
.bell-panel { position: absolute; top: calc(100% + 8px); right: 0; z-index: 30; width: min(340px, calc(100vw - 32px)); padding: 14px; border-radius: 8px; background: var(--card); color: var(--ink); border: 1px solid var(--line); box-shadow: 0 12px 32px rgba(11, 42, 63, .22); }
.push-bar h2 { font-size: 15px; }
.push-bar .row { gap: 8px; }
/* Customer bar: tools (language, bell, log out) on the right; phone layout in the v0.9.11 block. */
.tools { display: flex; align-items: center; gap: 8px; }
.langpick { position: relative; display: inline-flex; align-items: center; gap: 4px; min-height: 44px; padding: 0 12px; border: 1px solid #3d6680; border-radius: 8px; background: #123e5a; color: #fff; font-size: 14px; font-weight: 600; cursor: pointer; white-space: nowrap; }
.langpick::after { content: ''; width: 0; height: 0; margin-left: 2px; border: 4px solid transparent; border-top: 5px solid #a9cde3; transform: translateY(2px); }
.langpick:hover { background: var(--top-2); }
.langpick:focus-within { outline: 3px solid #7fb6d8; outline-offset: 1px; }
.top .langpick select { position: absolute; inset: 0; width: 100%; height: 100%; min-height: 0; opacity: 0; cursor: pointer; font-size: 16px; }
@media (max-width: 1023px) { .top-in { gap: 8px; } }
@media (max-width: 379px) { .brand .sub { display: none; } }

/* ---------- layout ---------- */
.wrap { max-width: 1200px; margin: 0 auto; padding: 20px 16px 48px; }
.wrap.wide { max-width: 1392px; }
.page-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 12px; margin-bottom: 12px; }
/* 0.26.0: title with a link on its row (pay page: "← TB-10042"), less room above */
.page-head.row { align-items: center; margin-bottom: 10px; }
.page-head.row h1 { margin: 0; font-size: 26px; }
body.cust .wrap { padding-top: 10px; }
.page-head .lead { margin: 4px 0 0; color: var(--muted); }
/* 0.12.0: admin pages with one action (Add service, Add method…): the action on the title row, the
   description under both; when they do not fit side by side the button goes whole under the title. */
.admin .page-head:has(> .btn) { align-items: center; }
.admin .page-head:has(> .btn) > div { display: contents; }
.admin .page-head:has(> .btn) > div > h1 { flex: 1 1 auto; margin: 0; }
.admin .page-head:has(> .btn) > div > .lead, .admin .page-head:has(> .btn) > div > .clamp-more { flex: 1 0 100%; order: 3; }
.admin .page-head:has(> .btn) > div > .clamp-more { flex: 0 0 auto; }
.grid-main { display: grid; grid-template-columns: minmax(0, 1fr); gap: 20px; align-items: start; }
.stack { display: flex; flex-direction: column; gap: 12px; }
.row { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.row.end { justify-content: flex-end; }
.row.between { justify-content: space-between; }
.f3 { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; }
@media (min-width: 1024px) {
  .wrap { padding: 28px 24px 56px; }
  .grid-main { grid-template-columns: minmax(0, 1fr) 340px; gap: 24px; }
  .grid-main.wide-side { grid-template-columns: minmax(0, 1fr) 380px; }
  .f3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  h1 { font-size: 30px; }
}
@media (min-width: 1024px) { .f3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.sticky { position: sticky; top: 16px; }

/* ---------- cards ---------- */
.card { background: var(--card); border: 1px solid var(--line); border-radius: 8px; padding: 16px; }
.card > h2:last-child { margin-bottom: 0; }
.kv { display: grid; font-size: 14px; margin: 0; }
.kv dt { color: var(--muted); }
.kv dd { margin: 0; }
.sumrow { display: flex; justify-content: space-between; gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--line-2); }
.sumrow.total { border-bottom: 0; font-weight: 700; padding-top: 14px; }

/* ---------- banners and chips ---------- */
.banner { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; border-radius: 8px; padding: 14px 16px; border: 1px solid transparent; margin-bottom: 18px; }
.banner > span { flex: 1 1 260px; }
.banner.ok { background: var(--ok-bg); color: var(--ok); border-color: #b7dcc4; }
.banner.warn { background: var(--warn-bg); color: var(--warn); border-color: #f0d3a6; }
.banner.info { background: var(--info-bg); color: var(--info); border-color: #b5d3e8; }
.banner.error { background: var(--err-bg); color: var(--err); border-color: #f2b8b1; }
.banner.muted { background: var(--line-2); color: var(--muted); }
.chip { display: inline-flex; align-items: center; min-height: 26px; padding: 2px 8px; border-radius: 6px; font-weight: 600; background: var(--line-2); color: #33475a; }
.chip.ok { background: var(--ok-bg); color: var(--ok); }
.chip.warn { background: var(--warn-bg); color: var(--warn); }
.chip.info { background: var(--info-bg); color: var(--info); }
.chip.err { background: var(--err-bg); color: var(--err); }
.chip.new { background: var(--info); color: #fff; }

/* ---------- forms ---------- */
label.lbl, .lbl { display: block; font-weight: 600; color: #33475a; margin-bottom: 6px; }
.in { width: 100%; min-height: 44px; border: 1px solid #a9bccd; border-radius: 8px; padding: 9px 12px; font: inherit; font-size: 16px; background: #fff; color: var(--ink); }
.in:focus, .btn:focus-visible, a:focus-visible, button:focus-visible, .opt:focus-within { outline: 3px solid #7fb6d8; outline-offset: 1px; }
textarea.in { min-height: 96px; resize: vertical; }
select.in { padding-right: 32px; }
.help { color: var(--muted); margin-top: 4px; }
.field-error { display: flex; gap: 6px; align-items: flex-start; margin-top: 6px; padding: 6px 10px; background: #fff3a8; color: #b00020; border-left: 4px solid #d0021b; border-radius: 6px; font-size: 14px; font-weight: 700; line-height: 1.35; }
.field-error::before { content: '⚠'; flex: 0 0 auto; }
.field-error:empty { display: none; }
/* A field (or card) with an error: red frame, light yellow inside. */
.has-error .in { border: 2px solid #d0021b; background: #fffbe0; }
section.card.has-error { border: 2px solid #d0021b; box-shadow: 0 0 0 3px #fff3a8; }
.has-error .drop, .has-error .opt { border-color: #d0021b; background: #fffbe0; }
.has-error > .lbl, .has-error .lbl { color: #b00020; }
.req { color: var(--err); }
.check { display: flex; gap: 12px; align-items: flex-start; min-height: 44px; padding: 4px 0; }
.check input { width: 20px; height: 20px; margin: 2px 0 0; flex-shrink: 0; accent-color: var(--brand); }
.opt { display: flex; align-items: center; gap: 12px; min-height: 52px; padding: 8px 14px; border: 1px solid var(--line); border-radius: 8px; cursor: pointer; background: #fff; }
.opt input { width: 20px; height: 20px; margin: 0; flex-shrink: 0; accent-color: var(--brand); }
.opt .grow { flex: 1 1 auto; min-width: 0; }
.opt .price { font-weight: 600; white-space: nowrap; }
.opt.is-off { background: var(--bg); cursor: not-allowed; }
.opt.is-off .name { color: var(--muted); }
.opts { display: flex; flex-direction: column; gap: 8px; }

/* ---------- buttons ---------- */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 44px; padding: 0 18px; border-radius: 8px; border: 1px solid var(--brand); background: var(--brand); color: #fff; font: inherit; font-weight: 600; text-decoration: none; cursor: pointer; text-align: center; }
.btn:hover { background: var(--brand-dark); border-color: var(--brand-dark); color: #fff; }
.btn.out { background: #fff; color: var(--brand); }
.btn.out:hover { background: var(--brand-2); border-color: var(--brand-2); color: #fff; }
.btn.danger { background: #fff; color: var(--err); border-color: var(--err); }
.btn.small { min-height: 40px; padding: 0 12px; }
.btn.block { width: 100%; }
.btn[disabled] { opacity: .55; cursor: not-allowed; }
.linkbtn { display: inline-flex; align-items: center; background: none; border: 0; padding: 0; min-height: 44px; font: inherit; color: var(--brand); text-decoration: underline; cursor: pointer; }

/* ---------- dropzone and file rows ---------- */
.drop { border: 2px dashed #a9bccd; border-radius: 8px; padding: 22px 16px; text-align: center; display: flex; flex-direction: column; align-items: center; gap: 6px; }
.is-over .drop, .drop.is-over, form.is-over textarea.in { border-color: var(--brand); background: #f0f7fc; }
.span-all { grid-column: 1 / -1; }
.files { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }
.file { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 12px; min-height: 48px; padding: 8px 12px; border: 1px solid var(--line); border-radius: 8px; background: #fff; color: var(--ink); text-decoration: none; }
a.file:hover { border-color: var(--brand); background: #f7fbfe; color: var(--ink); }
.file .nm { display: flex; flex-direction: column; min-width: 0; }
.file .act { font-weight: 600; color: var(--brand); }
.file.delivered { border-color: #7fbf96; background: #f3fbf6; }
.file.delivered .act { color: var(--ok); }
/* file row + optional photo thumbnail (click = full screen, row = download) */
.file-wrap { display: flex; gap: 10px; align-items: stretch; }
.file-wrap > .file { flex: 1 1 auto; min-width: 0; }
.thumb { flex: 0 0 auto; display: block; width: 72px; height: 72px; border-radius: 8px; border: 1px solid var(--line); overflow: hidden; background: var(--line-2); cursor: zoom-in; }
.thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.thumb:hover { border-color: var(--brand); }
/* full-screen photo viewer */
.lightbox { position: fixed; inset: 0; z-index: 100; background: #050f19; display: flex; flex-direction: column; }
.lightbox-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; padding: 10px 16px; color: #fff; }
.lightbox-bar .name { flex: 1 1 160px; min-width: 0; font-family: var(--mono); font-size: 14px; overflow-wrap: anywhere; }
.lightbox-bar .btn.out { background: transparent; color: #fff; border-color: #8fb3cc; }
.lightbox-bar .btn.out:hover { background: #fff; color: var(--ink); }
.lightbox-img { flex: 1 1 auto; min-height: 0; display: flex; align-items: center; justify-content: center; padding: 0 12px 12px; cursor: zoom-out; }
.lightbox-img img { width: 100%; height: 100%; object-fit: contain; }
body.no-scroll { overflow: hidden; }
.progress { height: 8px; border-radius: 2px; background: var(--line-2); overflow: hidden; }
.progress > i { display: block; height: 100%; width: 0; background: var(--brand-2); }

/* ---------- conversation ---------- */
.msgs { display: flex; flex-direction: column; }
.msg { display: flex; flex-direction: column; gap: 8px; border: 1px solid var(--line); background: #fff; }
.msg.note { background: var(--note-bg); border: 1px dashed var(--note-line); }
.msg .meta { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; color: var(--muted); }
.msg .meta strong { color: var(--ink); }
.msg .body { white-space: pre-wrap; }

/* ---------- lists / tables as clickable rows ---------- */
.rows { background: #fff; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.rows > .rh, .rows > a.r, .rows > div.r { display: grid; gap: 6px; padding: 12px 16px; border-top: 1px solid var(--line-2); color: var(--ink); text-decoration: none; align-items: center; }
.rows > :first-child { border-top: 0; }
.rows > a.r:hover, .rows > div.r.rowhost:hover { background: #f0f7fc; color: var(--ink); }
.rows > .rh { display: none; background: #eef3f7; font-size: 13px; font-weight: 600; color: #33475a; }
.rows .cell { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
/* 0.12.0: Admin › Customer emails: the template and its state on one row; two per row on a computer */
.rows .cell.em { flex-direction: row; flex-wrap: wrap; justify-content: space-between; align-items: baseline; column-gap: 12px; }
@media (min-width: 1024px) {
  .rows.em { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .rows.em > a.r { border-top: 1px solid var(--line-2); }
  .rows.em > a.r:nth-child(odd) { border-right: 1px solid var(--line-2); }
}
.cell > .chip { align-self: flex-start; }
@media (min-width: 1024px) {
  .rows > .rh { display: grid; }
}
/* 0.9.78: the queue table only from 1200 px (8 columns): between 1024 and 1199 the flexible columns
   got 3 px ("C u s t o m e r"); there the tickets are cards, two per row. Invoices: cards < 1024. */
@media (min-width: 1280px) { /* 0.13.30: at 1200–1279 px the eight columns overflowed by 49 px (Time cut off) */
  .rows.q > .rh, .rows.q > .r { grid-template-columns: 28px 100px minmax(150px, 1.1fr) minmax(140px, 1fr) minmax(180px, 1.6fr) 160px 120px 110px 140px; gap: 12px; }
  .rows.q .c-id .chip { align-self: flex-start; } /* 0.12.0: chips their own size, not full-width bars */
}
@media (min-width: 1024px) {
  .rows.inv > .rh, .rows.inv > a.r { grid-template-columns: 150px 110px minmax(160px, 1fr) 100px 100px; gap: 12px; }
}
@media (min-width: 1024px) and (max-width: 1279px) { /* 0.13.31: queue cards up to 1279 px, the table from 1280 */
  .rows.q > .rh { display: none; }
  .rows.q { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .rows.q > .r { border-top: 1px solid var(--line-2); }
  .rows.q > .r:nth-child(odd) { border-right: 1px solid var(--line-2); }
}
.stats { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin-bottom: 16px; }
@media (min-width: 1024px) { .stats { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); } }
.stat { display: flex; flex-direction: column; padding: 14px 16px; background: #fff; border: 1px solid var(--line); border-radius: 8px; text-decoration: none; color: var(--ink); min-height: 44px; }
.stat:hover { border-color: var(--brand); color: var(--ink); }
.stat b { font-size: 26px; line-height: 1.1; }
.filters { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; margin-bottom: 14px; align-items: end; }

/* ---------- operator / admin ---------- */
.grid-op { display: grid; grid-template-columns: minmax(0, 1fr); gap: 18px; align-items: start; }
/* 0.11.2: computer view from 1024 px: the side columns narrow with the window (down to 260 / 300 px
   at 1024), so the conversation in the middle keeps a usable width; full 290 / 360 px from ~1200. */
@media (min-width: 1024px) {
  .grid-op { grid-template-columns: clamp(260px, 24vw, 290px) minmax(0, 1fr) clamp(300px, 30vw, 360px); }
  /* 0.9.78: page order is conversation, work, details; on screen details left, work right. */
  .grid-op > .o-details { grid-column: 1; grid-row: 1; }
  .grid-op > #conversation { grid-column: 2; grid-row: 1; }
  .grid-op > .o-work { grid-column: 3; grid-row: 1; }
}
.ver { display: flex; flex-direction: column; gap: 6px; border: 1px solid var(--line); }
.ver.pending { border-color: var(--note-line); background: #fffaf0; }
.admin { display: grid; grid-template-columns: minmax(0, 1fr); gap: 20px; align-items: start; }
@media (min-width: 1024px) { .admin { grid-template-columns: 220px minmax(0, 1fr); } }
.side { display: flex; flex-wrap: wrap; gap: 4px; }
@media (min-width: 1024px) { .side { flex-direction: column; flex-wrap: nowrap; } }
.side a { display: flex; align-items: center; min-height: 42px; padding: 0 12px; border-radius: 8px; color: var(--ink); text-decoration: none; background: #fff; border: 1px solid var(--line); }
@media (min-width: 1024px) { .side a { background: none; border: 0; } }
.side a:hover { background: var(--line-2); color: var(--ink); }
.side a.on { background: var(--brand); color: #fff; font-weight: 600; }
/* 0.34.3: admin menu in five groups: a small blue heading each, a thin line between groups, tighter rows */
.side { display: block; }
.side .grp { padding-top: 8px; border-top: 1px solid var(--line); }
.side .grp:first-child { padding-top: 0; border-top: 0; }
.side .grp h4 { margin: 0 0 2px; padding: 0 12px; font-family: var(--font); font-size: 12px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--brand); }
.side .grp + .grp { margin-top: 8px; }
.side .grp a { min-height: 34px; font-size: 14.5px; }
@media (max-width: 1023px) { /* phones: two columns of groups, each a block with its heading; tap targets kept */
  .sidebox .side { gap: 10px 8px; align-items: start; }
  .side .grp { display: grid; gap: 4px; padding-top: 0; border-top: 0; }
  .side .grp + .grp { margin-top: 0; }
  .side .grp a { min-height: 40px; }
}
.sortable { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; min-height: 30px; }
.sortable li { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; min-height: 48px; padding: 6px 12px; border: 1px solid var(--line); border-radius: 8px; background: #fff; }
.sortable li:focus { outline: 3px solid #7fb6d8; }
.sortable li.dragging { opacity: .5; }
.sortable .grip { cursor: grab; color: #7d93a6; font-size: 18px; user-select: none; }
.sortable .grow { flex: 1 1 160px; min-width: 0; }
.lt { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; }
@media (min-width: 1024px) { .lt.two { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Translations (form sections, labels): the language code beside its box, not above it. Only for
   language codes (EN, IT…): longer labels stay above their box. 0.12.0: on the computer too. */
fieldset.lt.two.lang > div { display: grid; grid-template-columns: 40px minmax(0, 1fr); align-items: center; gap: 8px; }
fieldset.lt.two.lang > div > .lbl { margin: 0; font-size: 13px; }
/* 0.12.0: settings: a short value (number, amount, "07:00-23:00") beside its label, the help under
   both; on a computer two per row. */
.fs-grid { display: grid; gap: 12px 32px; align-items: start; }
@media (min-width: 1024px) { .fs-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.fs-n { display: grid; grid-template-columns: minmax(0, 1fr) 132px; align-items: center; gap: 4px 12px; }
.fs-n > .lbl { margin: 0; }
.fs-n > .help, .fs-n > .clamp-more { grid-column: 1 / -1; margin: 0; }
table.plain { width: 100%; border-collapse: collapse; font-size: 14px; }
table.plain th, table.plain td { text-align: left; padding: 8px; border-bottom: 1px solid var(--line-2); vertical-align: top; }
.tablewrap { overflow-x: auto; }
pre.prewrap { white-space: pre-wrap; margin: 0; font-family: var(--mono); font-size: 13px; }
.qr { width: 200px; height: 200px; border: 1px solid var(--line); border-radius: 8px; }
.narrow { max-width: 460px; margin: 0 auto; }
.flashwrap { padding-bottom: 0 !important; margin-bottom: -8px; }
.flashwrap .banner { margin-bottom: 0; }
.langform { display: flex; gap: 6px; align-items: center; }
.mt { margin-top: 14px; }
.mt-s { margin-top: 8px; }
.mb { margin-bottom: 14px; }
.m0 { margin: 0; }
.grow1 { flex: 1 1 auto; }
footer.foot { text-align: center; color: var(--muted); font-size: 13px; padding: 24px 16px; }

.quick { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.quick > span { flex: 1 1 100%; }

/* ---------- tip tiles (request form): big emoji, label, price; the whole tile is the choice ---------- */
.tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 8px; }
.tile { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; min-height: 92px; padding: 10px 6px; border: 2px solid var(--line); border-radius: 8px; background: var(--card); cursor: pointer; text-align: center; line-height: 1.25; }
.tile input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.tile .emo { font-size: 26px; line-height: 1; white-space: nowrap; letter-spacing: -3px; } /* 3 glasses on one line, even at 360 px */
.tile .lab { font-size: 13px; white-space: nowrap; }
.tile:has(input:checked) { border-color: var(--brand); }
.tile:has(input:focus-visible) { outline: 3px solid var(--brand-2); outline-offset: 2px; }
.pager { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 16px; }

/* ---------- request form: folded optional fields, compact extras, mobile total bar ---------- */
.more { border-top: 1px solid var(--line-2); padding-top: 2px; }
.more > summary { cursor: pointer; min-height: 40px; display: flex; align-items: center; gap: 6px; font-weight: 600; color: var(--brand); list-style: none; }
.more > summary::-webkit-details-marker { display: none; }
.more > summary::before { content: '+'; display: inline-flex; width: 22px; height: 22px; align-items: center; justify-content: center; border: 1px solid var(--line); border-radius: 6px; flex: 0 0 auto; }
.more[open] > summary::before { content: '−'; }
.more > summary .muted { font-weight: 400; font-size: 13px; }
.opt.compact { min-height: 44px; padding: 4px 14px; }
.mbar { display: none; }
@media (max-width: 1023px) {
  .mbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; position: fixed; left: 0; right: 0; z-index: 20; background: var(--card); border-top: 1px solid var(--line); }
  #request-form { padding-bottom: 72px; }
}
@media (min-width: 1024px) { .opts.two { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Extras in two columns: name, then price under it. */
/* One column on phones (no words cut in half), 2 on a computer (from 1024 px). */
[data-extras] .opts { display: grid; grid-template-columns: minmax(0, 1fr); }
@media (min-width: 1024px) { [data-extras] .opts { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Main services: name and price on one line, description on the full width below. */
.opt.main .head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.opt.main .head .price { flex: 0 0 auto; }
.opt.main .desc { display: block; margin-top: 2px; }
.tiles.three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.tiles.three .tile { min-height: 64px; }
/* "Custom work (quote)": green name, so it reads apart from the priced remaps. */
.opt.main.custom .name { color: #15803d; }
/* Processing speed: 1-3 rising bars per tile and a slow → fast track under the tiles. */
.speed { display: inline-flex; align-items: flex-end; gap: 3px; height: 16px; margin-bottom: 4px; }
.speed i { display: block; width: 6px; border-radius: 2px; background: var(--line); }
.speed i:nth-child(1) { height: 6px; } .speed i:nth-child(2) { height: 11px; } .speed i:nth-child(3) { height: 16px; }
.speed.lv1 i:nth-child(-n+1) { background: #6b9ab8; }
.speed.lv2 i:nth-child(-n+2) { background: #e08a00; }
.speed.lv3 i:nth-child(-n+3) { background: #c62828; }
.speed-track { display: flex; align-items: center; gap: 8px; margin-top: 8px; font-size: 12px; color: var(--muted); }
.speed-track i { flex: 1 1 auto; position: relative; height: 4px; border-radius: 2px; background: linear-gradient(90deg, #6b9ab8, #e08a00, #c62828); }
.speed-track i::after { content: ''; position: absolute; right: -2px; top: -4px; border: 6px solid transparent; border-right: 0; border-left: 8px solid #c62828; }

/* ---------- install steps (installer, start page, setup, first login) ---------- */
.steps { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; list-style: none; margin: 0 0 16px; padding: 0; }
.steps li { border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; font-size: 13px; line-height: 1.35; color: var(--muted); background: var(--card); }
.steps li .n { display: block; font-size: 12px; font-weight: 700; }
.steps li.on { border-color: var(--brand); color: var(--ink); font-weight: 600; box-shadow: inset 0 -3px 0 var(--brand); }
.steps li.done { color: var(--ok); background: var(--ok-bg); border-color: #b7dcc4; }
@media (max-width: 559px) { .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* ---------- request form: steps, conditions, compact services ---------- */
/* Conditions: each one a block with a number, the scrolling text (unchanged, below) and the box to tick. */
.terms-block { margin-bottom: 12px; padding: 12px; border: 1px solid var(--line); border-radius: 8px; background: var(--card); }
.terms-block:has(input:checked) { border-color: #b7dcc4; }
.terms-title { display: flex; align-items: flex-start; gap: 8px; font-size: 14px; line-height: 1.35; margin: 0 0 8px; }
.terms-block .terms-check { margin-top: 2px; padding: 10px 12px; border: 1px solid #a9bccd; border-radius: 8px; background: var(--info-bg); cursor: pointer; font-size: 14px; line-height: 1.45; }
.terms-block .terms-check:has(input:checked) { background: var(--ok-bg); border-color: #b7dcc4; }
.terms-block .terms-check:has(input:focus-visible) { outline: 3px solid var(--brand-2); outline-offset: 2px; }
.terms { font-size: 12px; line-height: 1.5; color: #3a4a57; white-space: pre-line; margin: 0 0 8px; }
/* On the request form the conditions are a 2-line box that scrolls (full text, little space). */
.terms-block .terms { height: calc(2 * 1.5em + 12px); overflow-y: auto; overscroll-behavior: contain; padding: 6px 10px; border: 1px solid #a9bccd; border-radius: 6px; background: var(--bg); scrollbar-gutter: stable; }
.terms-block .terms:focus { outline: 3px solid #7fb6d8; outline-offset: 1px; }
.terms-block .check { font-weight: 500; }
@media (min-width: 1024px) {
  .opts.mains { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* Extras on wide screens: 2 or 3 columns, whichever fills the rows (see the end of the file). */

/* ---------- admin: email log window ---------- */
.maillog { list-style: none; margin: 0; padding: 0; max-height: 520px; overflow-y: auto; border: 1px solid var(--line); border-radius: 8px; }
.maillog li { padding: 8px 12px; border-bottom: 1px solid var(--line-2); display: flex; flex-direction: column; gap: 2px; }
.maillog li:last-child { border-bottom: 0; }
.err-text { color: var(--err); overflow-wrap: anywhere; }
.self-end { align-self: flex-end; }

/* ---------- start page (the few seconds after a deploy or restart) ---------- */
body.boot { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 16px; background: var(--bg); }
.boot-card { width: 100%; max-width: 420px; text-align: center; background: var(--card); border: 1px solid var(--line); border-radius: 8px; padding: 32px 24px; display: flex; flex-direction: column; align-items: center; gap: 12px; }
.boot-card h1 { font-size: 22px; }
.boot-card p { margin: 0; }
.boot-mark { width: 48px; height: 48px; font-size: 18px; color: #fff; }
.boot-spin { width: 28px; height: 28px; border: 3px solid var(--line); border-top-color: var(--brand); border-radius: 50%; animation: boot-spin .9s linear infinite; }
@keyframes boot-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .boot-spin { animation: none; } }

/* ---------- service cards: everything top-aligned ----------
   Box, name and price share the first line; explanations go under the name. Cards in a row
   keep the same height, content always starts at the top. */
.opt.main { align-items: flex-start; }
.opt.main input { margin-top: 1px; }
[data-extras] .opt.compact { display: grid; align-items: start; column-gap: 10px; row-gap: 0; padding: 10px 12px; min-height: 0; line-height: 1.35; }
[data-extras] .opt.compact input { grid-area: box; margin: 0; }
[data-extras] .opt.compact .grow { grid-area: text; font-size: 14px; }
[data-extras] .opt.compact .price { grid-area: price; padding-left: 0; font-size: 14px; }
@media (max-width: 1023px) {
  [data-extras] .opt.compact .price { margin-top: 2px; }
}

/* ---------- label / value lists ----------
   0.9.97: the label stays beside its value at every width (the stacked layout for narrow cards
   is gone: it wasted a line per label). */
.card:has(.kv) { container-type: inline-size; }
.kv dt, .kv dd { overflow-wrap: break-word; word-break: normal; }

/* One-line value cut with "…" (full text in the tooltip): emails never break in the middle. */
.ellip { display: block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---------- suggestion list under make / ECU manufacturer (works on phones too) ---------- */
.has-suggest { position: relative; }
.suggest { position: absolute; left: 0; right: 0; z-index: 30; max-height: min(60vh, 440px); /* 0.17.5: ten rows before scrolling (was six) */ overflow-y: auto; background: #fff; border: 1px solid #a9bccd; border-radius: 8px; box-shadow: 0 8px 24px rgba(11, 42, 63, .15); }
.suggest button { display: block; width: 100%; min-height: 44px; padding: 10px 12px; border: 0; border-bottom: 1px solid var(--line-2); background: none; font: inherit; font-size: 16px; color: var(--ink); text-align: left; cursor: pointer; }
.suggest button:last-child { border-bottom: 0; }
.suggest button:hover, .suggest button[aria-selected="true"] { background: var(--info-bg); }

/* ---------- admin: system page ---------- */
.seg { display: flex; flex-wrap: wrap; gap: 4px; }
.seg a { display: inline-flex; align-items: center; min-height: 40px; padding: 0 12px; border: 1px solid var(--line); border-radius: 8px; font-size: 14px; text-decoration: none; color: var(--ink); background: #fff; }
.seg a.on { background: var(--brand); border-color: var(--brand); color: #fff; }
.grid2 { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; }
@media (min-width: 1024px) { .grid2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.h3 { font-size: 15px; margin: 0 0 8px; }
table.plain .num { text-align: right; white-space: nowrap; }
table.plain td .ellip { max-width: 220px; }
.cleanlist { list-style: none; margin: 0; padding: 0; border: 1px solid var(--line); border-radius: 8px; }
.cleanlist li { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; padding: 12px 14px; border-bottom: 1px solid var(--line-2); }
.cleanlist li:last-child { border-bottom: 0; }
.stats.m0 { margin: 0; }
.stat b { white-space: nowrap; }
@media (max-width: 559px) { .stat b { font-size: 21px; } }

/* Small text links still get a finger-sized target (40 px). */
.tap { display: inline-flex; align-items: center; min-height: 40px; }
/* Extra already in the chosen tuning: a green "Included" instead of a price. */
.incl-note { color: var(--ok); font-weight: 700; }
.opt.is-incl .price { display: none; }
/* "No remap" stands apart from the remaps: its own row, dashed border. */
.opts.mains .none-opt { grid-column: 1 / -1; margin-top: 8px; border-style: dashed; }
/* Long German compounds in narrow cards: hyphenate (lang is set on <html>), never cut mid-word. */
.opt .grow { -webkit-hyphens: manual; hyphens: manual; overflow-wrap: break-word; }
:lang(de) .opt .grow { -webkit-hyphens: auto; hyphens: auto; }
/* Fold-out rows (details/summary) are tap targets too. */
details:not(.more) > summary { padding: 10px 0; cursor: pointer; }
details:not(.more) > summary.btn { padding: 0 14px; } /* 0.9.75: a summary drawn as a button keeps its inner margins */
[data-sortable] > li { cursor: pointer; }
[data-sortable] > li .grip { cursor: grab; }
.plain pre.prewrap { overflow-wrap: break-word; max-width: 48ch; } /* audit log: long JSON wraps in its cell */
/* 0.12.0: audit details as "key: value" pairs. 0.12.9: wrapped between words only ("anywhere" let the
   column shrink to one character on a computer) and the widest column; the IP under who did it. */
.audit-d { display: block; overflow-wrap: break-word; }
table.audit td.a-det { min-width: 22ch; width: 45%; }
table.audit .a-ip { overflow-wrap: anywhere; } /* 0.13.7: after the email on the same line */
/* Statistics: ranked customers (whole row = link) and bars (progress elements: no inline styles under the CSP). */
.rank { list-style: none; margin: 0; padding: 0; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; background: #fff; }
.rank li + li { border-top: 1px solid var(--line-2); }
.rank a { display: grid; grid-template-columns: 34px minmax(0, 1fr) auto; gap: 10px; align-items: center; min-height: 44px; padding: 8px 12px; color: var(--ink); text-decoration: none; }
.rank a:hover { background: #f0f7fc; }
.rank .pos { color: var(--muted); font-weight: 700; font-size: 13px; }
.rank .rcust { display: flex; flex-direction: column; min-width: 0; } /* not .who: that is the header's user label */
.bars { list-style: none; margin: 0 0 8px; padding: 0; display: grid; gap: 6px; }
.bars li { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(60px, 1fr) 104px; gap: 10px; align-items: center; font-size: 14px; }
.bars li > strong { text-align: right; } /* fixed value column: every bar starts and ends at the same place */
.bars progress { -webkit-appearance: none; appearance: none; width: 100%; height: 10px; border: 0; border-radius: 4px; background: var(--line-2); overflow: hidden; }
.bars progress::-webkit-progress-bar { background: var(--line-2); border-radius: 4px; }
.bars progress::-webkit-progress-value { background: var(--brand-2); border-radius: 4px; }
.bars progress::-moz-progress-bar { background: var(--brand-2); border-radius: 4px; }
/* Statistic tiles: value, label, detail on fixed lines, so every tile in a row has the same shape. */
.stat .lab { font-size: 14px; font-weight: 600; margin-top: 4px; }
.stat .sub { font-size: 13px; color: var(--muted); min-height: 1.4em; }
.stats.k4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 1024px) { .stats.k4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } } /* 8 tiles = 2 full rows */
.grid3 { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; }
@media (min-width: 1024px) { .grid3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.grid2.tight { gap: 12px; }
/* 0.11.2: Admin › System: side by side only when each half is at least 380 px (the tables fit). */
@media (min-width: 1024px) { .grid2.fit { grid-template-columns: repeat(auto-fit, minmax(min(100%, 380px), 1fr)); } }
.grid2.tight .bars li { grid-template-columns: 56px minmax(40px, 1fr) 32px; }
/* 0.12.0: weekdays and slots side by side on phones too (short labels and counts) */
.grid2.tight { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 1023px) {
  .grid2.tight .bars li { grid-template-columns: 40px minmax(24px, 1fr) 28px; gap: 6px; }
  /* bars: the label wraps instead of being cut ("Bosch EDC17…" five times) */
  .bars li { grid-template-columns: minmax(0, 1fr) 56px 76px; }
  .bars li > .ellip { white-space: normal; overflow-wrap: anywhere; }
}
/* 0.12.0: rankings: the details under the name use the value column's width too */
.rank a { grid-template-areas: "pos name val" "pos sub sub"; row-gap: 2px; }
.rank .pos { grid-area: pos; align-self: start; padding-top: 2px; }
.rank .rcust { display: contents; }
.rank .rcust > strong { grid-area: name; }
.rank .rcust > .small { grid-area: sub; }
.rank a > strong.nowrap { grid-area: val; }
iframe.pdf { width: 100%; height: 75vh; min-height: 480px; border: 1px solid var(--line); border-radius: 8px; background: #fff; }

/* ---------- customer pages: v0.9.10 refinements ---------- */
.nowrap-row { flex-wrap: nowrap; }
.nowrap-row > * { min-width: 0; } /* long labels (Russian) wrap inside the button instead of pushing past the edge */
.files:empty { display: none; }
.file .nm { flex: 1 1 240px; }
.file .nm .mono { overflow-wrap: anywhere; }
.search { display: flex; gap: 8px; }
.search .in { flex: 1 1 auto; min-width: 0; }
.search .btn { flex: 0 0 auto; }
/* Phone: the search button keeps only the magnifier, so the hint in the field is not cut. */
@media (max-width: 1023px) { .search .lbl-d { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; } .search .btn { padding: 0 14px; } }
@media (max-width: 1023px) { .only-d { display: none !important; } }
@media (min-width: 1024px) { .only-m { display: none !important; } }
/* Vehicle card: short values, so label and value stay side by side even in a narrow card. */
@container (max-width: 440px) {
  .kv.pair dt { font-size: 14px; margin-top: 0; }
}
/* Billing fields: postcode next to the city at every width; country next to the VAT number on a computer (from 1024 px). */
.billgrid { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 12px; }
.b-full { grid-column: span 6; }
.b-zip { grid-column: span 2; }
.b-city { grid-column: span 4; }
.b-half { grid-column: span 3; }
@media (max-width: 1023px) { .b-half { grid-column: span 6; } } /* 0.9.75: country and VAT number one under the other on phones */
.card > details.more:first-child { border-top: 0; padding-top: 0; }
@media (max-width: 1023px) {
  .banner > .btn, .banner > form { flex: 1 1 100%; }
  .banner > form .btn { width: 100%; }
  /* Payment page on a phone: what you pay for first, then the methods. */
  .pay-grid > aside { order: -1; position: static; }
}

/* =====================================================================================
   v0.9.11 — customer interface, mobile first.
   One strong element per page: the order rail (request > payment > work > file ready).
   Amber = "your turn" (pay, accept, reply), blue = we are working, green = done / file ready.
   ===================================================================================== */

/* ---------- type and controls ---------- */
.btn { font-family: var(--font-c); font-size: 16px; letter-spacing: .01em; transition: background-color .15s, border-color .15s, transform .05s; }
.btn:active { transform: translateY(1px); }
.btn .ic { width: 20px; height: 20px; flex: 0 0 auto; }
.btn.ok { background: var(--go); border-color: var(--go); }
.btn.ok:hover { background: var(--go-dark); border-color: var(--go-dark); }
.btn.small { font-size: 15px; }
.ic { display: inline-block; vertical-align: middle; }
.card { box-shadow: var(--shadow); border-color: #dde5ec; }
.lead { font-size: 16px; }
.small { font-size: 14px; }
.help { font-size: 14px; }
label.lbl, .lbl { font-size: 14px; }
.chip { font-family: var(--font-c); font-size: 14px; }
.tap.back { gap: 6px; color: var(--muted); text-decoration: none; font-weight: 500; font-size: 15px; }
.tap.back:hover { color: var(--brand); }
.tap.back .ic { width: 18px; height: 18px; }
.mono { font-variant-ligatures: none; }
.wrap { padding-top: 16px; }

/* ---------- top bar (customer) ---------- */
body.cust .top { position: sticky; top: 0; z-index: 35; box-shadow: 0 1px 0 rgba(255, 255, 255, .06), 0 2px 10px rgba(0, 0, 0, .18); }
body.cust .top-in { min-height: 56px; padding-top: 6px; padding-bottom: 6px; }
/* 0.11.0: what a link jumps to (#coupon, #proof, a box opened by a link) and the sticky side cards
   stop under the sticky bar, not behind it (the order card on the payment page lost its title). */
html:has(> body.cust) { scroll-padding-top: 72px; }
body.cust .sticky { top: 76px; }
.brand { font-family: var(--font-c); font-size: 19px; letter-spacing: .01em; }
.brand-name { display: inline-flex; align-items: baseline; gap: 8px; }
.brand .sub { font-family: var(--font); font-size: 14px; }
.brand-mark { border-radius: 8px; font-family: var(--font-c); font-size: 14px; }
.nav.tabs-m .ic { display: none; }
.langcode { display: inline-flex; align-items: center; gap: 6px; }
.langcode .ic { width: 18px; height: 18px; color: #a9cde3; }
.bell-btn { color: #fff; font-size: 0; }
.bell-btn .ic { width: 22px; height: 22px; }
.bell-dot { top: 8px; right: 8px; }

/* Phone: slim bar on top (logo, language, alerts), the menu as a tab bar under the thumb. */
@media (max-width: 1023px) {
  body.cust { padding-bottom: calc(68px + env(safe-area-inset-bottom)); }
  body.cust .top-in .nav.tabs-m {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 40; order: 9; margin: 0;
    display: flex; flex-wrap: nowrap; gap: 4px; padding: 6px 8px calc(6px + env(safe-area-inset-bottom));
    background: var(--top); border-top: 1px solid #1f4a68; box-shadow: 0 -4px 16px rgba(0, 0, 0, .18);
  }
  body.cust .nav.tabs-m a { flex: 1 1 0; flex-direction: column; justify-content: center; gap: 3px; min-height: 52px; padding: 2px 4px; font-family: var(--font-c); font-size: 13px; font-weight: 600; line-height: 1.1; color: #a9cde3; text-align: center; }
  body.cust .nav.tabs-m a .ic { display: block; width: 22px; height: 22px; }
  body.cust .nav.tabs-m a.on { background: var(--top-2); color: #fff; }
  body.cust .nav.tabs-m a.on .ic { color: #7fd0ff; }
  .mbar { bottom: calc(64px + env(safe-area-inset-bottom)); padding: 10px 16px; box-shadow: 0 -6px 16px rgba(11, 42, 63, .10); }
  .mbar strong { font-family: var(--font-c); font-size: 20px; }
  .tools .out-d { display: none; }
  .langpick { padding: 0 10px; }
  footer.foot { padding-bottom: 16px; }
}

/* ---------- order rail ---------- */
.rail { list-style: none; margin: 18px 0 0; padding: 0; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); }
.rail .st { position: relative; display: flex; flex-direction: column; align-items: center; gap: 6px; text-align: center; min-width: 0; }
.rail .st::before { content: ''; position: absolute; top: 13px; left: -50%; right: 50%; height: 3px; background: var(--line); }
.rail .st:first-child::before { display: none; }
.rail .st.done::before, .rail .st.now::before, .rail .st.turn::before { background: var(--brand); }
.rail .pt { position: relative; z-index: 1; display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: 8px; background: #fff; border: 2px solid var(--line); color: #fff; }
.rail .pt .ic { width: 18px; height: 18px; stroke-width: 2.6; }
.rail .done .pt { background: var(--brand); border-color: var(--brand); }
.rail .now .pt { border: 3px solid var(--brand); }
.rail .now .pt::after { content: ''; width: 10px; height: 10px; border-radius: 3px; background: var(--brand); }
.rail .turn .pt { background: var(--turn); border-color: var(--turn); }
.rail .turn .pt::after { content: '!'; font-family: var(--font-c); font-weight: 700; font-size: 17px; color: var(--turn-ink); line-height: 1; }
.rail .lb { font-family: var(--font-c); font-size: 14px; font-weight: 600; line-height: 1.2; color: var(--muted); overflow-wrap: anywhere; }
.rail .done .lb { color: var(--ink); }
.rail .now .lb, .rail .turn .lb { color: var(--ink); font-weight: 700; }
.rail .todo .lb { font-weight: 600; color: var(--muted); } /* 0.9.75: 6.4:1 (was 4.3:1) */
.rail.ended .st::before { background: var(--line); }
.rail.ended .done .pt { background: #7d93a6; border-color: #7d93a6; }
@media (prefers-reduced-motion: no-preference) {
  .rail .now .pt::after { animation: rail-beat 1.8s ease-in-out infinite; }
  @keyframes rail-beat { 50% { transform: scale(.55); opacity: .55; } }
}
/* list version: four bars */
.rail.mini { margin: 0; gap: 4px; max-width: 240px; width: 100%; }
.rail.mini .st::before { display: none; }
.rail.mini .pt { width: 100%; height: 6px; border: 0; border-radius: 2px; background: var(--line); }
.rail.mini .done .pt { background: var(--brand); }
.rail.mini .now .pt { background: repeating-linear-gradient(90deg, var(--brand) 0 6px, #8cb8d3 6px 10px); }
.rail.mini .now .pt::after, .rail.mini .turn .pt::after { display: none; }
.rail.mini .turn .pt { background: var(--turn); }
.rail.mini.ended .done .pt { background: #9fb1c1; }

/* ---------- status label (one per ticket, customer words) ---------- */
.cstatus { display: inline-flex; align-items: center; gap: 7px; min-height: 30px; padding: 3px 10px; border-radius: 6px; font-family: var(--font-c); font-size: 15px; font-weight: 600; line-height: 1.15; background: var(--info-bg); color: var(--info); }
.cstatus::before { content: ''; flex: 0 0 auto; width: 8px; height: 8px; border-radius: 2px; background: currentColor; }
.cstatus.turn { background: var(--turn-bg); color: var(--turn-ink); box-shadow: inset 0 0 0 1px #f3cf86; }
.cstatus.turn::before { background: var(--turn); }
.cstatus.ok { background: var(--ok-bg); color: var(--ok); }
.cstatus.err { background: var(--err-bg); color: var(--err); }
.cstatus.muted { background: var(--line-2); color: var(--muted); }

/* ---------- ticket hero ---------- */
.hero { margin: 8px 0 14px; padding: 18px 16px 0; overflow: hidden; }
.hero-id { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: flex-start; gap: 2px 12px; }
.hero-id .cstatus { margin-left: auto; align-self: center; }
.tnum { font-family: var(--font-c); font-weight: 700; letter-spacing: .02em; font-variant-numeric: tabular-nums; }
h1.tnum { font-size: 30px; line-height: 1.1; }
.hero .veh { margin: 0; font-size: 18px; font-weight: 600; line-height: 1.25; } /* 0.26.0: on the number's row */
/* 0.9.93: the ECU right after the make, on the same line when it fits; otherwise on the next line,
   whole, with its label (no "·" between them: a line would start with it). */
.hero .veh { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 14px; row-gap: 4px; }
.hero .veh .ecu { display: block; font-size: 15px; font-weight: 500; color: var(--ink); }
.hero .k { color: var(--muted); font-weight: 500; }
.hero .svc { margin: 2px 0 0; font-size: 15px; line-height: 1.45; color: var(--ink); }
/* 0.26.0: a tighter head: smaller number, rail and paddings (phone 201 → 164 px, computer 140 → 86 px) */
.hero { padding: 12px 16px 0; }
.hero h1.tnum { font-size: 24px; }
.hero > .rail { margin: 10px 0 0; }
.hero > .rail .pt { width: 24px; height: 24px; }
.hero > .rail .pt .ic { width: 16px; height: 16px; }
.hero > .rail .st::before { top: 11px; }
.hero > .rail .lb { font-size: 13px; }
.hero .hero-next { margin-top: 12px; padding: 10px 16px; }
.hero .svc .it { white-space: nowrap; font-weight: 600; }
.hero .svc .sep { color: var(--muted); }
.hero-next { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 16px; margin: 18px -16px 0; padding: 14px 16px; border-top: 1px solid var(--line-2); background: var(--info-bg); color: var(--info); }
.hero-next > p { flex: 1 1 280px; }
.hero-next.warn { background: var(--turn-bg); color: var(--turn-ink); border-top-color: #f3cf86; }
.hero-next.ok { background: var(--ok-bg); color: var(--ok); border-top-color: #b7dcc4; }
.hero-next.muted { background: var(--line-2); color: var(--muted); }
.hero-next form { margin: 0; }
@media (max-width: 1023px) {
  .hero-next .btn, .hero-next form { flex: 1 1 100%; width: 100%; }
  .hero-next form .btn { width: 100%; }
  .btn { min-height: 48px; }
}
@media (min-width: 1024px) {
  .hero { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(300px, .9fr); grid-template-areas: "id rail" "svc rail" "next next"; column-gap: 28px; padding: 12px 20px 0; }
  .hero-id { grid-area: id; }
  .hero .svc { grid-area: svc; }
  .hero > .rail { grid-area: rail; align-self: center; margin: 0; }
  .hero .hero-next { grid-area: next; margin: 12px -20px 0; padding: 10px 20px; }
}

/* ---------- conversation: speech bubbles ---------- */
.msgs { gap: 10px; }
.msg { max-width: 94%; align-self: flex-start; padding: 12px 14px; border-color: #dde5ec; box-shadow: var(--shadow); border-radius: 8px 8px 8px 2px; }
.msg.me { align-self: flex-end; background: #e5f0f8; border-color: #c7dcec; border-radius: 8px 8px 2px 8px; box-shadow: none; }
.msg.sys { background: #fff; border-color: #dde5ec; font-size: 15px; }
.msg:has(.file.delivered) { border-color: #9fd0b0; }
.msg .meta { font-size: 13px; }
.msg .meta strong { font-family: var(--font-c); font-size: 15px; }
.msg .body { font-size: 16px; line-height: 1.45; }
@media (min-width: 1024px) { .msg { max-width: 86%; } }
.file { box-shadow: none; }
.file .act { display: inline-flex; align-items: center; gap: 6px; font-family: var(--font-c); font-size: 15px; }
.file .nm .mono { font-size: 14px; font-weight: 500; }

/* ---------- reply ---------- */
#reply.card { border-top: 3px solid var(--brand); }
#reply.card textarea.in { min-height: 104px; }

/* ---------- tickets list ---------- */
.rows.ct { box-shadow: var(--shadow); border-color: #dde5ec; }
.rows.ct > a.r { gap: 8px; padding: 14px 16px; }
.rows.ct .c-id { flex-direction: row; align-items: center; justify-content: space-between; gap: 8px; }
.rows.ct .tnum { font-size: 18px; }
.rows.ct .veh { font-size: 17px; font-weight: 600; }
.rows.ct .veh-row { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 12px; } /* 0.12.0: the ECU on the make's row when it fits */
.rows.ct .c-st { gap: 8px; }
.rows.ct .cstatus { font-size: 14px; min-height: 28px; }
@media (min-width: 1024px) {
  .rows.ct > .rh, .rows.ct > a.r { grid-template-columns: 120px minmax(0, 1.6fr) minmax(220px, 1fr) 150px; gap: 16px; }
  .rows.ct .c-st { align-items: flex-start; }
}
@media (max-width: 1023px) { .page-head > .btn[href="/new"] { display: none; } }

/* ---------- payment ---------- */
.ver { border-radius: 8px; padding: 14px; }
.ver > strong { font-family: var(--font-c); font-size: 17px; }
.sumrow.total { font-family: var(--font-c); font-size: 20px; }
.sumrow.total span:last-child { font-variant-numeric: tabular-nums; }

/* ---------- request form ---------- */
/* Sections numbered in the order they appear (hidden ones are not counted). */
/* Section numbers: set by app.js on the sections on screen (1, 2, 3… with no gaps). */
#request-form section.card[data-step] > h2::before { content: attr(data-n); display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; margin-right: 10px; border-radius: 8px; background: var(--top); color: #fff; font-size: 16px; vertical-align: 2px; }
.opt { transition: border-color .12s, background-color .12s; }
/* 0.35.3: a selectable service lights up under the mouse (not the ones that cannot be chosen) */
@media (hover: hover) { .opt:not(.is-off):hover { border-color: var(--brand-2); background: #f7fbfe; } }
.opt:has(input:checked) { border-color: var(--brand); box-shadow: inset 0 0 0 1px var(--brand); background: #f2f8fc; }
.opt:has(input:checked) .name { color: var(--brand-dark); }
.opt .name { font-family: var(--font-c); font-size: 17px; font-weight: 600; }
[data-extras] .opt.compact .name { font-size: 16px; }
.opt .price, .tile strong { font-family: var(--font-c); font-size: 17px; font-variant-numeric: tabular-nums; }
.tile { border-width: 1px; }
.tile:has(input:checked) { box-shadow: inset 0 0 0 1px var(--brand); background: #f2f8fc; }
.drop { border-color: #9fb6ca; background: #f8fbfd; }
@media (max-width: 1023px) {
  /* Extras two by two: half the scrolling on a phone. */
  [data-extras] .opt.compact { padding: 10px; }
  [data-extras] .opt.compact .grow { font-size: 14px; }
  [data-extras] .opt.compact .price { font-size: 16px; }
  body.cust .nav.tabs-m { transition: transform .22s ease; }
  body.tabs-away .nav.tabs-m { transform: translateY(105%); }
  body.tabs-away .mbar { bottom: 0; padding-bottom: calc(10px + env(safe-area-inset-bottom)); }
  .mbar { transition: bottom .22s ease, transform .22s ease; }
  .mbar.mbar-off { transform: translateY(calc(100% + 80px)); }
}
@media (max-width: 1023px) and (prefers-reduced-motion: reduce) { body.cust .nav.tabs-m, .mbar { transition: none; } }
.acc-mail { font-size: 17px; font-weight: 500; color: var(--muted); }
/* Typing on a phone: the tab bar leaves room for the keyboard and the field. */
@media (max-width: 1023px) {
  body.cust:has(:is(input:not([type="checkbox"]):not([type="radio"]):not([type="file"]), textarea):focus) .nav.tabs-m { transform: translateY(105%); }
}

/* ---------- v0.9.13 ---------- */
.hero-next.final p::first-letter { text-transform: uppercase; }
.hero-next .tap { font-weight: 600; }
.self-start { align-self: flex-start; }
.svcline { color: var(--ink); }
/* A hidden file input focused by keyboard outlines its visible button. */
label.btn:has(+ input.sr:focus-visible) { outline: 3px solid #7fb6d8; outline-offset: 1px; }
/* Bank transfer details: readable, easy to select. */
#proof .instr { font-size: 15px; line-height: 1.5; padding: 6px 12px; background: var(--bg); border-radius: 8px; }
.instr p { display: flex; align-items: center; gap: 8px; min-height: 28px; }
.instr p .mono { flex: 1 1 auto; min-width: 0; white-space: pre-wrap; overflow-wrap: anywhere; }
.instr p.blank { min-height: 8px; }
/* Copy button: amount, reference, IBAN or wallet in one tap (typing them on a phone is where mistakes happen). */
.copy { position: relative; flex: none; width: 40px; height: 40px; display: inline-grid; place-items: center; margin-left: 8px; vertical-align: middle;
  border: 1px solid var(--line); border-radius: 8px; background: var(--card); color: var(--brand); cursor: pointer; }
.copy:hover { border-color: var(--brand-2); }
.copy .ic { width: 18px; height: 18px; }
.copy.done { color: var(--go); border-color: var(--go); }
.copy.done::after { content: attr(data-done); position: absolute; right: 0; bottom: calc(100% + 4px); padding: 2px 8px; border-radius: 6px;
  background: var(--top); color: #fff; font: 600 12px/1.6 var(--font); white-space: nowrap; }
.paydata dd { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.paydata dt { align-self: center; }
.paydata dd .copy { margin-left: 8px; }
/* Bell: a dot only when it means something (on = green, needs action = amber). */
.bell:not([data-state="on"]):not([data-state="none"]) .bell-dot { display: none; }
/* Order bar on a phone: only once there is a total to show. */
.mbar.mbar-empty { display: none !important; }
/* Thank-you after payment: what happens next, as a short numbered sequence. */
.thanks { flex-direction: column; align-items: stretch; gap: 8px; }
.hero-next.thanks > * { flex: none; }
.thanks .thanks-title { font-family: var(--font-c); font-size: 20px; font-weight: 700; }
.thanks ol.after { margin: 0; padding-left: 22px; display: flex; flex-direction: column; gap: 6px; color: var(--ink); }
.thanks ol.after li::marker { font-family: var(--font-c); font-weight: 700; color: var(--ok); }
.thanks .tap { gap: 6px; font-weight: 600; color: var(--ok); }
.thanks .tap .ic { width: 18px; height: 18px; }

/* ---------- v0.9.15: operator queue ---------- */
.stat.on { border-color: var(--brand); box-shadow: inset 0 0 0 1px var(--brand); background: #f2f8fc; }
.chip.next { font-size: 15px; min-height: 30px; }
.filterbox { margin-bottom: 14px; }
.filterbox > summary { list-style: none; cursor: pointer; margin-bottom: 10px; }
.filterbox > summary::-webkit-details-marker { display: none; }
@media (min-width: 1024px) { .filterbox > summary { display: none; } }
@media (max-width: 1023px) {
  .stats .stat { padding: 10px 12px; }
}
@media (max-width: 1199px) {
}
/* ---------- v0.9.15: operator ticket ---------- */
.opstep { flex-wrap: wrap; align-items: center; gap: 10px 14px; margin: 0 0 16px; padding: 12px 16px; background: var(--card); border: 1px solid #dde5ec; border-left: 4px solid var(--brand); border-radius: 8px; box-shadow: var(--shadow); }
.opstep form { display: flex; align-items: center; gap: 8px; margin: 0; }
.composer.is-note { background: var(--note-bg); border-color: var(--note-line); }
.composer.is-note [data-canned] { opacity: .45; pointer-events: none; }
/* Notes written in the request form, inside the customer's first bubble. Not yellow: yellow means internal note. */
.reqnote { margin-top: 4px; padding: 8px 10px; background: var(--card); border-left: 3px solid var(--brand-2); border-radius: 6px; white-space: pre-wrap; }
.reqnote .small { white-space: normal; }
.proofbox { display: flex; flex-direction: column; gap: 6px; padding: 10px; background: #fff; border: 1px solid var(--line); border-radius: 8px; }
.proofbox .thumb { width: 100%; height: 220px; }
.proofbox .file-wrap { flex-direction: column; }
/* Phone: the conversation and the composer come before the side cards. */

/* =====================================================================================
   v0.9.15 — login code, payment details to copy.
   ===================================================================================== */
.in.code-in { font: 600 22px/1.2 var(--mono); letter-spacing: .3em; text-align: center; }
/* Russian: our Barlow files carry Latin only; one system font for the whole page instead of
   Cyrillic letters in a fallback font next to Latin ones in Barlow. */
:root:lang(ru) { --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; --font-c: var(--font); }
/* IMMO Off: the whole published table, grouped by make; the customer picks the row of the ECU. */
.immo-box { margin: 0; padding: 12px; border: 1px solid var(--line); border-radius: 8px; background: var(--bg); display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.immo-box legend { padding: 0 4px; }
.immo-brand { font-family: var(--font-c); }
.immo-group .opts { grid-template-columns: minmax(0, 1fr); margin-top: 6px; }
.immo-row .ecus { font-size: 14px; line-height: 1.4; overflow-wrap: anywhere; }
.immo-row .price { white-space: normal; text-align: right; max-width: 92px; } /* "49,99–149,99 €" wraps instead of squeezing the ECU list */

/* Option grids (app.js balanceGrids): never one choice alone in half a row. 4 extras = 2 x 2;
   3 columns only on wide screens and only when the count fills them better (3, 5, 6, 9…). */
.opts.n-odd > .last-vis { grid-column: 1 / -1; }
@media (min-width: 1024px) {
  [data-extras] .opts.n3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  [data-extras] .opts.n3 > .last-vis { grid-column: auto; }
  [data-extras] .opts.n3.lone3 > .last-vis { grid-column: 1 / -1; }
}

/* Request form, summary card (0.9.27): information only, below the sticky top bar. */
/* Always in sight while the page scrolls, down to the very bottom of the page: fixed below the top
   bar and never taller than the screen minus the top bar and the page footer (76 + ~134 px); a
   longer list of services (many extras) scrolls inside the card; total and next steps stay in sight. */
@media (min-width: 1024px) {
  body.cust .grid-main > aside.sum-side { top: 76px; max-height: calc(100vh - 210px); display: flex; flex-direction: column; overflow: hidden; }
  body.cust .grid-main > aside.sum-side > * { flex: 0 0 auto; }
  /* Only the list of services scrolls; the total and the next steps stay in sight. */
  body.cust .grid-main > aside.sum-side > [data-summary] { flex: 0 1 auto; min-height: 48px; overflow-y: auto; overscroll-behavior: contain; }
}
.sum-info { margin: 0 0 10px; padding: 0 0 10px; border-bottom: 1px solid var(--line); }
.sum-info > div { display: flex; flex-wrap: wrap; column-gap: 6px; align-items: baseline; line-height: 1.4; } /* 0.19.2: "Vehicle: BMW" on one line when it fits; else the label alone and the value whole on the next line */
.sum-info > div + div { margin-top: 4px; }
.sum-info dt { flex: none; color: var(--muted); font-size: 13px; }
.sum-info dt::after { content: ":"; }
.sum-info dd { flex: 0 1 auto; max-width: 100%; margin: 0; font-size: 14px; font-weight: 600; overflow-wrap: anywhere; }
.sum-next { margin-top: 12px; padding: 10px 12px; border-radius: 8px; background: var(--info-bg); color: var(--info); font-size: 13px; line-height: 1.5; }
.sum-next ol { margin: 4px 0 0; padding-left: 18px; }
/* End of the form: total and "Continue", where the customer has just ticked the conditions. */
.endbar-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; }
.endbar-total strong { font-size: 22px; font-variant-numeric: tabular-nums; }
.endbar-btn { min-width: 260px; min-height: 48px; font-size: 17px; }
@media (max-width: 559px) { .endbar-btn { flex: 1 1 100%; min-width: 0; } }

/* Request form (0.9.29): all sections on screen; they light up from top to bottom as completed.
   Rail on the left fills (green, glowing) down to the last section done in a row; done = green
   tick in the number badge; the first one to do = blue frame; the ones after it dimmed but usable. */
.form-steps { position: relative; padding-left: 30px; }
.form-steps > .rail { position: absolute; left: 10px; top: 0; bottom: 0; width: 6px; border-radius: 3px; background: var(--line); }
.form-steps > .rail > b { position: absolute; left: 0; right: 0; top: 0; height: 0; border-radius: 3px; background: linear-gradient(180deg, #1f9d55, #3fbf75); box-shadow: 0 0 10px rgba(31, 157, 85, .55); transition: height .35s ease-out; }
#request-form section.card.is-done > h2::before { content: '✓'; background: #1f9d55; }
#request-form section.card.is-done { box-shadow: inset 0 0 0 1px #b7dcc4; }
#request-form section.card.is-now { box-shadow: 0 0 0 2px var(--brand-2); }
/* 0.9.78: a step not reached yet is told by its grey number and a quieter card, never by fading its
   text (labels, help and conditions were at 2.2–3.2:1 on phones, which have no hover). */
#request-form section.card.is-todo { background: #fbfcfd; box-shadow: none; }
#request-form section.card.is-todo > h2::before { background: #6b7f91; }
@media (max-width: 1023px) {
  .form-steps { padding-left: 18px; }
  .form-steps > .rail { left: 4px; width: 5px; }
}
@media (prefers-reduced-motion: reduce) { .form-steps > .rail > b { transition: none; } }

/* Processing speed (0.9.29): with room enough (the tiles box at least 560 px wide), bars and name
   on the left, the price on the right of the same row; narrower, stacked as before. */
.tiles.three:has(.speed-tile) { container-type: inline-size; }
@container (min-width: 560px) {
  .speed-tile { flex-direction: row; justify-content: flex-start; gap: 10px; min-height: 56px; padding: 10px 14px; text-align: left; }
  .speed-tile .speed { margin-bottom: 0; }
  .speed-tile .tile-price { margin-left: auto; }
}

/* End bar (0.9.30): never dimmed; under the button "almost there" until the form is complete,
   then "all set" in green (the state comes from the progress rail: .is-done on the end bar). */
#request-form section.card.endbar.is-todo > *, #request-form section.card.endbar.is-now > * { opacity: 1; }

/* "Custom work (quote)" (0.9.31): warning that a request for a service already listed is closed. */
.opt.main .custom-note { display: block; margin-top: 4px; color: var(--warn); font-weight: 600; }

/* Extras (0.9.31, layout C): name, price under it, then the plain words; all on the full width
   of the card, nothing beside the text. Words are hyphenated only in German. */
/* 0.26.0: one row per extra: box | name and plain words (wrapping) | price, always on the first line. */
[data-extras] .opt.compact { grid-template-columns: 20px minmax(0, 1fr) auto; grid-template-rows: auto; grid-template-areas: "box text price"; align-items: start; align-content: start; }
/* One line per row: the name whole, the plain words cut with "…" where they do not fit (whole text in the tooltip). */
[data-extras] .opt.compact .grow { display: grid; grid-template-columns: minmax(0, max-content) minmax(0, 1fr) auto; align-items: baseline; column-gap: 6px; min-width: 0; }
[data-extras] .opt.compact .grow > .name { grid-column: 1; min-width: 0; font-size: 16px; } /* a name longer than the row wraps (Russian at 320 px) */
[data-extras] .opt.compact .grow > .hint { grid-column: 2; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; }
[data-extras] .opt.compact .grow > .incl-note { grid-column: 3; white-space: nowrap; }
[data-extras] .opt.compact .grow > .part-note, [data-extras] .opt.compact .grow > .svc-note { grid-column: 1 / -1; }
/* one column of groups at every width: two narrow columns left no room for the words */
[data-extras] .opts:has(> details.xg) { grid-template-columns: minmax(0, 1fr); }
[data-extras] .opt.compact > .price { grid-area: price; margin: 1px 0 0; padding: 0; font-size: 15px; color: var(--brand); white-space: nowrap; }
[data-extras] .opt.compact.is-incl > .price, [data-extras] .opt.compact.is-part > .price { display: none; }
@media (max-width: 399px) { [data-extras] .opt.compact { padding: 10px 8px; column-gap: 8px; } [data-extras] .opt.compact .small { font-size: 13px; } }

/* IMMO table search (0.9.33): a plain box with 8 px corners on every browser. */
.immo-box input[type=search].in { -webkit-appearance: none; appearance: none; }

/* IMMO brand groups (0.9.35): folded boxes, closed; the whole row opens them (tap target 48 px). */
details.immo-group { border: 1px solid var(--line); border-radius: 8px; background: var(--card); }
details.immo-group > summary.immo-brand { display: flex; align-items: center; gap: 10px; min-height: 48px; padding: 8px 12px; cursor: pointer; list-style: none; }
details.immo-group > summary.immo-brand::-webkit-details-marker { display: none; }
details.immo-group > summary.immo-brand::before { content: '+'; flex: 0 0 auto; display: inline-flex; width: 22px; height: 22px; align-items: center; justify-content: center; border: 1px solid var(--line); border-radius: 6px; color: var(--brand); font-weight: 700; }
details.immo-group[open] > summary.immo-brand::before { content: '−'; }
details.immo-group[open] > summary.immo-brand { border-bottom: 1px solid var(--line-2); }
details.immo-group > summary.immo-brand:focus-visible { outline: 3px solid var(--brand-2); outline-offset: 2px; }
details.immo-group > .opts { margin: 0; padding: 8px; }

/* 0.9.39: few main services (gearbox, IMMO, agri/truck): one service per row, also on wide screens. */
@media (min-width: 1024px) {
  .opts.mains.one-col { grid-template-columns: minmax(0, 1fr); }
  .opts.mains.one-col > .last-vis { grid-column: auto; }
}

/* 0.9.40: "Need an invoice? Fill in the details" as big as the section titles ("Buy our operators a beer"). */

/* 0.9.42: operator queue as cards (up to 1199 px; from 1200 px the table). 0.12.3: as dense as the
   Zoho Desk app, nothing removed, in reading order: number + next step | payment; priority, beers and
   work status; vehicle, ECU and services in one text; customer · email on one line ("…" when long);
   the operator on the work-status row; submitted and updated on one line. The next step and the
   chips are written twice in the row (queue.ejs): each layout shows one copy. */
.rows.q .m-only { display: none; }
.rows.q .q-vs { display: contents; } /* the table: its cells are columns */
@media (min-width: 1280px) { .rows.q .c-id > .chip.next, .rows.q .c-next > .id-chips { display: none; } }
@media (max-width: 1279px) {
  .rows.q > .r { grid-template-columns: minmax(0, 1fr) auto auto; grid-template-areas: "id pay sel" "next op op" "vs vs vs" "cust cust cust" "time time time"; gap: 5px 10px; padding: 10px 12px; }
  .rows.q .c-id > .id-chips, .rows.q .c-next > .chip.next { display: none; }
  .rows.q .c-id { grid-area: id; flex-direction: row; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
  .rows.q .c-id .mono { font-size: 17px; }
  .rows.q .c-pay { display: flex; grid-area: pay; align-self: start; justify-self: end; }
  .rows.q .c-id .chip, .rows.q .c-next .chip, .rows.q .c-pay .chip { min-height: 26px; font-size: 13px; }
  .rows.q .c-next { grid-area: next; flex-direction: row; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
  .rows.q .c-next:not(:has(> .id-chips, > .small)) { display: none; } /* nothing more to say: no empty row */
  .rows.q .c-next > .id-chips { display: inline-flex; flex-wrap: nowrap; gap: 6px; }
  .rows.q .q-vs { display: block; grid-area: vs; min-width: 0; font-size: 14px; line-height: 1.35; }
  .rows.q .q-vs > .cell, .rows.q .c-svc > span { display: inline; }
  .rows.q .c-veh .make { font-weight: 600; font-size: 15px; margin-right: 6px; }
  .rows.q .c-svc::before { content: "\00a0· "; }
  .rows.q > .r .c-cust { display: block; grid-area: cust; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 13px; color: var(--muted); }
  .rows.q > .r .c-cust > span { display: inline; font-size: 13px; }
  .rows.q .c-cust > .cu-n { color: var(--ink); }
  .rows.q .c-cust > .cu-n + .cu-e::before { content: "\00a0· "; }
  .rows.q .c-op { grid-area: op; justify-self: end; align-self: center; min-width: 0; text-align: right; font-size: 13px; }
  .rows.q .c-time { grid-area: time; flex-direction: row; flex-wrap: wrap; gap: 0 12px; padding-top: 4px; border-top: 1px dashed var(--line-2); font-size: 13px; }
  .rows.q .c-time > span { display: inline; white-space: nowrap; }
  .rows.q .m-only { display: inline; }
}

/* 0.9.42: staff header. Computer: as before (icons hidden). Phone view (< 1024 px), 0.12.3: one row
   on top (brand, email · 2FA, Log out) that scrolls away with the page; Queue, Notifications and
   Admin in a tab bar at the bottom, under the thumb, like the customer side. The role is the Admin
   tab, the version is in the footer. */
body.staff .nav .ic { display: none; }
@media (max-width: 1023px) {
  body.staff { padding-bottom: calc(68px + env(safe-area-inset-bottom)); }
  body.staff .top-in { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; grid-template-areas: "brand who out"; align-items: center; gap: 0 10px; min-height: 0; padding: 6px 8px 6px 12px; }
  body.staff .brand-box { grid-area: brand; margin: 0; }
  body.staff .brand { margin: 0; gap: 8px; font-size: 16px; min-width: 0; white-space: nowrap; }
  body.staff .brand .sub { display: none; }
  body.staff .brand-mark { width: 26px; height: 26px; font-size: 12px; }
  body.staff .who { grid-area: who; display: flex; justify-content: flex-end; min-width: 0; font-size: 12px; color: #a9cde3; white-space: nowrap; }
  body.staff .who-mail { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
  body.staff .n-out { grid-area: out; align-self: center; }
  body.staff .n-main { position: fixed; left: 0; right: 0; bottom: 0; z-index: 40; flex-wrap: nowrap; gap: 4px; margin: 0; padding: 6px 8px calc(6px + env(safe-area-inset-bottom)); background: var(--top); border-top: 1px solid #1f4a68; box-shadow: 0 -4px 16px rgba(0, 0, 0, .18); }
  body.staff .n-main a { flex: 1 1 0; flex-direction: column; justify-content: center; gap: 2px; min-height: 52px; padding: 2px 4px; font-size: 13px; font-weight: 600; line-height: 1.1; text-align: center; }
  body.staff .n-out button { flex-direction: row; justify-content: center; gap: 6px; min-height: 40px; padding: 2px 8px; font-size: 13px; line-height: 1.1; }
  body.staff .chat-box { bottom: calc(68px + env(safe-area-inset-bottom)); } /* the reply box stays above the tab bar */
  body.staff .nav .ic { display: block; width: 20px; height: 20px; }
  /* Work queue top: smaller title and counter tiles. */
  body.staff .page-head h1 { font-size: 24px; }
  body.staff .stats { gap: 8px; margin-bottom: 12px; }
  body.staff .stat { padding: 8px 12px; }
  body.staff .stat b { font-size: 20px; }
  body.staff .stats > .stat:last-child:nth-child(odd) { grid-column: 1 / -1; }
}

/* ---------- 0.9.42 mobile audit (staff side, phone view < 1024 px) ---------- */
/* Admin: 22 sections behind one row naming the current one; open = two columns. Wide: sidebar as before. */
.sidebox > summary { list-style: none; }
.sidebox > summary::-webkit-details-marker { display: none; }
.side-sum { width: 100%; justify-content: flex-start; margin-bottom: 8px; }
.side-sum::after { content: '▾'; margin-left: auto; padding-left: 8px; }
.sidebox[open] .side-sum::after { content: '▴'; }
@media (min-width: 1024px) { .sidebox > summary { display: none; } }
@media (max-width: 1023px) {
  .sidebox .side { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; margin-bottom: 12px; }
  .sidebox .side a { min-height: 44px; padding: 6px 10px; font-size: 14px; line-height: 1.2; }
}
@media (max-width: 379px) { .side-n { display: none; } }
/* Queue filters: search on its own row, the four lists two by two. */
@media (max-width: 1023px) {
  .filters { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 10px; }
  .filters > .f-q { grid-column: 1 / -1; }
  .filters .lbl { font-size: 13px; }
}
/* Operator ticket: next step and work first, then the conversation, the files, the money, the rest. */
@media (max-width: 1023px) {
  .grid-op > aside { display: contents; }
  .grid-op > #conversation { order: 1; }
  .grid-op .o-veh { order: 2; }
  .grid-op #files { order: 3; }
  .grid-op #payment { order: 4; }
  .grid-op .o-svc { order: 5; }
  .grid-op .o-cust { order: 6; }
}
@media (max-width: 1023px) {
  .op-ctl { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 10px; width: 100%; }
  .op-ctl > div:first-of-type { grid-column: 1 / -1; }
  .op-ctl select { width: 100%; }
  .op-ctl > .btn { grid-column: 1 / -1; }
  body.staff .page-head .chip { font-size: 13px; min-height: 26px; }
  a.tap { display: inline-flex; align-items: center; min-height: 40px; }
  /* Catalog rows: same order on every row — name + kind, prices, status + Edit. */
  /* 0.12.0: name (code under it) and Edit on the first row; prices and the chips on one line under them */
  .sortable li:has(.c-name) { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; grid-template-areas: "grip name edit" "grip facts facts"; gap: 6px 10px; padding: 10px 12px; }
  .sortable li .grip { grid-area: grip; align-self: start; }
  .sortable li .c-name { grid-area: name; }
  .sortable li .c-name .mono { display: block; }
  .sortable li .c-facts { grid-area: facts; display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; }
  .sortable li .c-chips { display: inline-flex; flex-wrap: wrap; gap: 6px; } /* the chips wrap together, never one alone */
  .sortable li .c-tags { display: contents; }
  .sortable li .c-edit { grid-area: edit; align-self: start; }
  /* Statistics tables: column titles wrap instead of pushing a column off screen. */
  table.plain th.num { white-space: normal; }
  table.plain td .ellip { max-width: 130px; }
  /* Cleanup: the button on the title row, the counts and notes under both (0.12.0: they wrapped in 165 px). */
  .cleanlist li { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 4px 12px; }
  .cleanlist .grow1 { display: contents; }
  .cleanlist .grow1 > :first-child { grid-column: 1; grid-row: 1; }
  .cleanlist li > form { grid-column: 2; grid-row: 1; }
  .cleanlist .grow1 > div { grid-column: 1 / -1; }
}
.c-tags { display: inline-flex; flex-wrap: wrap; gap: 8px; align-items: center; }
@media (max-width: 1023px) {
  /* "Message with the file": the hint goes under the title instead of squeezing it. */
  #files .more > summary { flex-wrap: wrap; }
  #files .more > summary > .muted { flex: 1 0 100%; padding-left: 28px; }
}

/* ---------- 0.9.43: opening hours in the customer bar (option C) ---------- */
body.cust .brand-box { display: flex; flex-direction: column; justify-content: center; flex: 1 1 auto; min-width: 0; margin-right: auto; }
body.cust .brand-box .brand { margin-right: 0; }
.hb-s { display: flex; align-items: center; gap: 6px; padding-left: 40px; margin-top: -2px; font-size: 12px; font-weight: 600; color: #fff; line-height: 1.25; }
.hb-s .dot, .hb-d .dot { flex: 0 0 auto; width: 8px; height: 8px; border-radius: 2px; background: #3ddc84; }
.hb-s.is-closed .dot, .hb-d.is-closed .dot { background: #f2a516; }
.hb-d { display: none; }
.hb-strip { background: #0e3550; color: #a9cde3; border-top: 1px solid rgba(255, 255, 255, .08); font-size: 13px; }
.hb-strip .hb-in { max-width: 1392px; margin: 0 auto; padding: 6px 16px; display: flex; flex-direction: column; gap: 2px; }
.hb-strip.is-slow .hb-r { color: #ffd58a; font-weight: 600; }
.hb-strip.has-note { background: #3a2a05; color: #ffd58a; }
.hb-note { font-weight: 600; color: #ffd58a; }
@media (max-width: 1023px) { body.cust .top-in { flex-wrap: nowrap; } }
/* 0.10.0: the full opening hours in the bar from 1200 px (below, the bar broke onto two rows:
   language, bell and "Log out" alone on the second); on a narrower computer the short status. */
/* 0.27.0: one layout on every computer width: logo, then the menu right after it; language, bell and
   "Log out" at the right (with the opening hours before them from 1200 px). Before, the menu sat at the
   right edge under 1200 px and beside the logo above it, and moved when the hours block was missing.
   The bar is as wide as the page column (1200 px), so the logo lines up with the page title. */
@media (min-width: 1024px) {
  body.cust .top-in { max-width: 1200px; }
  body.cust .brand-box { flex: 0 0 auto; margin-right: 0; }
  body.cust .top-in .nav.tabs-m { order: 1; margin-left: 10px; }
  body.cust .top-in .hb-d { order: 2; }
  body.cust .top-in .tools { order: 3; margin-left: auto; }
}
@media (min-width: 1200px) {
  body.cust .top-in:has(.hb-d) .tools { margin-left: 18px; } /* the hours block (shown from here) takes the free room */
  .hb-s { display: none; }
  .hb-d { display: flex; align-items: center; gap: 10px; margin: 0 0 0 auto; padding-left: 18px; border-left: 1px solid rgba(255, 255, 255, .15); font-size: 13px; color: #d5e6f1; line-height: 1.3; min-width: 0; }
  .hb-d .hb-lines { display: flex; flex-direction: column; min-width: 0; }
  .hb-d strong { color: #fff; font-size: 14px; }
  .hb-d .hb-sched { color: #a9cde3; }
  .hb-d.is-slow .hb-resp { color: #ffd58a; font-weight: 600; }
}
/* 0.26.0: no opening-hours line under the bar at any width (the bar says open/closed and the next opening);
   the strip stays only for the "send your file now" note while closed. */
.hb-strip:not(.has-note) { display: none; }
.hb-strip .hb-facts { display: none; }

/* 0.9.44: first request sent — check the inbox and the spam folder, trust the sender. */
/* 0.26.0: one compact block (title, text and link run on) */

/* 0.9.45: Admin > Email template */
.et-previews { display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; }
@media (min-width: 1024px) { .et-previews { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.et-frame { display: block; width: 100%; height: 560px; border: 1px solid var(--line); border-radius: 8px; background: #edf2f6; }
.et-code { font-size: 13px; line-height: 1.45; min-height: 360px; white-space: pre; overflow-wrap: normal; overflow-x: auto; }
.et-sample { width: auto; }
/* 0.9.45: Admin > SMTP, inbox-not-spam checks */
.dlv { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.dlv li { padding: 10px 12px; border: 1px solid var(--line); border-radius: 8px; }
.dlv-d { overflow-wrap: anywhere; color: var(--muted); }

/* 0.9.47: notifications ON / OFF at a glance */
.push-state { display: inline-flex; align-self: flex-start; align-items: center; gap: 8px; padding: 6px 12px; border-radius: 8px; font-family: var(--font-c); font-size: 16px; font-weight: 700; letter-spacing: .02em; background: var(--line-2); color: var(--ink); }
.push-state .ps-dot { width: 12px; height: 12px; border-radius: 3px; background: #8aa4b5; }
.push-state[data-st="on"] { background: var(--ok-bg); color: var(--ok); }
.push-state[data-st="on"] .ps-dot { background: #1f9d55; }
.push-state[data-st="off"], .push-state[data-st="blocked"] { background: var(--err-bg); color: var(--err); }
.push-state[data-st="off"] .ps-dot, .push-state[data-st="blocked"] .ps-dot { background: #d93025; }
.push-state[data-st="setup"] { background: var(--warn-bg); color: var(--warn); }
.push-state[data-st="setup"] .ps-dot { background: #f2a516; }
.push-card[data-st="on"] { border-left: 4px solid #1f9d55; }
.push-card[data-st="off"], .push-card[data-st="blocked"] { border-left: 4px solid #d93025; }
.push-card[data-st="setup"] { border-left: 4px solid #f2a516; }
/* staff top bar: dot on the Notifications tab */
body.staff a[href="/op/notifications"] { position: relative; }
body.staff a[href="/op/notifications"][data-push]::after { content: ''; position: absolute; top: 6px; right: 6px; width: 10px; height: 10px; border-radius: 50%; border: 2px solid var(--top); background: #8aa4b5; }
body.staff a[href="/op/notifications"][data-push="on"]::after { background: #22c55e; }
/* 0.9.75: off = grey, blocked or set-up needed = amber; red is kept for the unseen counter only. */
body.staff a[href="/op/notifications"][data-push="off"]::after { background: #8aa4b5; }
body.staff a[href="/op/notifications"][data-push="blocked"]::after, body.staff a[href="/op/notifications"][data-push="setup"]::after { background: #f59e0b; }
@media (max-width: 1023px) { body.staff .n-main a[href="/op/notifications"][data-push]::after { top: 4px; right: calc(50% - 20px); } }
/* customers: the bell dot a little bigger */
.bell-dot { width: 12px; height: 12px; }

/* ---------- 0.9.50: layout pass — no words broken in odd places, controls lined up ---------- */
/* Label / value lists: the label never wraps, takes only its own width; the value wraps (long
   emails break anywhere). Side by side at every width; stacked only in a really narrow card. */
.kv, .kv.wide, .kv.pair { grid-template-columns: max-content minmax(0, 1fr); gap: 8px 16px; align-items: baseline; }
.kv dt { white-space: nowrap; font-size: 14px; margin-top: 0; }
.kv dd { overflow-wrap: anywhere; }
@container (max-width: 440px) {
  .kv, .kv.wide, .kv.pair { grid-template-columns: max-content minmax(0, 1fr); gap: 8px 14px; }
  .kv dt { font-size: 13px; margin-top: 0; }
}
/* 0.9.97: no more label above its value under 250 px ("Billing" / "Italy" wasted a line each): the
   label stays beside the value at every width (the rule above), on one line. */
/* A row of labelled fields with a button: everything sits on the same bottom line. */
.row:has(> div > .lbl), .row:has(> label.lbl) { align-items: flex-end; }
.op-ctl { align-items: flex-end; }
.op-ctl select { min-width: 150px; }
.op-ctl > .btn { min-height: 44px; }
/* Chips never break inside ("Payment · Pending" on one line); the row wraps between chips. */
.chip { white-space: nowrap; }
.cell > .chip, .rows .chip { white-space: nowrap; }

/* 0.19.2: lines are filled to the end, everywhere. "balance"/"pretty" (0.9.50) split text into even
   lines and left up to a third of each line empty — the owner wants the space used first. */
body, p, li, dd, label, h1, h2, h3, .btn, .small, .help, .muted, .lead, .lbl { text-wrap: wrap; }
.chip.chip-wrap { white-space: normal; max-width: 100%; }
time, .nowrap, td.num { white-space: nowrap; }
/* 0.9.51: extra payments */
.extra-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "head head" "why act"; align-items: center; gap: 4px 10px; padding: 0 0 10px; border-bottom: 1px solid var(--line-2); }
.extra-row .er-head { grid-area: head; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
.extra-row .er-why { grid-area: why; }
.extra-row .er-act { grid-area: act; align-self: start; } /* 0.12.0: Cancel beside the reason: the chip never wraps alone */
.extra-box { display: flex; flex-direction: column; gap: 8px; margin: 0; padding: 14px 16px; background: var(--warn-bg); border: 1px solid #f0c27a; border-left: 4px solid var(--turn); border-radius: 8px; }
.extra-box.paid { background: var(--ok-bg); border-color: #b9e2c8; border-left-color: #1f9d55; }
.extra-box .eb-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px; }
.extra-box .eb-txt { display: flex; flex-direction: column; gap: 4px; flex: 1 1 240px; min-width: 0; }
.extra-box .eb-title { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 0 12px; font-family: var(--font-c); font-size: 18px; font-weight: 700; }
.extra-boxes { margin: 0 0 14px; gap: 10px; }
.xhero { padding-bottom: 18px; }
.pre-wrap { white-space: pre-wrap; }
/* 0.9.53: payment brand marks */
.pl-row { display: inline-flex; gap: 6px; }
.pl { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 26px; border: 1px solid var(--line); border-radius: 6px; background: #fff; flex: 0 0 auto; }
.pl svg { width: 22px; height: 22px; display: block; }
.pl-visa svg, .pl-americanexpress svg { width: 26px; }
.wel-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px; }
/* 0.9.53: staff top bar — unseen notifications counter on the Notifications tab */
.nbadge { display: inline-flex; align-items: center; justify-content: center; min-width: 20px; height: 20px; margin-left: 6px; padding: 0 5px; border-radius: 6px; background: #c81e1e; color: #fff; font: 700 12px/1 var(--font-c); box-shadow: 0 0 0 2px var(--top); } /* 0.9.75: 5.6:1 */
.nbadge.hide { display: none; }
@media (max-width: 1023px) { body.staff .n-main a[href="/op/notifications"] .nbadge { position: absolute; top: 2px; right: calc(50% + 10px); margin: 0; } }
/* staff: notifications list */
.nlist { list-style: none; margin: 0; padding: 0; }
.nlist li { border-top: 1px solid var(--line-2); }
.nlist li:first-child { border-top: 0; }
.nlist a { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 2px 12px; padding: 10px 8px; color: inherit; text-decoration: none; border-radius: 6px; }
.nlist a:hover { background: var(--line-2); }
.nlist .nt { font-weight: 600; }
.nlist .nb { grid-column: 1 / -1; color: var(--muted); font-size: 14px; overflow-wrap: anywhere; }
@media (min-width: 1024px) { /* 0.12.0: title, text and time on one row */
  .nlist a { grid-template-columns: max-content minmax(0, 1fr) auto; align-items: baseline; }
  .nlist .nt { grid-column: 1; grid-row: 1; }
  .nlist .nb { grid-column: 2; grid-row: 1; }
  .nlist a > .small { grid-column: 3; grid-row: 1; }
}
.nlist .new .nt::before { content: ''; display: inline-block; width: 8px; height: 8px; margin-right: 8px; border-radius: 2px; background: #c81e1e; vertical-align: 1px; }
@media (min-width: 1024px) { body.staff a[href="/op/notifications"][data-push] { padding-right: 24px; } }
/* 0.9.54: coupon on the payment page */
.coupon-box { margin: 10px 0 4px; }
.coupon-form { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; }
.coupon-form .in { text-transform: uppercase; letter-spacing: .04em; }
.ok-text { color: var(--ok); }
/* Admin › Coupons */
.cp-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 14px 16px; align-items: start; }
.cp-disc { display: grid; grid-template-columns: minmax(0, 1fr) 110px; gap: 8px; }
.cp-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 16px; padding: 12px 0; border-top: 1px solid var(--line-2); }
.cp-row:first-of-type { border-top: 0; }
.cp-main { display: flex; flex-direction: column; gap: 4px; min-width: 0; flex: 1 1 320px; }
.cp-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; }
.cp-act { display: flex; gap: 8px; }
.lt .lt-full { grid-column: 1 / -1; }
.lt > .field-error, fieldset.lt.two.lang > div > .field-error { grid-column: 1 / -1; } /* 0.9.76: a field message spans the row */
/* 0.9.58: Users and roles */
.staff-act { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.staff-role { display: flex; align-items: center; gap: 8px; }
.staff-role select { width: auto; min-width: 130px; }
.search-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; }
.lt.two > .btn { align-self: end; }
/* 0.9.59: operator ticket, Customer card */
.cust-who { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; }
.cust-links { display: flex; flex-wrap: wrap; gap: 4px 16px; margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--line-2); }
/* 0.9.62: pull down to refresh (Home Screen app) */
.ptr { position: fixed; left: 50%; top: calc(env(safe-area-inset-top, 0px) - 44px); z-index: 2000; width: 40px; height: 40px; border-radius: 50%; background: #fff; border: 1px solid var(--line); box-shadow: 0 4px 14px rgba(0, 0, 0, .18); display: flex; align-items: center; justify-content: center; transform: translate(-50%, 0); opacity: 0; pointer-events: none; transition: opacity .15s; }
.ptr.pulling, .ptr.spin, .ptr.blocked { opacity: 1; }
.ptr.pulling { transition: none; }
.ptr-ic { width: 18px; height: 18px; border: 3px solid #9fb1c1; border-top-color: transparent; border-radius: 50%; }
.ptr.ready .ptr-ic, .ptr.spin .ptr-ic { border-color: var(--brand, #005a87); border-top-color: transparent; }
.ptr.spin { transform: translate(-50%, 80px); }
.ptr.spin .ptr-ic { animation: ptr-spin .7s linear infinite; }
.ptr.blocked { transform: translate(-50%, 80px); animation: ptr-no .45s; }
.ptr.blocked .ptr-ic { border-color: var(--err, #c0392b); border-top-color: transparent; }
@keyframes ptr-spin { to { transform: rotate(360deg); } }
@keyframes ptr-no { 0%, 100% { margin-left: 0; } 25% { margin-left: -8px; } 75% { margin-left: 8px; } }
@media (prefers-reduced-motion: reduce) { .ptr.spin .ptr-ic { animation-duration: 2s; } .ptr.blocked { animation: none; } }
/* 0.9.63: staff Notifications page */
@media (min-width: 1024px) { .notif-grid { grid-template-columns: minmax(0, 1fr) 380px; } }
.push-plain { gap: 10px; }
.check-list { display: flex; flex-direction: column; gap: 6px; }
.check-list .check { min-height: 40px; align-items: center; }
.dev-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 0; border-top: 1px solid var(--line-2); }
.dev-row:first-of-type { border-top: 0; }
.dev-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.ios-steps { margin: 8px 0; padding-left: 20px; }
.ios-steps li { margin: 2px 0; }
/* 0.9.63: operator ticket, wide screens — the messages scroll inside a box as tall as the window
   allows (set by app.js), so the reply box is always in view under them. */

/* 0.9.65: conversation card — messages + reply box together, the box always under the messages */
.chat { display: flex; flex-direction: column; padding: 0; overflow: hidden; }
.chat-h { margin: 0; padding: 12px 16px; border-bottom: 1px solid var(--line-2); }
.chat > .msgs { padding: 14px 16px; background: #f6f9fb; }
.chat-box { display: flex; flex-direction: column; gap: 8px; padding: 10px 16px 12px; background: #fff; border-top: 2px solid var(--brand); }
.chat-box .files:empty { display: none; }
.chat-row { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 8px; align-items: end; }
.chat-row textarea.in { min-height: 44px; height: 44px; max-height: 168px; resize: none; overflow-y: auto; line-height: 1.4; padding-top: 10px; padding-bottom: 10px; }
.chat-attach { width: 44px; min-width: 44px; padding: 0; justify-content: center; }
.chat-attach .ic { width: 20px; height: 20px; margin: 0; }
.chat-send { min-height: 44px; }
.chat-hint { margin: 0; font-size: 12px; line-height: 1.4; color: var(--muted); }
.chat > .chat-hint { padding: 0 16px 12px; background: #fff; } /* 0.12.0: staff, under the reply box (not in its sticky part) */
.chat-box:has(+ .chat-hint) { padding-bottom: 6px; }
/* 0.9.79: one fact per line (limit, files), never a sentence broken across two lines with one word left over. */
.chat-hint .ch-limit, .chat-hint .ch-files { display: block; }
.chat-hint.problem-hint { font-size: 13px; color: var(--ink); }
.chat-wait { padding: 12px 16px; border-top: 1px solid var(--line-2); background: var(--info-bg); color: var(--info); font-size: 14px; }
.chat-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; }
.quick-d > summary { cursor: pointer; font-size: 14px; font-weight: 600; color: var(--brand); min-height: 32px; display: inline-flex; align-items: center; gap: 4px; }
.quick-d[open] { flex: 1 1 100%; }
.quick-d .quick { margin-top: 6px; }
.composer.chat-box.is-note { background: var(--note-bg); }
.composer.is-note .quick-d { opacity: .45; pointer-events: none; }
/* Phone: the reply box sticks to the bottom of the screen while the conversation is in view. */
@media (max-width: 1023px) {
  .chat { overflow: visible; }
  .chat-box { position: sticky; bottom: 0; z-index: 5; box-shadow: 0 -6px 14px rgba(11, 42, 63, .08); border-radius: 0 0 8px 8px; }
}
@media (max-width: 1023px) {
  body.cust .chat-box { bottom: calc(68px + env(safe-area-inset-bottom)); transition: bottom .22s ease; }
  body.cust.tabs-away .chat-box { bottom: 0; padding-bottom: calc(12px + env(safe-area-inset-bottom)); }
  .chat-hint .ch-files { display: none; }
}
/* 0.9.77: in the phone view (< 1024 px) the conversation is narrow: the send button
   shows only its icon (it has its label for screen readers), the message box keeps the room. */
@media (max-width: 1023px) { .chat-send .cs-l { display: none; } }
/* 0.13.0: AI assistant. "AI draft" stacked above Send, same width; Undo / Show in … on the tool row;
   Translate on the title row of a customer message; translations in a grey box (max 120 px in the composer). */
.ai-btn { min-height: 40px; padding: 0 10px; gap: 6px; white-space: nowrap; }
.ai-btn .ic { width: 18px; height: 18px; margin: 0; flex: none; }
.ai-btn[aria-busy="true"] { opacity: .6; cursor: progress; }
.ai-btn[aria-busy="true"] .ic { animation: ai-spin 1s linear infinite; }
@keyframes ai-spin { to { transform: rotate(360deg); } }
@media (max-width: 1023px) { .ai-btn .ai-l2 { display: none; } }
.ai-a { background: none; border: 0; padding: 0; font: inherit; font-size: 14px; font-weight: 600; color: var(--brand); min-height: 40px; display: inline-flex; align-items: center; white-space: nowrap; cursor: pointer; }
.ai-a:hover { text-decoration: underline; }
.ai-a[hidden] { display: none; }
.msg .meta .ai-t { margin: -10px 0 -10px auto; font-size: 13px; } /* 40 px to tap, the title row keeps its height */
.ai-tr { margin: 6px 0 0; padding: 8px 10px; border-left: 3px solid var(--line); background: var(--bg); border-radius: 4px; font-size: 14px; line-height: 1.4; color: var(--ink); white-space: pre-wrap; overflow-wrap: anywhere; }
.ai-tr b { display: block; font-size: 12px; color: var(--muted); font-weight: 600; margin-bottom: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ai-tr[hidden], .ai-msg[hidden] { display: none; }
.chat-box .ai-tr { margin: 0; max-height: 120px; overflow: auto; }
.ai-msg { margin: 0; font-size: 13px; color: var(--err); }
.msg .ai-msg { margin-top: 6px; }
.chat > .chat-hint.one { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: none; }
.ai-models { columns: 2 220px; margin: 0; padding-left: 18px; }
.changelog h2 { font-size: 20px; margin: 22px 0 4px; } .changelog h2:first-child { margin-top: 0; }
.changelog code { white-space: normal; } /* long file names break only at _ / . (wbr), never mid-word */
.changelog h3 { font-size: 16px; margin: 14px 0 4px; } .changelog p, .changelog li { font-size: 15px; line-height: 1.5; }
/* 0.9.66: desktop ticket pages work like an app — the page itself never scrolls: the header and the
   ticket summary stay put, the conversation scrolls inside its card (reply box always under it) and
   each side column scrolls on its own when it is longer than the window. */
@media (min-width: 1024px) {
  body.app { height: 100vh; height: 100dvh; overflow: hidden; display: flex; flex-direction: column; }
  body.app > .foot { display: none; }
  body.app > main { flex: 1 1 auto; min-height: 0; width: 100%; display: flex; flex-direction: column; padding-bottom: 14px; }
  body.app > main > * { flex-shrink: 0; } /* summary, notices: full height, never squeezed */
  body.app > main > .grid-main,
  body.app > main > .grid-op { flex: 1 1 auto; min-height: 0; grid-template-rows: minmax(0, 1fr); align-items: stretch; }
  body.app .grid-main > aside,
  body.app .grid-op > aside { min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 0 4px 2px 0; }
  body.app .chat > .msgs { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
  body.app .conv-col { min-height: 0; display: flex; flex-direction: column; overflow-y: auto; }
  body.app .conv-col > .chat { flex: 1 1 auto; min-height: 320px; }
  body.app .grid-op > .chat { min-height: 0; }
  body.app main aside > *, body.app .conv-col > :not(.chat) { flex-shrink: 0; }
  /* Hidden inputs (.sr file pickers, tab radios) are placed against their scroll column, never the
     page: otherwise focusing one far down a column grows and scrolls the page (0.9.75). */
  body.app .conv-col, body.app main aside, body.app .chat { position: relative; }
}

/* 0.9.68: app version in the staff bar, desktop only (phones: footer). */
.brand .ver { display: none; }
@media (min-width: 1024px) {
  body.staff .brand .ver { display: inline-block; margin-left: 2px; padding: 2px 7px; border: 1px solid rgba(255, 255, 255, .28); border-radius: 6px; font-family: var(--font); font-size: 12px; font-weight: 500; line-height: 1.4; color: rgba(255, 255, 255, .75); letter-spacing: .02em; }
}

/* 0.9.70: operator ticket chips. Computer: a row of chips next to the number. Phone view
   (< 1024 px): one single row under the number, never wrapped (more chips than fit: swipe
   sideways). No payment chip (0.9.75): the banner and the Payment card say it. */
.op-chips { display: contents; }
@media (max-width: 1023px) {
  .page-head > div:has(.op-chips) { min-width: 0; width: 100%; }
  .page-head .row:has(> .op-chips) { display: block; }
  .op-chips { display: flex; flex-wrap: nowrap; gap: 5px; margin-top: 8px; overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
  .op-chips::-webkit-scrollbar { display: none; }
  .op-chips.more { -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 28px), transparent); mask-image: linear-gradient(90deg, #000 calc(100% - 28px), transparent); }
  body.staff .page-head .op-chips .chip { flex: 0 0 auto; font-size: 12px; min-height: 26px; padding: 2px 7px; }
}
/* 0.9.69: staff bar on a computer (from 1024 px): one line always; when tight the email shortens (full in the tooltip). */
@media (min-width: 1024px) {
  body.staff .top-in { flex-wrap: nowrap; }
  body.staff .top-in > * { flex-shrink: 0; }
  body.staff .who { flex: 0 1 auto; display: flex; min-width: 0; white-space: nowrap; }
  body.staff .who-mail { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
}

/* 0.9.72: request sent while we are closed: courtesy note on its own line under the next step. */
.hero-next > .closed-note { flex: 1 1 100%; order: 9; padding-top: 10px; border-top: 1px dashed currentColor; border-top-color: color-mix(in srgb, currentColor 30%, transparent); }

/* 0.9.75: a whole row opens its page: the main link covers the row, the other controls stay above it. */
.rowhost { position: relative; }
.rowhost a.rowlink::after { content: ''; position: absolute; inset: 0; z-index: 0; }
.rowhost :is(form, .btn, select, label, a:not(.rowlink)) { position: relative; z-index: 1; }
tr.rowhost:hover, .ver.rowhost:hover { background: #f0f7fc; }
table.plain tr.rowhost > td { vertical-align: middle; }
tr.rowhost a.tap { min-width: 40px; }
/* 0.9.75: tables as cards (Admin › Users, Audit log): one card per row, each value with its label
   ("Country · IT"), no sideways scrolling inside the card. 0.11.2: up to 1199 px, phone view and
   smaller computers alike: below 1200 px the full tables did not fit and hid their last columns
   (Disable, the IP); from 1200 px the tables. */
@media (max-width: 1199px) {
  table.plain.cards, table.plain.cards tbody { display: block; }
  table.plain.cards thead { display: none; }
  table.plain.cards tr { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px 12px; padding: 12px 0; border-bottom: 1px solid var(--line-2); align-items: center; }
  /* 0.12.0: audit: When on the first row, Who (0.12.9: IP under it), then Action and Object on one line, details */
  table.plain.cards.audit tr { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 14px; }
  table.plain.cards.audit td.full { flex: 1 0 100%; }
  table.plain.cards tr:last-child { border-bottom: 0; }
  table.plain.cards td { display: block; min-width: 0; padding: 0; border: 0; }
  table.plain.cards td.full { grid-column: 1 / -1; }
  table.plain.cards td.o-late { order: 1; }
  table.plain.cards td:empty { display: none; }
  table.plain.cards td[data-label]::before { content: attr(data-label) " · "; color: var(--muted); }
  table.plain.cards td.num { text-align: left; } /* 0.12.0: "Files · 4" reads as a pair, not pushed right */
  table.plain.cards .rowlink { display: inline-flex; align-items: center; min-height: 40px; font-weight: 600; overflow-wrap: anywhere; }
  table.plain.cards .prewrap { max-width: none; }
  table.plain.cards .row.nowrap-row { flex-wrap: wrap; }
  /* 0.11.1: customers: the short facts on one line (each one whole, wrapping as needed), Tickets
     last, Edit and Disable after them at the right (on their own line if there is no room). */
  table.plain.cards.cust-list tr { display: flex; flex-wrap: wrap; gap: 0 14px; }
  table.plain.cards.cust-list td.full { flex: 1 0 100%; }
  table.plain.cards.cust-list td:not(.full) { white-space: nowrap; }
  /* 0.34.2: the two-line cells (profile, orders, dates) each on their own line of the card, wrapping as needed */
  table.plain.cards.cust-list td.c-two { flex: 1 0 100%; white-space: normal; line-height: 1.4; }
  table.plain.cards.cust-list td.c-two br { display: none; }
  table.plain.cards.cust-list td.c-two .small { margin-left: 4px; }
  table.plain.cards.cust-list td.c-two .small::before { content: "· "; }
  table.plain.cards.cust-list .c-act { order: 2; margin-left: auto; }
}
/* 0.9.75: the logo link is a 44 px tap target; negative margins keep the bars exactly as tall as before. */
.brand { min-height: 44px; margin-top: -7px; margin-bottom: -7px; }
@media (max-width: 1023px) { body.staff .brand { margin-top: -9px; margin-bottom: -9px; } }
/* 0.9.75: file names on one line, cut with "…" (full name in the tooltip); a message carrying files
   takes the full width of the conversation, so the name has room. */
.file .nm .mono.fname { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; overflow-wrap: normal; }
/* 0.13.7: staff: the name the customer gets, on the details line; breaks after "_" (<wbr>), never mid-word. */
.file .nm .mono.sent-as { font-size: 13px; overflow-wrap: break-word; }
/* 0.13.7: the size alone goes beside the name (the name cut with "…" first), never on a line of its own. */
.file .nm-top { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.file .nm-top .fname { flex: 0 1 auto; min-width: 0; }
.file .nm-top .fsize { flex: none; white-space: nowrap; }
.msg:has(.file) { max-width: 100%; align-self: stretch; }
/* 0.9.75: phones — no button alone on its own line. Email template: the sample above, then
   Save | Preview side by side. Language switcher (invoice preview): equal columns, 4 + 3. */
@media (max-width: 1023px) {
  .et-act { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .et-act > select { grid-column: 1 / -1; order: -1; width: 100%; }
  .et-act > .btn:nth-of-type(3) { grid-column: 1 / -1; }
  .seg.seg-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .seg.seg-grid a { justify-content: center; padding: 0 4px; }
}
/* 0.9.75: Admin › Request form — section title with its key in a chip; each field's facts with their
   qualifiers ("Type · text", "Required · no", "Shown · always") in one group. Phones: name and Edit
   on the first line, the facts on the full width below. */
.sec-head { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: start; gap: 6px 12px; margin-bottom: 10px; } /* 0.9.77: the key chip stays beside the title (it wrapped alone) */
.fmeta { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px 14px; }
.fmeta > span { min-width: 0; overflow-wrap: anywhere; }
@media (max-width: 1023px) {
  .sortable li:has(.fmeta) { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; grid-template-areas: "grip name edit" "grip meta meta"; gap: 6px 10px; }
  .sortable li:has(.fmeta) > .grip { grid-area: grip; align-self: start; }
  .sortable li:has(.fmeta) > .grow { grid-area: name; }
  .sortable li:has(.fmeta) > .fmeta { grid-area: meta; display: flex; flex-wrap: wrap; gap: 2px 14px; } /* 0.13.7: flowing, no item alone on a line when it fits */
  .sortable li:has(.fmeta) > .btn { grid-area: edit; align-self: start; }
}

/* 0.9.77: request form on a computer: the form column next to the summary can be narrow, two
   choices per row broke words in the middle ("Transporte/r", "Дизельн/ые"). Two per row only when
   the card has room for them; otherwise one per row (phones keep their own layout above). */
@media (min-width: 1024px) {
  #request-form section.card { container: rfcard / inline-size; }
  @container rfcard (max-width: 459px) {
    .opts.two, .opts.mains, [data-extras] .opts, .f3 { grid-template-columns: minmax(0, 1fr); }
  }
}

/* 0.9.77: operator next step: sentence (label first) | buttons together. Phones: buttons under it. */
.opstep { display: grid; grid-template-columns: minmax(0, 1fr) auto; }
.opstep .op-acts { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 8px; }
.opstep .op-acts:empty { display: none; }
.opstep .grow1 { text-wrap: wrap; }
.opstep .grow1 .chip { margin-right: 6px; vertical-align: 1px; }
@media (max-width: 1023px) {
  .opstep { grid-template-columns: minmax(0, 1fr); }
  .opstep .op-acts { justify-content: flex-start; }
  .opstep:has(> .op-acts > :only-child) { grid-template-columns: minmax(0, 1fr) auto; } /* 0.12.0: one button never alone on a line */
}
/* 0.9.77: catalog rows on tablet and desktop: fixed columns, the prices wrap inside theirs, so a long
   price list never pushes "Edit" alone onto a second line. */
@media (min-width: 1024px) {
  .sortable li:has(.c-name) { display: grid; grid-template-columns: auto minmax(180px, 1.2fr) auto minmax(140px, 1.6fr) auto auto; align-items: center; }
  .sortable li .c-tags { flex-wrap: wrap; justify-content: flex-end; } /* 0.9.78: tags wrap, prices never run under them */
  .sortable li .c-facts, .sortable li .c-chips { display: contents; } /* 0.12.0: the computer keeps its columns */
  .sortable li .c-kind { order: 1; } .sortable li .c-price { order: 2; } .sortable li .c-tags { order: 3; } .sortable li .c-edit { order: 4; }
  .sortable li .c-name .mono { display: block; } /* the code under the name: the name never splits */
  .sortable li .c-price { text-align: right; }
  .sortable li .c-price .pp { white-space: nowrap; }
}
/* 0.9.77: a link inside a sentence (e.g. "Request a revision" in the next step) gets a 40 px touch
   area without moving the text. */
.wrap-any { overflow-wrap: break-word; min-width: 0; } /* 0.9.78: a long name wraps, never cut. 0.12.9: between words ("anywhere" let a column shrink and split names and emails) */
.proof-more > summary { cursor: pointer; font-weight: 600; color: var(--brand); } /* 0.9.78 */
fieldset.bare { border: 0; margin: 0; padding: 0; min-width: 0; } /* 0.9.78: groups fields (account page) without a box */
fieldset.bare[disabled] .in { background: #f1f4f7; color: #4a5a68; }
/* 0.9.78: tip tiles. 5 = 3 + 2, 4 = 2 + 2, 3 in a row; all in one row when the card has room. */
#request-form section.card:has(.tiles.tips) { container: tipcard / inline-size; }
.tiles.tips.n5 { grid-template-columns: repeat(6, minmax(0, 1fr)); }
.tiles.tips.n5 > :nth-child(-n+3) { grid-column: span 2; }
.tiles.tips.n5 > :nth-child(n+4) { grid-column: span 3; }
.tiles.tips.n4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.tiles.tips.n3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@container tipcard (min-width: 560px) {
  .tiles.tips.n5, .tiles.tips.n4 { grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); grid-auto-flow: column; }
  .tiles.tips.n5 > * { grid-column: auto; }
}
.tile strong, .tile .price, .speed-tile strong { white-space: nowrap; } /* "+ 14,99 €" never split */
.tnum { white-space: nowrap; } /* "TB-10010" on one line */
.hero-next p a { padding-block: 11px; margin-block: -11px; }
.tile-price { white-space: nowrap; }
#files .more > summary > .muted { white-space: nowrap; } /* 0.9.78: the hint never splits */
.cn-act { display: flex; align-items: center; gap: 8px; margin-left: auto; } /* 0.9.78 */
/* 0.9.78: queue view tiles: 6 tiles never leave one alone on a row (3 + 3, or 6 in a row). */
@media (min-width: 1024px) {
  nav.stats:has(> :nth-child(6):last-child) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (min-width: 1200px) {
  nav.stats:has(> :nth-child(6):last-child) { grid-template-columns: repeat(6, minmax(0, 1fr)); }
}

/* 0.9.80: payment page — billing as a real section (title, "optional", what is saved), order summary
   with labelled vehicle and ECU. */
.bill-card { padding: 0; }
details.bill-box > summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: 12px; padding: 14px 16px; min-height: 56px; }
.bill-box > summary::-webkit-details-marker { display: none; }
.bill-box .bb-txt { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.bill-box .bb-t { font-family: var(--font-c); font-size: 20px; font-weight: 600; line-height: 1.2; color: var(--ink); }
.bill-box .bb-opt { font-family: var(--font); font-size: 14px; font-weight: 500; color: var(--muted); }
.bill-box .bb-s { font-size: 14px; color: var(--brand); line-height: 1.35; overflow-wrap: anywhere; }
.bill-box[open] .bb-s { display: none; }
.bill-box .bb-chev { flex: 0 0 auto; width: 10px; height: 10px; border-right: 2px solid var(--brand); border-bottom: 2px solid var(--brand); transform: rotate(45deg); margin: -4px 6px 0 0; transition: transform .15s ease; }
.bill-box[open] .bb-chev { transform: rotate(-135deg); margin-top: 4px; }
.bill-box .bb-form { padding: 0 16px 16px; }
.bill-box .bb-help { text-wrap: wrap; }
/* 0.9.98: the ECU right after the make on the same line when it fits (as in the ticket header since
   0.9.93), otherwise whole on the next line. */
.ord-veh { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 12px; margin: -4px 0 8px; font-size: 15px; }
.ord-veh .ord-ecu { color: var(--ink); }
/* 0.9.82: payment methods — one header row per method (name left, brand marks right), same font */
.pm-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px; }
.pm-title { font-family: var(--font-c); font-size: 17px; font-weight: 600; }

/* 0.9.83: extras in the phone view: one per row (two columns broke names mid-word). 0.26.0: the row is one
   line at every width (name, words cut with "…", price), so no phone-only layout any more. */
@media (max-width: 1023px) {
  [data-extras] .opts { grid-template-columns: minmax(0, 1fr); gap: 8px; }
}

/* =====================================================================================
   0.9.88 — UI pass from the 0.9.82 audit (customer and staff)
   ===================================================================================== */
/* Payment page: on a phone the order folds into one row "Your order · total ▾" (every line one tap
   away), so the pay buttons are on the first screen; on a computer it is always open, a plain title. */
.ord-fold > summary { list-style: none; display: flex; align-items: center; gap: 12px; min-height: 40px; }
.ord-fold > summary::-webkit-details-marker { display: none; }
.ord-fold > summary h2 { flex: 1 1 auto; }
.ord-fold .ord-tot { font-family: var(--font-c); font-size: 20px; font-variant-numeric: tabular-nums; }
.ord-fold .bb-chev { flex: 0 0 auto; width: 10px; height: 10px; border-right: 2px solid var(--brand); border-bottom: 2px solid var(--brand); transform: rotate(45deg); margin: -4px 6px 0 0; transition: transform .15s ease; }
.ord-fold[open] .bb-chev { transform: rotate(-135deg); margin-top: 4px; }
.ord-fold[open] > summary { margin-bottom: 12px; }
.ord-fold[open] .ord-tot { display: none; } /* open: the total is the last row, as always */
.ord-fold:not([open]) + .sumrow.total { display: none; }
@media (min-width: 1024px) {
  .ord-fold > summary { pointer-events: none; cursor: default; }
  .ord-fold .bb-chev { display: none; }
}
@media (max-width: 1023px) { .ord-fold > summary { cursor: pointer; } }
.ord-why { display: block; margin-top: 2px; }
/* Request form: the picked file keeps "Remove" on its row (it sat alone under the name). */
[data-files-list] > .file { flex-wrap: nowrap; }
[data-files-list] > .file > .nm { flex: 1 1 0; }
[data-files-list] > .file > .btn { flex: none; }
[data-files-list] > .file .nm .mono { overflow-wrap: break-word; } /* breaks after "_" "." "-" first (app.js) */
/* Custom work: the price goes under the name when they do not fit side by side ("Lavoro su / misura / (preventivo)"). */
.opt.main.custom .head { flex-wrap: wrap; }
/* IMMO "my ECU is not listed": no price column, its line already says it is on quote. */
.immo-row.immo-other > .price { display: none; }
/* "Continue" comes after the summary in the page: on a computer it stays in the left column, under the form. */
@media (min-width: 1024px) {
  #request-form > aside.sum-side { grid-column: 2; grid-row: 1 / span 2; }
  #request-form > .endbar { grid-column: 1; grid-row: 2; }
}
/* On a phone the summary just above shows the total: the end card keeps only the button. */
#request-form > .endbar .endbar-total { display: none; } /* 0.12.0: computer too: the summary beside it shows the total */
#request-form > .endbar .endbar-row { justify-content: center; } /* 0.20.2: the button alone, centred (no total, no subtitle) */
/* Ticket header: a long service name may wrap (its last two words stay together). */
.hero .svc .it.long { white-space: normal; }
.hero .svc { text-wrap: wrap; } /* 0.12.0: "pretty" moved a whole name down and left "Services:" alone */
/* Account: the address breaks after the "@" only. */
.acc-mail { overflow-wrap: break-word; }
/* 0.12.0: account. First and last name side by side at every width (short fields, like postcode and
   city); on a computer the personal data and the billing data in two columns, Save under both. */
.names { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.acc-grid { display: grid; gap: 12px; }
.acc-b > h2 { margin-top: 8px; }
.hero-next .eb-why { display: block; margin-top: 4px; } /* 0.12.0: the extra payment's reason under the banner sentence */
/* 0.12.0: "label · value" pairs in a grid (Admin › Retention): 4 per row on a computer, 2 on a phone */
.pairs { list-style: none; padding: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px 16px; }
@media (min-width: 1024px) { .pairs { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.cr-row { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--line-2); } /* 0.12.0: Platform Credit, a row of Amounts */
@media (min-width: 1024px) {
  main.acc { max-width: 920px; }
  .acc-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px 32px; align-items: start; }
  .acc-b > h2 { margin-top: 0; }
  .acc-grid > .acc-save { grid-column: 1 / -1; }
}
/* Payment proof: "Attach files" and "Send proof" side by side when they fit, otherwise each on its
   own line, full width (0.12.0: by what fits, not by the screen; DE/RU wrapped on narrow phones). */
#proof .nowrap-row { flex-wrap: wrap; }
#proof .nowrap-row > .btn { flex: 1 1 auto; justify-content: center; white-space: nowrap; }
/* Staff queue filters on a computer: every choice readable. */
@media (min-width: 1024px) {
  .filters { grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); }
  .filters > .f-q { grid-column: span 2; }
}
/* Staff ticket: the customer's address whole, on two lines if needed. */
.cust-mail .tap { max-width: 100%; }
/* Admin › Invoices as cards: what each value is. */
.rows.inv .m-only { display: none; }
@media (max-width: 1023px) {
  .rows.inv .m-only { display: inline; }
  /* 0.12.0: invoice cards in three rows: number and total, bill to, date and ticket (were five) */
  .rows.inv > a.r { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "num tot" "bill bill" "date tick"; gap: 4px 12px; }
  .rows.inv > a.r > :nth-child(1) { grid-area: num; }
  .rows.inv > a.r > :nth-child(2) { grid-area: date; }
  .rows.inv > a.r > :nth-child(3) { grid-area: bill; }
  .rows.inv > a.r > :nth-child(4) { grid-area: tick; justify-self: end; }
  .rows.inv > a.r > :nth-child(5) { grid-area: tot; justify-self: end; }
}

/* =====================================================================================
   0.9.89
   ===================================================================================== */
/* Staff ticket header: number, chips and the controls on one row — each label beside its
   select instead of above it (the labels took a second line for nothing). 0.12.0: on every
   computer (was from 1200 px): when the row is full the controls go to a second row as a whole. */
@media (min-width: 1024px) {
  body.staff .page-head { align-items: center; }
  body.staff .page-head .op-ctl { align-items: center; gap: 8px 14px; }
  body.staff .page-head .op-ctl > div { display: flex; align-items: center; gap: 8px; }
  body.staff .page-head .op-ctl .lbl { margin: 0; white-space: nowrap; }
  body.staff .page-head .op-ctl select, body.staff .page-head .op-ctl > .btn { min-height: 44px; }
}

/* =====================================================================================
   0.9.90 — fixes from the 0.9.89 audit
   ===================================================================================== */
/* Staff ticket header on a computer: number, chips and controls on one row when they fit; when
   they do not (narrow window, many chips), the controls go to a second row as a whole — never a
   chip alone on a line, never a cut menu (0.9.92: 0.9.90 wrapped single chips and cut "Waiting
   for customer"). 0.12.0: short labels at every width ("Lang", "Operator", "Work"; the full ones in
   the tooltip), so the step chip fits on the row. */
@media (min-width: 1024px) {
  body.staff .page-head .op-ctl #ws { min-width: 215px; }
}
/* Staff queue filters at 1024–1199 px: the six on one row ("Created" was alone on the second). */
@media (min-width: 1024px) and (max-width: 1199px) {
  .filters { grid-template-columns: repeat(6, minmax(0, 1fr)); }
}
/* Admin › Invoices cards: the labels in the text font (they took the number's monospace). */
.rows.inv .m-only { font-family: var(--font); }

/* Admin › Invoices and System periods: six choices in two even rows (3 + 3), never one alone. */
@media (max-width: 1023px) {
  .seg.seg-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .seg.seg-3 a { justify-content: center; text-align: center; }
}

/* Tickets list on a phone: the status chip never wraps inside itself (ru "Смета на / согласовании");
   when it does not fit beside the number it goes under it. */
.c-id .cstatus { white-space: nowrap; }
.rows.ct .c-id { flex-wrap: wrap; }
/* Admin menu on a phone (two columns): an odd last item takes the whole row instead of sitting alone. */
.sidebox .side > a:last-child:nth-child(odd) { grid-column: 1 / -1; }
/* 0.9.94: ticket header without a banner at the bottom (file ready): the same space under the
   content as above it (the services line or the steps touched the bottom edge). */
.hero:not(:has(> .hero-next)) { padding-bottom: 18px; }
@media (min-width: 1024px) { .hero:not(:has(> .hero-next)) { padding-bottom: 22px; } }
/* 0.9.94: staff ticket, side cards more compact. Services: the price list on one line ("…" when
   cut, whole in the tooltip), tighter rows. Customer: one card with the order IP and place (the
   Consents card is gone), tighter rows. */
.o-svc .o-head { margin-bottom: 4px; }
.o-svc .o-pl { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* 0.13.7: on the title row */
.o-svc .sumrow { padding: 5px 0; }
.o-svc .sumrow.total { padding-top: 8px; }
.o-cust .kv { gap: 4px 12px; }
.o-cust .cust-links { margin-top: 6px; padding-top: 4px; }
/* 0.9.95: staff ticket, work column more compact. Extra payment and Platform Credit are sections
   of the Payment card (no card order of their own any more); a title row carries its side note or
   its action, and the action goes under the title when they do not fit (phone). */
.o-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 2px 10px; }
.o-head > h2, .o-head > h3, .o-head > p, .o-head > details > summary { white-space: nowrap; }
.o-head > details.more { border-top: 0; padding-top: 0; }
.o-head > details[open] { flex: 1 0 100%; }
.o-sub > .o-head { align-items: center; }
.o-sub { gap: 6px; padding-top: 8px; margin-top: 4px; border-top: 1px solid var(--line-2); }
.o-sub .extra-row:last-of-type { padding-bottom: 0; border-bottom: 0; }
#files, #payment > .fold-b { gap: 8px; }
#files > form[data-dropzone] { gap: 6px; }
#files .drop { padding: 9px 12px; gap: 2px; }
#files form .check { min-height: 40px; padding: 0; align-items: center; }
#files .ver { padding: 10px 12px; gap: 4px; }
/* A version: name and Download on one row, the details on the row under them. */
.file.f-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 0 12px; min-height: 0; padding: 0; border: 0; background: none; }
.file.f-row .nm { display: contents; }
.file.f-row .fname { grid-column: 1; grid-row: 1; }
.file.f-row .nm > .small { grid-column: 1 / -1; grid-row: 2; }
.file.f-row .act { grid-column: 2; grid-row: 1; min-height: 36px; }
/* Upload buttons side by side when both fit, each on its own full row otherwise. */
.o-up { display: flex; flex-wrap: wrap; gap: 8px; }
.o-up > .btn { flex: 1 1 auto; padding-left: 10px; padding-right: 10px; font-size: 15px; white-space: nowrap; }
/* Invoice and GA4 on one row. */
.o-docs { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0 12px; }
.o-docs > p { white-space: nowrap; }
a.file.f-row:hover { background: none; }
/* 0.12.0: every file card (customer and staff, phone and computer): name and Download on one row, the
   details under them (Download wrapped alone under the details on phones; 0.9.96 did it for staff only). */
a.file:not(.f-row) { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 0 12px; }
a.file:not(.f-row) .nm { display: contents; }
a.file:not(.f-row) .nm > :first-child { grid-column: 1; grid-row: 1; min-width: 0; }
a.file:not(.f-row) .nm > .small { grid-column: 1 / -1; grid-row: 2; }
a.file:not(.f-row) .act { grid-column: 2; grid-row: 1; }
a.file.f-row:hover .act { text-decoration: underline; }
/* 0.12.0: a long admin help text (data-clamp) in three lines with "Show all" (app.js). */
[data-clamp].clamp { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; line-clamp: 3; overflow: hidden; }
.clamp-more { align-self: flex-start; min-height: 40px; font-size: 14px; font-weight: 600; }
/* 0.9.96: a long System message in the conversation, same (0.12.0: customers too, translated labels). */
.msg.sys > .body.clamp { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; line-clamp: 3; overflow: hidden; }
.msg.sys > .sys-more { align-self: flex-start; min-height: 40px; margin-top: -8px; font-size: 14px; font-weight: 600; }
/* 0.9.96: staff on a phone, the ticket header (file cards: see "every file card" above). */
@media (max-width: 1023px) {
  /* 0.12.0: each label beside its select, Save on the Work row */
  body.staff .op-ctl { grid-template-columns: max-content minmax(0, 1fr) auto; align-items: center; }
  body.staff .op-ctl > div { display: contents; }
  body.staff .op-ctl .lbl { margin: 0; }
  body.staff .op-ctl #as { grid-column: 2 / -1; }
  body.staff .op-ctl > .btn { grid-column: auto; padding: 0 16px; }
}
/* 0.10.0: customer pages, phone view up to 1023 px: on a tablet held
   upright the same single column, centred, not stretched across the screen. */
@media (max-width: 1023px) { body.cust main.wrap { max-width: 680px; margin-left: auto; margin-right: auto; } }
/* 0.10.0: staff queue on a phone, less height per ticket and nothing removed. "Search and filters"
   on the title row (full row once open); counters three per row; in each ticket the payment beside
   the number, customer and operator on one row, "Submitted" and "Updated" on one line. */
@media (max-width: 1023px) {
  .q-page { display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 12px; align-items: center; }
  .q-page > * { grid-column: 1 / -1; }
  .q-page > .page-head { grid-column: 1; }
  .q-page > .filterbox:not([open]) { grid-column: 2; grid-row: 1; margin: 0 0 12px; }
  .q-page > .filterbox:not([open]) > summary { margin: 0; }
  .q-page .stats { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-bottom: 12px; }
  /* 0.12.3: each number beside its caption (the tips: caption and detail in one text under it) */
  .q-page .stats { gap: 6px; margin-bottom: 10px; }
  .q-page .stats .stat { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; align-content: center; column-gap: 6px; padding: 6px 8px; min-height: 48px; }
  .q-page .stats .stat b { font-size: 18px; }
  .q-page .stats .st-t { display: block; min-width: 0; }
  .q-page .stats .st-t > .small { display: block; font-size: 12px; line-height: 1.2; }
  .q-page .stats .st-tips { grid-template-columns: minmax(0, 1fr); }
  .q-page .stats .st-tips b { font-size: 15px; }
  .q-page .stats .st-tips .st-t { font-size: 12px; line-height: 1.2; }
  .q-page .stats .st-tips .st-t > .small { display: inline; }
  .q-page .stats .st-tips .st-t > .sr + .small::before { content: "\00a0· "; }
}
.rows.q .id-chips { display: contents; }
.stat .st-t { display: contents; } /* computer: caption and detail under the number, as before */
/* 0.10.1: staff ticket, side cards that fold (Vehicle and ECU, Customer, Payment; Services and
   Processed files never). Closed: the title and a one-line summary under it (wraps, never cut). */
.fold > summary.fold-h { position: relative; display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 10px; min-height: 40px; padding-left: 32px; cursor: pointer; list-style: none; }
.fold > summary.fold-h::-webkit-details-marker { display: none; }
.fold > summary.fold-h::before { content: '▸'; position: absolute; left: 0; top: 9px; display: inline-flex; width: 22px; height: 22px; align-items: center; justify-content: center; border: 1px solid var(--line); border-radius: 6px; font-size: 13px; color: var(--brand); flex: 0 0 auto; }
.fold[open] > summary.fold-h::before { content: '▾'; }
.fold > summary.fold-h > h2 { margin: 0; }
/* 0.13.7: the summary on the title row when it fits, else whole on the next line under the title */
.fold > summary .fold-s { flex: 0 1 auto; min-width: 0; font-size: 14px; color: var(--muted); overflow-wrap: anywhere; }
.fold[open] > summary .fold-s { display: none; }
.fold[open] > summary.fold-h { margin-bottom: 8px; }
.fold:not([open]) { padding-top: 10px; padding-bottom: 10px; }

/* 0.12.0: staff ticket on a computer, no step bar over the columns (82 px back to them). The step is
   the first chip of the header, a link to its card (the sentence in the tooltip); "Take it" beside the
   Operator menu; "No reply needed" on the Quick replies row of the reply box. Phone: the bar as before. */
a.chip.next { text-decoration: none; }
a.chip.next:hover, a.chip.next:focus-visible { text-decoration: underline; }
.op-take { min-height: 44px; padding: 0 14px; white-space: nowrap; }
.chat-tools > .no-reply { margin-left: auto; }

/* 0.12.2: queue table, the customer's email under the company or name, always on one line: what
   fits, then "…" (whole in the tooltip). Cards (0.12.3): name · email on one line. */
.rows.q .c-cust .cu-e { display: block; min-width: 0; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* 0.12.9: "Edit" on the ECU row (no extra row while closed); open: the form under the value,
   label beside its box, Save across the whole row */
.ecu-fix { display: inline; }
.ecu-fix > summary { display: inline-flex; align-items: center; min-height: 40px; margin: -10px 0; padding: 0 6px; color: var(--brand); font-weight: 600; cursor: pointer; list-style: none; }
.ecu-fix > summary::-webkit-details-marker { display: none; }
.ecu-fix[open] > summary { color: var(--muted); }
.ecu-fix[open] > .ecu-f { margin-top: 8px; }
.ecu-f { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 8px 12px; align-items: center; }
.ecu-f .lbl { margin: 0; }
.ecu-f .btn { grid-column: 1 / -1; }
/* 0.12.9: layout audit on every page 1024-1920 px: no word split, no single word alone on a line */
.audit-d { text-wrap: wrap; }
.small code, li > code { white-space: nowrap; }
/* 0.12.9: queue card on a phone: "Work · In progress" never wraps; a long operator label is cut
   with "…" (whole label in the tooltip) instead of pushing the work status onto two lines */
@media (max-width: 1279px) {
  .rows.q .c-next > .small { white-space: nowrap; }
  .rows.q .c-op { max-width: min(46vw, 220px); }
  .rows.q .c-op > span { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
}
/* 0.12.9: emails never go to a new line (owner rule, as the customer's email in the queue): the operator
   in the queue and the customers on System on one line, what fits then "…", whole in the tooltip */
.one-line { display: block; min-width: 0; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.one-line * { white-space: nowrap !important; } /* a label inside ("Operator · ") never opens a line break either */
.rows.q .c-op, .rcust { min-width: 0; }
/* 0.12.10: audit details, each short "key: value" pair on one line on a computer; on a phone (360 px) a pair may wrap */
@media (min-width: 1024px) { .audit-d .pair { white-space: nowrap; } }
/* 0.13.3: login, under the code box: "Send a new code" · "Use another email" (link look, 40 px to tap) */
.lg-alt { display: flex; flex-wrap: wrap; gap: 0 20px; }
.lg-alt form { margin: 0; }
.lg-link { background: none; border: 0; padding: 0; font: inherit; font-size: 15px; font-weight: 600; color: var(--brand); min-height: 40px; display: inline-flex; align-items: center; cursor: pointer; text-decoration: none; }
.lg-link:hover { text-decoration: underline; }
/* 0.13.7: a secret's state ("Saved …" / "Not set") on its label row. */
.lbl-row { gap: 4px 10px; margin-bottom: 6px; }
.lbl-row > .lbl { margin: 0; }
/* 0.13.7: tables in the changelog (before/after heights). */
.changelog .tbl-wrap { overflow-x: auto; margin: 6px 0 10px; }
.changelog table.cl-t { border-collapse: collapse; font-size: 14px; }
.changelog table.cl-t th, .changelog table.cl-t td { padding: 4px 10px; border-bottom: 1px solid var(--line-2); text-align: left; }
.changelog table.cl-t td:not(:first-child), .changelog table.cl-t th:not(:first-child) { white-space: nowrap; text-align: right; }
/* 0.13.8: why the page reloaded by itself (or "Refresh" when it could not); the button beside the text. */
.live-note > span { flex: 1 1 0; min-width: 0; }
.live-note > .btn { flex: none; min-height: 40px; }
/* 0.13.9: the checksum in its own card after the service: text, then the option (computer: side by side). */
.ck-card .ck-help { margin: 0 0 10px; }
.ck-card .ck-help strong { color: var(--ink); }
.ck-card [data-extras] .opts { grid-template-columns: minmax(0, 1fr); }
@media (min-width: 1024px) {
  .ck-card { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 24px; align-items: center; }
  .ck-card > h2 { grid-column: 1 / -1; }
  .ck-card .ck-help { margin: 0; }
}
/* 0.13.10: under the quick replies, when the inserted reply puts the ticket on "Waiting for customer". */
.then-wait { margin: 0 0 6px; padding: 6px 10px; border: 1px solid #f0d3a6; border-radius: 8px; background: var(--warn-bg); color: var(--warn); font-size: 13px; }
/* 0.13.10: links in messages (staff and customers) are clickable; a long address breaks, never overflows. */
.msg .body a { overflow-wrap: anywhere; }
/* ---------- 0.13.12: notifications impossible to miss ---------- */
/* Customer bell: red with the count while staff replies or files are unread; the list on top of the panel. */
.bell-n { position: absolute; top: -7px; right: -7px; min-width: 22px; height: 22px; padding: 0 6px; border-radius: 6px; background: #c81e1e; color: #fff; font: 700 13px/22px var(--font-c); text-align: center; box-shadow: 0 0 0 2px var(--top); }
.bell-n.hide, .tbadge.hide { display: none; }
.bell.has-unread .bell-btn { background: #c81e1e; border-color: #c81e1e; color: #fff; }
.bell.has-unread .bell-dot { display: none; }
.nt-list { display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px; padding-bottom: 12px; border-bottom: 1px solid var(--line); }
.nt-list.hide { display: none; }
.nt-list:last-child { margin-bottom: 0; padding-bottom: 0; border-bottom: 0; }
.nt-h { font-weight: 700; font-size: 15px; color: var(--ink); }
.nt-items { display: flex; flex-direction: column; gap: 6px; }
.nt-item { display: flex; flex-direction: column; gap: 2px; min-height: 44px; padding: 8px 10px; border-radius: 8px; background: #eaf3f9; border-left: 4px solid var(--brand); color: var(--ink); text-decoration: none; }
.nt-item:hover { background: #dcebf5; }
.nt-item b { font-size: 15px; }
.nt-item span { font-size: 13px; color: var(--muted); }
/* "My tickets" tab: the count of unread tickets. */
.tbadge { display: inline-flex; align-items: center; justify-content: center; min-width: 20px; height: 20px; margin-left: 6px; padding: 0 5px; border-radius: 6px; background: #c81e1e; color: #fff; font: 700 12px/1 var(--font-c); }
@media (max-width: 1023px) { body.cust .nav.tabs-m a { position: relative; } body.cust .nav.tabs-m a .tbadge { position: absolute; top: 3px; right: calc(50% - 26px); margin: 0; } }
/* Ticket page: what came since the last visit. */
.nt-banner { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; padding: 14px 16px; border-radius: 8px; background: var(--brand); color: #fff; box-shadow: 0 6px 18px rgba(0, 90, 135, .35); }
.nt-banner.file { background: #1d7a46; box-shadow: 0 6px 18px rgba(29, 122, 70, .35); }
.nt-banner .nt-ic .ic { width: 28px; height: 28px; }
.nt-banner .nt-tx { flex: 1 1 0; min-width: 0; font-weight: 700; font-size: 16px; line-height: 1.3; }
.nt-banner .nt-tx small { display: block; margin-top: 2px; font-weight: 400; font-size: 14px; opacity: .92; }
.nt-banner .btn { flex: none; min-height: 40px; background: #fff; border-color: #fff; color: var(--brand); white-space: nowrap; }
.nt-banner.file .btn { color: #1d7a46; }
.msg.is-new { outline: 3px solid var(--brand); outline-offset: 2px; }
.nt-chip { display: inline-flex; align-items: center; margin-left: 8px; padding: 1px 8px; border-radius: 6px; background: var(--brand); color: #fff; font: 700 13px/20px var(--font-c); vertical-align: 1px; }
/* Customer list and staff queue: rows with something new. */
.rows .r.is-new { box-shadow: inset 5px 0 0 var(--brand); background: #eef6fb; }
.q-dot { display: inline-block; width: 10px; height: 10px; margin-right: 6px; border-radius: 50%; background: var(--brand); vertical-align: 1px; }
/* Staff: the alert when a notification arrives (stays until Open or Later), the counter that pulses. */
.nt-toast { position: fixed; z-index: 90; top: 72px; right: 16px; width: min(380px, calc(100vw - 32px)); display: flex; gap: 10px; align-items: flex-start; padding: 12px 14px; border: 1px solid var(--line); border-left: 6px solid var(--brand); border-radius: 8px; background: #fff; color: var(--ink); box-shadow: 0 10px 30px rgba(19, 33, 46, .28); }
.nt-toast .ic { flex: none; width: 22px; height: 22px; color: var(--brand); }
.nt-toast .nt-tx { flex: 1 1 0; min-width: 0; font-size: 14px; overflow-wrap: anywhere; }
.nt-toast .nt-tx b { display: block; font-size: 15px; }
.nt-toast .nt-act { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.nt-toast .nt-act .btn { min-height: 40px; }
.nbadge.pulse { animation: nt-pulse 1.2s ease-out 3; }
@keyframes nt-pulse { 0% { box-shadow: 0 0 0 2px var(--top), 0 0 0 0 rgba(200, 30, 30, .7); } 100% { box-shadow: 0 0 0 2px var(--top), 0 0 0 12px rgba(200, 30, 30, 0); } }
@media (prefers-reduced-motion: reduce) { .nbadge.pulse { animation: none; } }
.nt-staff { display: flex; align-items: center; gap: 12px; margin: 0 0 10px; padding: 10px 14px; border-radius: 8px; background: var(--brand); color: #fff; }
.nt-staff span { flex: 1 1 0; min-width: 0; font-weight: 700; }
.nt-staff .btn { flex: none; min-height: 40px; background: #fff; border-color: #fff; color: var(--brand); }
@media (max-width: 1023px) { .nt-toast { top: 64px; right: 16px; } }

/* 0.13.16: admin "Delete ticket" (computer only): the title in the error colour */
.o-del h2 { color: var(--err); }
.o-del .in { max-width: 420px; } /* 0.13.19: the confirmation field as wide as an email, not the whole page */

/* 0.13.27: Admin › Payments › Webhooks card */
.stack.tight { gap: 6px; }
.brk { word-break: break-all; }
.hint[title]:not([data-nv]) { text-decoration: underline dotted; cursor: help; } /* 0.19.3: only where there is a tooltip to show (the form's extra descriptions share the class and had none) */
.inv-logo { max-width: 190px; max-height: 56px; display: block; }

/* 0.14.0: referral card in Account: label, value and copy button on one line at every width */
.ref-row { display: flex; align-items: center; gap: 12px; min-width: 0; }
.ref-row .lbl { flex: none; }
.ref-row .ref-code { flex: 1 1 0; min-width: 0; font-size: 20px; font-weight: 600; letter-spacing: .04em; }
.ref-row .brk { flex: 1 1 0; min-width: 0; overflow-wrap: anywhere; }
.ref-row .copy { margin-left: 0; }
@media (max-width: 339px) { /* 0.15.2: 320 px phones: the code a little smaller, label and value still on one line */
  .ref-row { gap: 8px; }
  .ref-row .ref-code { font-size: 17px; letter-spacing: .02em; }
  .ref-row .brk { font-size: 12px; }
}

/* ---------- 0.16.0: staff work queue, "console" look (one line per ticket on a computer, flat statuses) ---------- */
.q-page .page-head h1 { font-size: 22px; }
.q-page .w-only { display: none; }
.q-page .tipw { font: 12px var(--mono); color: var(--go); }
/* counters: one strip (computer) / three compact tiles per row (phone) */
@media (min-width: 1024px) {
  .q-page nav.stats, .q-page nav.stats:has(> :nth-child(6):last-child) { display: flex; grid-template-columns: none; gap: 0; background: #fff; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; margin-bottom: 12px; }
  .q-page .stat { flex-direction: row; align-items: baseline; gap: 8px; padding: 9px 16px; min-height: 0; border: 0; border-right: 1px solid var(--line-2); border-radius: 0; }
  .q-page .stat b { font-size: 20px; line-height: 1; }
  .q-page .stat .st-t { display: flex; gap: 6px; white-space: nowrap; }
  .q-page .stat.on { box-shadow: inset 0 -2px 0 var(--brand); background: #eaf3f9; }
  .q-page .stat.on .st-t .muted { color: var(--brand); }
  .q-page .stat.st-tips { margin-left: auto; border-right: 0; }
  .q-page .stat.st-tips b { font-size: 16px; color: var(--go); }
}
@media (max-width: 1023px) {
  .q-page nav.stats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; }
  body.staff .q-page nav.stats > .stat:last-child:nth-child(odd) { grid-column: auto; }
  .q-page .stat { flex-direction: row; align-items: baseline; gap: 2px 8px; padding: 6px 10px; min-height: 40px; }
  .q-page .stat b { font-size: 18px; line-height: 1; flex: none; }
  .q-page .stat .st-t { display: flex; flex-wrap: wrap; column-gap: 6px; font-size: 13px; line-height: 1.2; min-width: 0; }
  .q-page .stat .st-t .small { font-size: 13px; white-space: nowrap; }
  .q-page .stat.st-tips b { color: var(--go); }
}
/* flat statuses everywhere in the queue: a dot and words, no filled boxes */
.rows.q .chip.next { background: none; padding: 0; min-height: 0; border-radius: 0; font-size: 13px; font-weight: 500; color: var(--ink); white-space: nowrap; }
.rows.q .chip.next::before { content: ""; display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 7px; vertical-align: 1px; background: #9fb0bd; }
.rows.q .chip.next.info::before { background: var(--brand); }
.rows.q .chip.next.warn::before { background: #e0920a; }
.rows.q .chip.next.ok::before { background: var(--go); }
.rows.q .chip.next.new::before { background: var(--brand); box-shadow: 0 0 0 3px #cfe3f0; }
.rows.q .chip.next.err::before { background: var(--err); }
.rows.q .c-pay .chip { background: none; padding: 0; min-height: 0; border-radius: 0; font-size: 13px; font-weight: 600; color: var(--muted); white-space: nowrap; }
.rows.q .c-pay .chip.ok { color: var(--go); }
.rows.q .c-pay .chip.warn { color: #b86a00; }
.rows.q .c-pay .chip.err { color: var(--err); }
.rows.q .id-chips .chip { background: none; padding: 0; min-height: 0; border-radius: 0; font-size: 12px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; }
.rows.q .id-chips .chip.err { color: var(--err); }
.rows.q .id-chips .chip.warn { color: #b86a00; }
.rows.q .c-time .abs { color: var(--ink); font-weight: 500; }
/* the table (1280 px and up): 44 px rows, every cell on one line */
@media (min-width: 1280px) {
  .q-page .w-only { display: inline; }
  .rows.q > .rh { padding: 8px 12px; font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); background: #f7f9fb; }
  .rows.q > .rh > span:last-child { text-align: right; }
  .rows.q > .r { padding: 0 12px; min-height: 44px; }
  .rows.q .cell { gap: 1px; }
  .rows.q .c-id { flex-direction: row; align-items: center; gap: 8px; white-space: nowrap; }
  .rows.q .c-id .mono { font-size: 13px; font-weight: 600; }
  .rows.q .c-cust .cu-n { font-size: 13px; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .rows.q .c-cust .cu-e { font-size: 12px; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .rows.q .c-veh { flex-direction: row; align-items: baseline; gap: 6px; white-space: nowrap; overflow: hidden; }
  .rows.q .c-veh .make { font-weight: 600; font-size: 13px; flex: none; }
  .rows.q .c-veh .mono { font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
  .rows.q .c-svc > span { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 13px; }
  .rows.q .c-svc > span > span { display: inline; }
  .rows.q .c-next { flex-direction: row; align-items: baseline; gap: 6px; white-space: nowrap; overflow: hidden; }
  .rows.q .c-next > .small { font-size: 12px; }
  .rows.q .c-pay { flex-direction: row; align-items: baseline; gap: 8px; white-space: nowrap; }
  .rows.q .c-op { font-size: 13px; }
  .rows.q .c-time { align-items: flex-end; text-align: right; font-size: 12px; color: var(--muted); gap: 0; line-height: 1.25; }
  .rows.q .c-time .lbl-sub, .rows.q .c-time .ago { display: none; }
  .rows.q .c-time > span > .muted { font-size: 12px; }
  .rows.q > .rh, .rows.q > .r { grid-template-columns: 28px 130px minmax(150px, 1.1fr) minmax(150px, 1.1fr) minmax(160px, 1.6fr) 170px 120px 100px 110px; gap: 12px; } /* 0.16.4: 1,174 px at least: fits from 1280 */
}
/* the cards (phone and up to 1279 px): same language, tighter */
@media (max-width: 1279px) {
  .rows.q .c-time .abs { display: none; }
  .rows.q .c-id .chip, .rows.q .c-next .chip, .rows.q .c-pay .chip { min-height: 0; font-size: 13px; }
  .rows.q .c-id .mono { font-size: 16px; }
  .rows.q .c-next > .id-chips { gap: 10px; }
}

/* ---------- 0.16.1: phone queue as mockup M3 (Open / All on top, the rest inside the filters; cards in four lines) ---------- */
.q-page .m-counts { display: none; }
@media (min-width: 1024px) { .q-page .stat.m-stat { display: none; } }
@media (max-width: 1023px) {
  .q-page .stat.w-stat { display: none; }
  .q-page nav.stats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .q-page .stat { min-height: 44px; padding: 8px 12px; }
  .q-page .stat b { font-size: 20px; }
  .q-page .stat .st-t .small { font-size: 14px; }
  .q-page .m-counts { display: flex; flex-wrap: wrap; gap: 0 14px; margin-bottom: 6px; font-size: 13px; }
  .q-page .m-counts a { color: var(--muted); text-decoration: none; white-space: nowrap; padding: 10px 0; }
  .q-page .m-counts a b { color: var(--ink); font-weight: 700; margin-right: 4px; }
  .q-page .m-counts a.tips b { color: var(--go); }
}
@media (max-width: 1279px) {
  .rows.q > .r { grid-template-columns: auto minmax(0, 1fr) auto; grid-template-areas: "id id sel" "vs vs vs" "pay cust op" "time time time"; gap: 3px 6px; padding: 10px 12px; }
  .rows.q .c-id { grid-area: id; display: flex; flex-direction: row; align-items: baseline; gap: 8px; min-width: 0; }
  .rows.q .c-id .id-chips { display: contents; }
  .rows.q .c-id > .chip.next { display: inline-flex; margin-left: auto; white-space: nowrap; }
  .rows.q .c-next { display: none; }
  .rows.q .q-vs { grid-area: vs; }
  .rows.q .c-pay { grid-area: pay; display: flex; flex-direction: row; align-items: baseline; gap: 6px; justify-self: start; align-self: baseline; white-space: nowrap; font-size: 13px; }
  .rows.q > .r .c-cust { grid-area: cust; display: flex; flex-direction: row; align-items: baseline; align-self: baseline; gap: 0; font-size: 13px; white-space: nowrap; overflow: hidden; min-width: 0; }
  .rows.q > .r .c-cust > span { display: inline; overflow: hidden; text-overflow: ellipsis; }
  .rows.q > .r .c-cust::before { content: "·"; color: var(--muted); margin-right: 6px; flex: none; }
  .rows.q .c-op { grid-area: op; display: flex; flex-direction: row; align-items: baseline; align-self: baseline; justify-self: end; font-size: 13px; color: var(--muted); white-space: nowrap; }
  .rows.q .c-op::before { content: "·"; margin-right: 6px; }
  .rows.q .c-time { grid-area: time; justify-content: space-between; margin-top: 2px; }
}

/* ---------- 0.16.2: staff ticket page, same language as the queue ---------- */
.op-meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 0; font-size: 14px; color: var(--muted); min-width: 0; }
.op-meta > *:not(:last-child)::after { content: "·"; margin: 0 8px; color: #b7c3cc; }
.op-meta .flag { font-size: 12px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; }
.op-meta .flag.err { color: var(--err); } .op-meta .flag.warn { color: #b86a00; }
.op-meta .ok-text { color: var(--go); } .op-meta .warn-text { color: #b86a00; }
.op-meta .next-l { font-weight: 600; color: var(--brand); text-decoration: none; }
.st:not(.rail .st) { color: var(--ink); font-weight: 600; white-space: nowrap; } /* 0.16.4: was ".dot", which the hours bar already uses. 0.22.3: never the steps of the progress rail (their connector became an 8 px dot) */
.st:not(.rail .st)::before { content: ""; display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 6px; vertical-align: 1px; background: #9fb0bd; }
.st.ok:not(.rail .st)::before { background: var(--go); } .st.info:not(.rail .st)::before { background: var(--brand); } .st.warn:not(.rail .st)::before { background: #e0920a; } .st.err:not(.rail .st)::before { background: var(--err); }
body.staff .page-head > div { min-width: 0; }
body.staff .page-head .row:has(> .op-meta) { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 14px; }
body.staff .page-head h1.mono { font-size: 26px; }
/* statuses in the ticket cards: words, not boxes */
.grid-op .chip:not(.next) { background: none; padding: 0; min-height: 0; border-radius: 0; font-weight: 600; }
.grid-op .chip.ok { color: var(--go); } .grid-op .chip.warn { color: #b86a00; } .grid-op .chip.err { color: var(--err); }
.grid-op .ver .row.between { align-items: baseline; }
.grid-op .file.delivered { border-color: var(--line); background: #fff; }
/* upload: a button and a hint; the box lights up when a file is dragged over */
.drop.pick { flex-direction: row; justify-content: flex-start; gap: 10px; padding: 0; border: 0; background: none; border-radius: 8px; text-align: left; }
.is-over .drop.pick, .drop.pick.is-over { outline: 2px dashed var(--brand); outline-offset: 6px; background: #f0f7fc; }
/* delivery text folded like a system message */
.msg.std > .body.clamp { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
@media (max-width: 1023px) {
  body.staff .page-head .row:has(> .op-meta) { display: block; }
  .op-meta { font-size: 13px; margin-top: 2px; }
  /* operator and work status on one row, label inside the box, Save beside (overrides the 0.12 rows above) */
  body.staff .op-ctl { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto; gap: 8px; align-items: stretch; margin-top: 8px; }
  body.staff .op-ctl > div, body.staff .op-ctl > div:first-of-type { display: flex; align-items: center; gap: 4px; min-width: 0; height: 44px; padding: 0 0 0 10px; background: #fff; border: 1px solid var(--line); border-radius: 8px; grid-column: auto; }
  body.staff .op-ctl .lbl { margin: 0; font-size: 12px; color: var(--muted); flex: none; }
  body.staff .op-ctl .in, body.staff .op-ctl #as { border: 0; background: none; height: 42px; min-width: 0; flex: 1; padding: 0 2px; width: auto; grid-column: auto; font-size: 14px; text-overflow: ellipsis; }
  body.staff .op-ctl .lbl[for="as"] { font-size: 0; } body.staff .op-ctl .lbl[for="as"]::before { content: "Op."; font-size: 12px; }
  body.staff .op-ctl > .btn { grid-column: auto; min-height: 44px; padding: 0 14px; }
  body.staff .op-ctl .op-take { display: none; } /* "Take it" is in the step bar on a phone */
  .grid-op .drop.pick { display: grid; grid-template-columns: 1fr; }
  .grid-op .drop.pick .small { display: none; }
}

/* 0.16.3: previous / next ticket at the top right (computer) */
.op-nav { display: flex; gap: 6px; }
.op-nav .btn { min-height: 44px; width: 44px; padding: 0; font-size: 22px; line-height: 1; }
.op-nav .btn.is-off { color: #9fb0bd; border-color: var(--line); cursor: default; }
@media (min-width: 1024px) {
  body.staff .page-head:has(> .op-nav) { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: center; gap: 12px; }
  body.staff .page-head:has(> .op-nav) > div:first-child { min-width: 0; }
}

@media (max-width: 1023px) { body.staff .op-ctl select { text-overflow: ellipsis; overflow: hidden; } } /* 0.16.4: long operator names end with "…" */

/* ===== 0.17.0 — ECU coverage: the known-ECU line, the two groups of extras, the admin page ===== */
/* 0.17.2: the two group titles as coloured bands (mockup H1): count inside the title, help under it */
.cov-h { display: block; margin: 16px 0 8px; padding: 10px 12px; border-radius: 8px; border-left: 4px solid; font-size: 16px; line-height: 1.3; }
.cov-h b { display: block; font-weight: 700; }
.cov-h span { display: block; margin-top: 2px; font-size: 13px; opacity: .85; }
.cov-h[data-cov-h="avail"] { background: #e6f4ea; color: #14532d; border-color: var(--ok); }
.cov-h[data-cov-h="nv"] { background: #fff4e5; color: #7a4a00; border-color: var(--warn); }
.cov-h + .opts { margin-top: 0; }
[data-cov="nv"] { margin-top: 0; }
/* 0.27.4: the attach rules under the drop zone */
.drop-rules { margin: 10px 0 0; padding: 10px 12px; border-radius: 8px; background: #f3f6f9; font-size: 13px; color: var(--ink); line-height: 1.45; }
.drop-rules b { font-weight: 600; }
/* 0.26.0: form heading with a note on its line ("Power increase · Includes Vmax Off…"); the note goes under when it does not fit */
.lbl-row { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 12px; row-gap: 2px; margin-bottom: 6px; }
.lbl-row .lbl { margin: 0; }
.lbl-row .main-note { margin: 0; }
.lbl-row .main-note.hide { display: none; }
/* 0.26.0: account not confirmed: one box, two buttons side by side when they fit */
.confirm-box { display: flex; flex-direction: column; gap: 12px; }
.confirm-box .btns { display: flex; gap: 10px; flex-wrap: wrap; }
.confirm-box .btns .btn { flex: 1 1 auto; }
/* 0.26.0: delivery message: warnings and procedures folded under one line */
.msg details.rb { border: 1px solid #f0c27a; border-radius: 8px; margin-top: 8px; background: #fffaf0; }
.msg details.rb > summary { list-style: none; display: flex; align-items: center; gap: 8px; min-height: 44px; padding: 8px 12px; cursor: pointer; font-weight: 700; color: #92400e; }
.msg details.rb > summary::-webkit-details-marker { display: none; }
.msg details.rb > summary .chev { margin-left: auto; width: 10px; height: 10px; border-right: 2px solid #92400e; border-bottom: 2px solid #92400e; transform: rotate(45deg); margin-bottom: 4px; flex: 0 0 auto; }
.msg details.rb[open] > summary .chev { transform: rotate(-135deg); margin-bottom: 0; margin-top: 4px; }
.msg details.rb > .body { padding: 0 12px 12px; }
.msg .file-wrap + .body { margin-top: 8px; }
/* 0.26.0: the extras in two foldable groups (removals / limiters, fixes & features), open by default */
.opts:has(> details.xg) { gap: 10px; align-items: start; } /* computer: the two groups side by side, each its own height */
@media (min-width: 1024px) { .opts:has(> details.xg) { gap: 14px; } }
details.xg { border: 1px solid var(--line); border-radius: 8px; background: #fff; }
details.xg > summary { list-style: none; display: flex; align-items: center; gap: 10px; min-height: 48px; padding: 8px 12px; cursor: pointer; font-family: var(--font-c); font-weight: 700; font-size: 17px; } /* 0.27.1: bold titles */
details.xg > summary::-webkit-details-marker { display: none; }
details.xg > summary .xg-n { margin-left: auto; font-family: var(--font); font-weight: 400; font-size: 14px; color: var(--muted); white-space: nowrap; }
details.xg > summary .chev { width: 10px; height: 10px; border-right: 2px solid var(--brand); border-bottom: 2px solid var(--brand); transform: rotate(45deg); margin: 0 4px 4px 2px; flex: 0 0 auto; }
details.xg[open] > summary .chev { transform: rotate(-135deg); margin: 4px 4px 0 2px; }
details.xg > .xg-list { border-top: 1px solid var(--line); }
details.xg .opt.compact { border: 0; border-radius: 0; border-bottom: 1px solid #e6ecf1; }
details.xg .opt.compact:last-child { border-bottom: 0; }
details.xg .opt.compact:has(input:checked) { background: #eef5fb; box-shadow: inset 3px 0 0 var(--brand); }
/* "· not verified" on the description line (hint), or on its own line when the extra has none */
/* 0.20.3: no "· not verified" on the cards (the amber group header says it); the tag stays in the summary and on the ticket. */
[data-extras] .opt.compact .grow > .nv-note { display: none; }
.sum-nv, .op-nv { color: var(--warn); font-size: 12px; font-weight: 600; white-space: nowrap; }
.op-nv { display: block; white-space: normal; } /* staff box: under the name, never a split name */
.cov-stats { display: flex; gap: 18px 24px; flex-wrap: wrap; }
.cov-stats div { font-size: 13px; color: var(--muted); }
.cov-stats div b { display: block; font-size: 22px; color: var(--ink); }
.cov-up { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.cov-up .in { max-width: 420px; }
.cov-row { display: flex; gap: 10px; flex-wrap: wrap; margin: 10px 0; }
.cov-row .in { flex: 1 1 160px; max-width: 260px; }

/* ===== 0.18.0 — AI draft: the instruction row above the reply (mockup A2) ===== */
.ai-row { display: flex; gap: 8px; align-items: center; margin: 0 0 8px; }
.ai-row .in { flex: 1 1 auto; min-width: 0; height: 40px; padding-top: 0; padding-bottom: 0; }
.ai-row .ai-btn { flex: none; }
.ai-row .in::placeholder { color: var(--muted); }

/* ===== 0.18.0 — billing details under the invoice (customer ticket): compact box, same look as the payment page ===== */
.inv-bill { border: 1px solid var(--line); border-radius: 8px; background: #fff; }
.inv-bill > summary { min-height: 48px; padding: 10px 12px; }
.inv-bill .bb-t2 { font-size: 15px; font-weight: 600; color: var(--ink); }
.inv-bill .bb-form { padding: 0 12px 12px; }

/* ===== 0.19.0 — installation notes of the coverage export: under the extra, in the summary, on the ticket ===== */
.svc-note { display: block; font-size: 13px; line-height: 1.35; color: var(--muted); overflow-wrap: anywhere; text-wrap: wrap; } /* 0.19.1: not "balance" — it left a quarter of each line empty */
.svc-note::before { content: "\25B8\00A0"; color: var(--brand); }
.sumrow.has-note { flex-wrap: wrap; }
.sumrow.has-note > span:first-child { flex: 1 1 0; min-width: 0; }
.sumrow.has-note > span:nth-child(2) { flex: 0 0 auto; }
.sumrow.has-note > .svc-note { flex: 0 0 100%; margin-top: 2px; }

/* 0.20.0: price-list tiles: the icon replaces the radio circle, the whole border marks the choice */
.opt.grp { position: relative; border-width: 2px; padding: 8px 14px 8px 12px; }
.opt.grp input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.opt.grp .gi { flex: none; width: 48px; height: 24px; color: var(--muted); } /* 0.26.1: one 48 px slot for every list, two vehicles on the car lists */
.opt.grp:has(input:checked) { box-shadow: none; background: #eef5fa; }
.opt.grp:has(input:checked) .gi { color: var(--brand); }
.opt.grp:has(input:focus-visible) { outline: 2px solid var(--brand); outline-offset: 2px; }

/* 0.20.3: service cards without the checkbox/radio: the whole card is the choice (border + tint), a ✓ before
   the name on the chosen ones (extras are multiple). IMMO rows, Checksum and the two conditions keep their box. */
.opt.main, .opt.none-opt, section:not(.ck-card) [data-extras] .opt.compact:not(.immo-row) { position: relative; border-width: 2px; }
.opt.main > input, .opt.none-opt > input, section:not(.ck-card) [data-extras] .opt.compact:not(.immo-row) > input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; }
.opt.main, .opt.none-opt { gap: 0; }
section:not(.ck-card) [data-extras] .opt.compact:not(.immo-row) { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "text price"; } /* 0.26.0: the price keeps its column */
.opt.main:has(input:checked), .opt.none-opt:has(input:checked), section:not(.ck-card) [data-extras] .opt.compact:not(.immo-row):has(input:checked) { box-shadow: none; background: #eef5fa; border-color: var(--brand); }
.opt.main:has(input:checked) .name::before, .opt.none-opt:has(input:checked) .name::before, section:not(.ck-card) [data-extras] .opt.compact:not(.immo-row):has(input:checked) .name::before { content: "\2713"; display: inline-block; width: 18px; height: 18px; margin-right: 6px; border-radius: 4px; background: var(--brand); color: #fff; font-size: 12px; line-height: 18px; text-align: center; vertical-align: 1px; }
.opt.main:has(input:focus-visible), .opt.none-opt:has(input:focus-visible), section:not(.ck-card) [data-extras] .opt.compact:not(.immo-row):has(input:focus-visible) { outline: 2px solid var(--brand); outline-offset: 2px; }
/* "✓ Included" after the words, where the price column stays empty */

/* 0.20.5: checksum = a yes/no the customer must make (tiles like the price lists); the extra card itself is hidden */
.ck-card .ck-help strong { display: block; margin-top: 6px; }
.ck-card .ck-opts { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; }
/* 0.27.1: the checksum price at the right of its title (the title wraps, the price stays top right) */
.ck-card .ck-opts .opt.grp .grow { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: baseline; column-gap: 12px; }
.ck-card .ck-opts .opt.grp .grow br { display: none; }
.ck-card .ck-opts .opt.grp .grow > .small { font-size: 15px; font-weight: 600; color: var(--brand); white-space: nowrap; }
.ck-card .ck-hidden { display: none; }

/* 0.20.6: the summary is sticky only beside the form (computer): on a phone it slid down over the "Continue" card
   when the screen was shorter than the summary's distance to the page end (Safari with its bars). */
@media (max-width: 1023px) { #request-form > aside.sum-side.sticky { position: static; } }
/* 0.20.6: "Log in" and "Email me a code" side by side, each half the row */
.exist-row > .btn { flex: 1 1 auto; min-width: 0; padding-left: 12px; padding-right: 12px; white-space: nowrap; } /* side by side when both fit, else each full width; never wrapped inside */

/* 0.20.6: tips on a phone: one row of five (emoji + price; the label stays for screen readers), half the height */
@container tipcard (max-width: 559px) {
  .tiles.tips.n5 { grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 6px; }
  .tiles.tips.n5 > :nth-child(n) { grid-column: auto; }
  .tiles.tips .tile { min-height: 0; padding: 8px 2px; gap: 3px; }
  .tiles.tips .tile .emo { font-size: min(20px, 5.4cqw); letter-spacing: -3px; }
  .tiles.tips .tile .lab { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .tiles.tips .tile > strong, .tiles.tips .tile > .small { font-size: 13px; }
}

/* 0.20.8: conditions — the checkbox sentence is the condition; the full text folds under it */
.terms-block { padding: 0; border: 0; background: none; margin-bottom: 8px; }
.terms-block .terms-check { align-items: flex-start; }
.terms-block .terms-check span { font-size: 14px; line-height: 1.45; }
.terms-block .terms-check:has(input:checked) { background: #e4f0fa; border-color: var(--brand); }
.terms-more { margin: 2px 0 0 2px; font-size: 13px; color: var(--muted); }
.terms-more > summary { cursor: pointer; padding: 4px 0; min-height: 40px; display: flex; align-items: center; gap: 6px; list-style: none; }
.terms-more > summary::-webkit-details-marker { display: none; }
.terms-more > summary::before { content: "\25B8"; color: var(--brand); transition: transform .15s; }
.terms-more[open] > summary::before { transform: rotate(90deg); }
.terms-more .terms-title { margin: 4px 0 6px; font-size: 14px; color: var(--ink); }
.terms-block .terms-more .terms { height: auto; max-height: 40vh; overflow-y: auto; }

/* 0.22.0: Platform Credit box (My tickets, Account) */
.credit-box { display: flex; align-items: center; gap: 10px; margin: 0 0 14px; padding: 10px 14px; border: 1px solid #b7dcc4; border-radius: 8px; background: var(--ok-bg); font-size: 14px; line-height: 1.4; }
.credit-box strong { color: #14532d; }
.credit-box .cb-ic { flex: none; font-size: 18px; }
.acc .credit-box { margin: 10px 0 0; }
/* 0.22.0: settings backup card (Admin › System) */
.sb-row { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.sb-row input[type=file] { max-width: 280px; }
.rows.pend .r { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 4px 14px; align-items: center; padding: 8px 0; border-top: 1px solid var(--line-2); }
.rows.pend .r > .err-text, .rows.pend .r > .muted:last-of-type { grid-column: 1 / -1; }
@media (max-width: 759px) { .rows.pend .r { grid-template-columns: minmax(0, 1fr) auto; } .rows.pend .r > span:nth-child(2) { grid-column: 1 / -1; } }
.rows.errs .r { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 2px 12px; padding: 6px 0; border-top: 1px solid var(--line-2); font-family: var(--mono, monospace); }
@media (max-width: 559px) { .rows.errs .r { grid-template-columns: minmax(0, 1fr); } }

/* 0.22.2: the ticket summary card and the order card on the payment page: tighter rows, nothing removed */
.card:has(#svc-h) .sumrow, .ord-card .sumrow { padding: 4px 0; font-size: 14px; }
.card:has(#svc-h) .sumrow.total, .ord-card .sumrow.total { padding-top: 8px; font-size: 18px; }
.card:has(#svc-h) > h2 { margin-bottom: 6px; }
.card:has(#svc-h) > p.small.muted.mb { margin-bottom: 4px; }
.card:has(#svc-h) .cr-row { margin-top: 2px; padding-top: 0; border-top: 0; }

/* 0.23.0: Admin > System — "vs previous period" line on the tiles, and the service × month table. */
.stat .delta { font-size: 13px; margin-top: 2px; color: var(--muted); }
.stat .delta.up { color: #1a7f37; }
.stat .delta.down { color: #b42318; }
@media (max-width: 559px) { .stat .delta .vs { display: none; } } /* the compared range is in the line under the title */
table.plain.heat td.h { text-align: center; padding: 6px 4px; min-width: 34px; font-variant-numeric: tabular-nums; }
table.plain.heat th.h { text-align: center; padding: 6px 4px; font-weight: 600; color: var(--muted); font-size: 12px; white-space: nowrap; }
table.plain.heat td.h.l1 { background: #e3eff6; }
table.plain.heat td.h.l2 { background: #bfd9e8; }
table.plain.heat td.h.l3 { background: #8fbcd6; }
table.plain.heat td.h.l4 { background: #4f93bd; color: #fff; }
table.plain.heat td:first-child, table.plain.heat th:first-child { position: sticky; left: 0; background: #fff; }
table.plain.heat td.ellip { display: table-cell; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 220px; }
@media (max-width: 559px) { table.plain.heat td.ellip { max-width: 128px; } }

/* 0.23.1: "Are you sure?" dialog of the delete-for-good forms (staff.js, form[data-confirm]) */
dialog.dlg { border: 1px solid var(--line); border-radius: 8px; padding: 20px 22px; max-width: 420px; width: calc(100% - 32px); color: var(--ink); background: #fff; }
dialog.dlg::backdrop { background: rgba(11, 42, 63, .45); }
dialog.dlg h3 { margin: 0 0 8px; font-size: 18px; color: var(--err); overflow-wrap: anywhere; }
dialog.dlg .acts { display: flex; flex-wrap: wrap; gap: 10px; justify-content: flex-end; margin-top: 16px; }

/* 0.24.0: queue selection (checkbox per row, "select all" in the header) and the action bar */
.rows.q .c-sel { display: flex; align-items: center; justify-content: center; min-width: 28px; min-height: 40px; margin: 0; cursor: pointer; }
.rows.q .c-sel input, .rows.q .rh .sel-all { width: 20px; height: 20px; margin: 0; accent-color: var(--brand); cursor: pointer; }
.rows.q .rh > span:first-child { display: flex; align-items: center; }
.rows.q > .r.on { background: #eef5fb; }
@media (max-width: 1279px) { .rows.q .c-sel { grid-area: sel; justify-self: end; align-self: start; min-height: 0; } }
.bulk { position: sticky; top: 0; z-index: 5; display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; padding: 10px 14px; margin: 0 0 10px; background: #0b2a3f; color: #fff; border-radius: 8px; }
.bulk b { font-size: 15px; margin-right: 4px; white-space: nowrap; }
.bulk .btn { min-height: 36px; padding: 0 12px; font-size: 14px; background: #fff; color: var(--brand); border-color: #fff; white-space: nowrap; }
.bulk .btn.danger { color: var(--err); }
.bulk .assign { display: inline-flex; gap: 6px; }
.bulk select.in { min-height: 36px; height: 36px; padding: 0 8px; font-size: 14px; width: auto; }
.bulk .x { margin-left: auto; color: #a9cde3; background: none; border: 0; font: inherit; cursor: pointer; min-height: 36px; }
.q-page .stat.st-trash { margin-left: auto; }
.rows.q.trash .c-next, .rows.q.trash .c-op { color: var(--ink); }
.rows.q .c-id .rowlink { color: inherit; text-decoration: none; }
.rows.q .c-id .rowlink:hover { color: var(--brand); }
@media (max-width: 1279px) { .rows.q .c-sel { min-height: 40px; padding: 0 0 0 10px; margin: -10px -6px -10px 0; } } /* a finger-sized target without moving the line */

/* 0.24.1: the last rule of the file. app.js checks it is there: a stylesheet cut by a proxy or a cache
   (26/10: Cloudflare served app.css cut at 64 KB for every staff page) is fetched again from the origin. */
html { --css-complete: 1; }

/* 0.25.0: Admin > Coupons > uses: the rows of a person with several accounts */
table.plain.cu tr.cu-flag > td { background: #fdf2f1; }
@media (max-width: 1199px) { table.plain.cu tr.cu-flag { background: #fdf2f1; border-radius: 8px; padding-left: 8px; padding-right: 8px; } }

/* 0.32.1 / 0.35.15: /op/online — summary, two sections; a table on a computer, one card per row under 760 px. */
.o-head { gap: 8px 16px; }
.o-head .o-bots { margin-left: auto; min-height: 36px; padding: 4px 10px; font-size: 14px; }
.o-lead { margin-bottom: 10px; }
.o-sum { margin: 0 0 10px; font-size: 15px; }
.o-sec { margin: 12px 0 6px; font-family: var(--font); font-size: 12px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--muted); }
.online-card { padding: 0 8px; }
table.online td { line-height: 1.35; vertical-align: top; }
table.online .o-mail, table.online .o-from, table.online .o-ipl, table.online .o-hits { display: block; font-size: 13px; }
table.online .o-pg { font-weight: 600; color: var(--brand); }
table.online .o-uai { width: 14px; height: 14px; vertical-align: -2px; margin-right: 4px; opacity: .75; }
table.online .o-path { font-size: 12px; }
table.online .o-flag { width: 16px; height: 12px; vertical-align: -1px; border-radius: 2px; box-shadow: 0 0 0 1px rgba(0,0,0,.08); }
table.online .o-ipl { color: var(--muted); }
table.online .o-lang { margin-left: 6px; }
table.online .o-dot { display: inline-block; width: 8px; height: 8px; margin-right: 6px; border-radius: 50%; background: #3ddc84; vertical-align: 1px; }
table.online tr.is-off .o-dot { background: #c3cbd3; } /* seen earlier in the hour, not online now */
table.online tr.is-off td { color: var(--muted); }
table.online tr.is-off .o-pg { color: var(--muted); }
table.online tr.is-bot .o-dot { background: #e0a526; }
[data-online-list].hide-bots tr.is-bot { display: none; }
table.online .o-ip2 { display: none; } /* the IP sits under the location on a computer, on the last line of the card on a phone */
@media (max-width: 759px) {
  .o-head { margin-bottom: 4px; }
  .online-card { padding: 0; background: none; border: 0; }
  table.online, table.online tbody, table.online td { display: block; }
  table.online thead { display: none; }
  /* a card: name + "ago" on the first line; the page; location and browser side by side (they wrap when
     long); IP, time on the desk and requests on the last line */
  table.online tr { display: flex; flex-wrap: wrap; align-items: baseline; gap: 1px 0; margin-bottom: 8px; padding: 9px 12px; background: #fff; border: 1px solid var(--line); border-radius: 8px; font-size: 14px; }
  table.online tr.is-off { background: #f6f8fa; }
  table.online td { padding: 0; border: 0; }
  table.online .o-who { flex: 1 1 auto; order: 1; font-size: 16px; min-width: 0; }
  table.online .o-ago { flex: 0 0 auto; order: 2; color: var(--muted); font-size: 13px; text-align: right; }
  table.online .o-page { order: 3; } table.online .o-loc { order: 4; } table.online .o-br { order: 5; } table.online .o-since { order: 6; }
  table.online .o-page { flex: 0 0 100%; }
  table.online .o-page:empty { display: none; }
  table.online .o-from { display: inline; font-size: 14px; }
  table.online .o-pg + .o-from::before, table.online .o-path + .o-from::before { content: "\00a0· "; }
  table.online .o-loc, table.online .o-br { flex: 0 1 auto; color: var(--muted); }
  table.online .o-loc .o-ipl { display: none; }
  table.online .o-loc:not(.o-noloc) + .o-br::before { content: "\00a0· "; }
  table.online .o-loc.o-noloc { display: none; }
  table.online .o-br .o-lang { margin-left: 0; }
  table.online .o-br .o-lang::before { content: " · "; }
  table.online .o-since { flex: 0 0 100%; color: var(--muted); text-align: left; font-size: 13px; }
  table.online .o-since .o-ip2 { display: inline; font-size: 13px; }
  table.online .o-since .o-ip2::after { content: " · "; }
  table.online .o-since .o-time::after { content: " on the desk"; }
  table.online .o-since .o-hits { display: inline; }
  table.online .o-since .o-hits::before { content: " · "; }
}

/* 0.32.3: "anche senza registrazione" beside the request page title for visitors: on the same line when it
   fits, whole on the next line when it does not (never broken). */
h1 .noreg { display: inline-block; font-family: var(--font); font-size: 15px; font-weight: 600; letter-spacing: 0; color: #1b7f4b; white-space: nowrap; vertical-align: 2px; }
h1 .noreg::before { content: "✓ "; }

/* 0.33.0: welcome page — the two questions as radio rows; "(optional)" next to a label in plain weight */
.fw-n { font-weight: 400; }
fieldset.b0 { border: 0; min-width: 0; }
.p0 { padding: 0; }

/* 0.34.0: checkout survey strip on the ticket page (right after a payment) */
.fb { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; margin-bottom: 16px; padding: 12px 44px 12px 16px; border: 1px solid var(--line); border-radius: 8px; background: var(--card); }
.fb .q { font-weight: 600; } .fb .q.full { width: 100%; }
.fb .faces { display: flex; gap: 6px; }
.fb .face { width: 44px; height: 44px; border: 1px solid var(--line); border-radius: 8px; background: var(--card); font-size: 24px; line-height: 1; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; }
.fb .face.on { border-color: var(--brand); background: #eaf3f9; }
.fb .x { position: absolute; top: 6px; right: 6px; width: 32px; height: 32px; border: 0; background: none; font-size: 22px; color: var(--muted); cursor: pointer; border-radius: 8px; }
.fb .chips { display: flex; flex-wrap: wrap; gap: 6px; }
.fb .chip2 { padding: 0 10px; min-height: 36px; display: inline-flex; align-items: center; border: 1px solid var(--line); border-radius: 8px; background: var(--card); color: var(--ink); font: inherit; font-size: 14px; cursor: pointer; }
.fb .chip2[aria-pressed="true"] { border-color: var(--brand); background: #eaf3f9; }
.fb .row2 { display: flex; gap: 8px; width: 100%; } .fb .row2 .in { flex: 1 1 auto; min-width: 0; }
.fb .face:focus-visible, .fb .chip2:focus-visible, .fb .x:focus-visible { outline: 3px solid var(--brand-2); outline-offset: 2px; }
.fb-comments { padding-left: 18px; font-size: 14px; display: grid; gap: 4px; }
/* 0.34.2: customers list — second lines in the two-line cells */
table.cust-list td.c-two { line-height: 1.4; }
/* 0.35.0: the locked reply box of an unpaid ticket: text and the Pay button on one line when they fit */
.chat-unpaid { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.chat-unpaid .btn { margin-left: auto; }
.cancel-req { flex: 1 0 100%; font-size: 13px; }
.cancel-req > summary { cursor: pointer; color: var(--muted); text-decoration: underline; list-style: none; min-height: 32px; display: inline-flex; align-items: center; }
.cancel-req > summary::-webkit-details-marker { display: none; }
.cancel-req form { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin-top: 4px; }
/* 0.35.1: operator ticket — while a file is dragged over the page, the reply box says it will take it */
body.staff.is-drag #composer { box-shadow: inset 0 0 0 3px var(--brand); background: #f0f7fc; border-radius: 8px; }
body.staff.is-drag #composer::after { content: "Drop here: attached to your reply to the customer"; display: block; margin-top: 6px; font-size: 13px; font-weight: 600; color: var(--brand); }
/* 0.35.2: survey comment required with "Other" and left empty */
.fb .in.is-missing { border-color: var(--err); box-shadow: 0 0 0 3px var(--err-bg); }
/* 0.35.4 (layout B): bell | title / text / link; the link on its own line, right-aligned on computer, never broken */
.mailwarn { display: grid; grid-template-columns: auto 1fr; gap: 2px 10px; align-items: start; margin: 0 0 14px; padding: 10px 12px; background: var(--warn-bg); color: var(--warn); border: 1px solid #f0c27a; border-left: 4px solid var(--turn); border-radius: 8px; font-size: 14px; line-height: 1.35; }
.mailwarn .mw-ic { grid-row: 1 / span 3; margin-top: 2px; } .mailwarn .mw-ic .ic { width: 18px; height: 18px; }
.mailwarn .mw-h { grid-column: 2; font-family: var(--font-c); font-size: 15px; font-weight: 700; color: var(--turn-ink); }
.mailwarn .mw-b { grid-column: 2; }
.mailwarn .mw-link { grid-column: 2; justify-self: end; white-space: nowrap; margin-top: 2px; font-weight: 600; }
@media (max-width: 600px) { .mailwarn .mw-link { justify-self: start; } }
.stack > .mailwarn { margin: 0; }
.mailwarn .mw-addr { display: inline-block; max-width: 100%; overflow-wrap: anywhere; } /* whole address on the next line before it breaks */
/* 0.35.4: the survey's flex parts (faces, chips, comment row, the strip itself) honour `hidden`: before, after
   "Send" they stayed in view under "Received, thanks" and the strip never went away */
.fb[hidden], .fb [hidden] { display: none !important; }
.st-since > p { flex: 1 1 auto; }
/* 0.36.0: Admin › Statistics — period bar + tabs; Conversions (funnel, journeys); Admin › System two-column grid */
.st-bar { display: flex; flex-direction: column; gap: 8px; }
.st-tabs { display: flex; flex-wrap: wrap; gap: 6px; }
.st-tabs a { display: inline-flex; align-items: center; min-height: 38px; padding: 0 14px; border: 1px solid var(--line); border-radius: 8px; background: var(--card); color: var(--ink); font-weight: 600; font-size: 14px; text-decoration: none; }
.st-tabs a.on { background: var(--brand); border-color: var(--brand); color: #fff; }
.st-tabs a:hover:not(.on) { border-color: var(--brand-2); }
.funnel { display: grid; grid-template-columns: minmax(150px, 220px) 1fr 90px; gap: 6px 12px; align-items: center; font-size: 14px; }
.funnel .fbar { height: 18px; background: #d9e7f0; border-radius: 4px; position: relative; overflow: hidden; }
.funnel .fbar i { position: absolute; left: 0; top: 0; bottom: 0; background: var(--brand); border-radius: 4px; }
.funnel .num { text-align: right; white-space: nowrap; }
.ok-t { color: var(--ok); font-weight: 600; } .warn-t { color: var(--warn); font-weight: 600; }
.jy-sub { display: block; }
.jy-path { display: block; font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 12px; color: var(--muted); margin-top: 2px; overflow-wrap: anywhere; }
table.jy tr.is-left td { color: var(--muted); }
.sys-grid > section { margin: 0; }
@media (max-width: 759px) { .funnel { grid-template-columns: 1fr 70px; } .funnel > span:nth-child(3n+1) { grid-column: 1 / -1; margin-top: 4px; } }
.cust-where { display: block; }
.cust-ip { display: block; font-size: 12px; line-height: 1.3; letter-spacing: -.01em; }
.cust-contact { display: flex; flex-wrap: wrap; gap: 2px 14px; align-items: baseline; }
