:root {
  --bg: #0b0d10;
  --panel: #16191f;
  --panel-alt: #1c2029;
  --panel-hover: #21262f;
  --border: #262b35;
  --text: #eceef1;
  --muted: #8b93a1;
  --accent: #5b8def;
  --accent-2: #7aa2ff;
  --accent-text: #ffffff;
  --warn: #f0b429;
  --warn-bg: #2e2308;
  --error: #ff6b6b;
  --error-bg: #2e1414;
  --success: #34d399;
  --success-bg: #0d2a20;
  --shadow: 0 2px 10px rgba(0, 0, 0, 0.35);
  --shadow-lg: 0 8px 30px rgba(0, 0, 0, 0.45);
  --radius: 14px;
  --radius-sm: 10px;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html { background: var(--bg); color-scheme: dark; }

body {
  margin: 0;
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
  /* Safety net: wide content (wide tables, etc.) must scroll inside its
     own container (see .table-scroll below), never push the whole page
     sideways. If something wide ever slips through anyway, this clips it
     instead of letting the appbar/tabbar shift with the rest of the
     screen — found 23.08, Продажи's table had no scroll wrapper and the
     whole app shifted horizontally when it overflowed a narrow phone. */
  overflow-x: hidden;
}

a { color: var(--accent); text-decoration: none; }

/* ---- app shell: top bar ---- */

.appbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  /* --tg-top: room for the status bar and Telegram's own controls when
     the app is fullscreen inside Telegram (telegram-fullscreen.js); 0 otherwise. */
  padding: calc(max(env(safe-area-inset-top, 0px), var(--tg-top, 0px)) + 14px) 18px 12px;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  position: sticky;
  top: 0;
  z-index: 20;
  border-bottom: 1px solid var(--border);
}

.appbar-title-block { min-width: 0; }
.appbar-title { font-size: 19px; font-weight: 800; letter-spacing: -0.01em; }
.appbar-store { font-size: 12px; font-weight: 500; color: var(--muted); margin-top: 1px; }

.avatar {
  width: 34px; height: 34px; border-radius: 50%;
  background: linear-gradient(135deg, var(--accent), #8b5cf6);
  color: #fff; display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 14px; flex-shrink: 0;
  box-shadow: var(--shadow);
}

/* ---- app shell: bottom tab bar ---- */

.tabbar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  display: flex;
  justify-content: space-around;
  padding: 8px 6px calc(max(env(safe-area-inset-bottom, 0px), var(--tg-bottom, 0px)) + 8px);
  background: color-mix(in srgb, var(--panel) 82%, transparent);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  border-top: 1px solid var(--border);
  z-index: 20;
}

.tabbar a {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  color: var(--muted);
  font-size: 10.5px; font-weight: 600;
  padding: 5px 12px 4px;
  border-radius: 12px;
  transition: color 0.15s ease, background 0.15s ease, transform 0.1s ease;
  min-width: 56px;
}
.tabbar a svg { display: block; }
.tabbar a.active { color: var(--accent-2); background: color-mix(in srgb, var(--accent) 14%, transparent); }
.tabbar a:active { transform: scale(0.92); }

/* ---- layout ---- */

.container { max-width: 640px; margin: 0 auto; padding: 18px 16px calc(max(env(safe-area-inset-bottom, 0px), var(--tg-bottom, 0px)) + 96px); }
/* A page with no top bar of its own (the boot screen, a login) must not sit under Telegram's controls either. */
body:not(:has(.appbar)) .container { padding-top: calc(var(--tg-top, 0px) + 18px); }

h1 { font-size: 21px; margin: 0 0 16px; font-weight: 800; letter-spacing: -0.01em; }
h2 { font-size: 15px; margin: 28px 0 12px; font-weight: 700; }
h3 { font-size: 12px; color: var(--muted); margin: 0 0 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; }

.back-link { display: inline-flex; align-items: center; gap: 4px; color: var(--muted); font-size: 13px; font-weight: 600; margin-bottom: 14px; }
.back-link:hover { color: var(--text); }
.back-link svg { flex-shrink: 0; }

/* ---- tables ---- */

/* Every <table class="table"> must be wrapped in this — a table with
   several columns (repairs/sales/movements history etc.) is often wider
   than a phone screen, and without this wrapper the table pushed the
   WHOLE .container (and with it the whole visible screen) sideways
   instead of just scrolling itself (found 23.08 on Продажи, was true of
   every .table on every page — .container has no width clamp against
   content wider than it). Rule going forward: any wide content (a table,
   a long code block, anything that can't just wrap) gets its own
   overflow-x:auto wrapper — never let the page itself grow wider than
   the viewport. */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.table-scroll .table { min-width: max-content; }

.table { width: 100%; border-collapse: collapse; background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow); }
.table th, .table td { text-align: left; padding: 11px 13px; border-bottom: 1px solid var(--border); font-size: 13.5px; }
.table tr:last-child td { border-bottom: none; }
.table th { color: var(--muted); font-weight: 700; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.05em; background: var(--panel-alt); }
.table tr.clickable { cursor: pointer; transition: background 0.12s ease; }
.table tr.clickable:active { background: var(--panel-hover); }
@media (hover: hover) { .table tr.clickable:hover { background: var(--panel-alt); } }
.table tr.row-warn td { background: var(--warn-bg); }

/* ---- cards ---- */

.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; margin-bottom: 14px; }
.card {
  position: relative;
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 16px; text-decoration: none; color: var(--text); box-shadow: var(--shadow);
  transition: transform 0.12s ease, background 0.12s ease;
  display: flex; flex-direction: column; gap: 10px;
}
.card:active { transform: scale(0.97); background: var(--panel-hover); }
/* A whole card can be one big tap target (.stretched-link, covers the
   card) while still carrying a real, separately-clickable link inside it
   (e.g. a tel: number) — two nested <a> tags would be invalid HTML, so
   the card itself becomes a plain <div class="card">, the stretched-link
   supplies its navigation, and any exception just needs to paint above
   it (positioned content stacks above unpositioned content by default). */
.stretched-link { position: absolute; inset: 0; z-index: 0; }
.stretched-link-exception { position: relative; z-index: 1; color: var(--accent-2); text-decoration: none; }
.card-icon {
  width: 36px; height: 36px; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--accent) 16%, transparent); color: var(--accent-2);
}
.card-warn .card-icon { background: color-mix(in srgb, var(--warn) 18%, transparent); color: var(--warn); }
.card-num { font-size: 24px; font-weight: 800; letter-spacing: -0.02em; }
.card-label { color: var(--muted); font-size: 12.5px; }
.card-warn .card-num { color: var(--warn); }

.nav-card { display: flex; flex-direction: row; align-items: center; gap: 14px; padding: 14px 16px; }
.nav-card .card-icon { flex-shrink: 0; }
.nav-card-body { flex: 1; }
.nav-card-title { font-weight: 700; font-size: 14.5px; }
.nav-card-sub { color: var(--muted); font-size: 12px; margin-top: 1px; }
.nav-card .chevron { color: var(--muted); flex-shrink: 0; }
.nav-list { display: flex; flex-direction: column; gap: 10px; }

/* Photo + short details card, in a 2-col .cards grid — used for both
   Товары and Ремонты lists (thumb- prefix since it's not product-specific
   any more). */
.thumb-card { padding: 10px; gap: 8px; }
.thumb-card-photo, .thumb-card-photo-placeholder {
  width: 100%; aspect-ratio: 1; border-radius: 8px; object-fit: cover; background: var(--panel-alt);
}
.thumb-card-photo-placeholder { display: flex; align-items: center; justify-content: center; color: var(--muted); }
.thumb-card-name { font-weight: 700; font-size: 13px; line-height: 1.3; }
.thumb-card-meta { color: var(--muted); font-size: 11.5px; display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }

.profile-card { display: flex; flex-direction: row; align-items: center; gap: 14px; padding: 18px 16px; margin-bottom: 20px; }
.profile-avatar { width: 48px; height: 48px; border-radius: 50%; background: linear-gradient(135deg, var(--accent), #8b5cf6); color: #fff; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 18px; flex-shrink: 0; }
.profile-name { font-weight: 700; font-size: 16px; }
.profile-role { color: var(--muted); font-size: 12.5px; margin-top: 2px; }

/* ---- forms ---- */

form.inline-form { display: flex; gap: 8px; margin-top: 8px; flex-wrap: wrap; }
form.search-bar { display: flex; gap: 8px; margin-bottom: 16px; align-items: center; }
form.edit-form { display: flex; flex-direction: column; gap: 12px; margin-top: 8px; }
form.edit-form label { display: flex; flex-direction: column; gap: 5px; font-size: 12.5px; color: var(--muted); font-weight: 600; }
.required-mark { color: var(--error); margin-left: 2px; }
.checkbox-row { display: flex; flex-direction: row; flex-wrap: wrap; gap: 10px; }
form.edit-form label.checkbox-label {
  /* display:block on purpose, not flex — a flex-display <label> that
     implicitly wraps its checkbox is unreliable on mobile WebKit/Chrome
     (tap doesn't toggle it), even though the identical markup works fine
     on desktop Telegram's engine. Checkbox+text are laid out via
     vertical-align/margin below instead; product-scan.js adds an
     explicit click handler as a second safety net regardless. */
  display: block;
  flex: 1 1 auto; min-width: 150px;
  padding: 12px 14px;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel);
  font-size: 13.5px; color: var(--text); font-weight: 500;
}
form.edit-form label.checkbox-label input[type="checkbox"] {
  width: 24px; height: 24px;
  vertical-align: middle;
  margin-right: 10px;
}
/* .sale-layout/.cash-layout only get their side-by-side grid at
   min-width:900px (below) — at every width, including mobile Telegram
   where this is actually used, the plain wrapper <div> inside each
   column had NO gap of its own (only form.edit-form's own gap:12px
   applies, and only to ITS direct children — .sale-layout is one such
   child, but everything nested a level deeper inside it got zero
   spacing). "+ Добавить позицию" sat flush against the row above it and
   the Канал/Оплата fields below with no breathing room — found 23.08,
   Павел: "залазит на форму". */
.sale-layout > div, .cash-layout > div { display: flex; flex-direction: column; gap: 12px; }

.movement-forms { display: flex; flex-direction: column; gap: 14px; }
.movement-forms form,
.panel-box { background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); padding: 16px; box-shadow: var(--shadow); }

.grid-2 { display: grid; grid-template-columns: 1fr; gap: 16px; }

input, select, textarea, button {
  font-family: inherit; font-size: 14.5px;
  padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--panel-alt); color: var(--text);
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
}
input::placeholder, textarea::placeholder { color: #4d5566; }
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent); }

select {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238b93a1' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 16px;
  padding-right: 34px;
}
select::-ms-expand { display: none; }
option { background: var(--panel-alt); color: var(--text); }

/* ---- custom select (see select-enhance.js) ---- */
.csel { position: relative; }
.csel-native { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.csel-trigger {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 8px;
  text-align: left; font-family: inherit; font-size: 14.5px;
  background: var(--panel-alt); color: var(--text); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 10px 12px; cursor: pointer;
}
.csel-trigger::after {
  content: ""; width: 16px; height: 16px; flex-shrink: 0;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238b93a1' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>");
  background-repeat: no-repeat; background-size: contain;
}
.csel-panel {
  display: none; position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 30;
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg); max-height: 240px; overflow-y: auto; padding: 4px;
}
.csel-panel.open { display: block; }
.csel-item { padding: 9px 10px; border-radius: 8px; font-size: 14px; cursor: pointer; color: var(--text); }
.csel-item.active { color: var(--accent-2); font-weight: 600; }
.csel-item:hover, .csel-item:active { background: var(--panel-hover); }
button {
  background: linear-gradient(135deg, var(--accent), #6b7fe8); color: var(--accent-text);
  border: none; cursor: pointer; padding: 11px 18px; font-weight: 700;
  box-shadow: 0 4px 14px color-mix(in srgb, var(--accent) 35%, transparent);
  transition: transform 0.1s ease, filter 0.15s ease;
}
button:active { transform: scale(0.97); }
button svg { vertical-align: -4px; margin-right: 2px; }
@media (hover: hover) { button:hover { filter: brightness(1.08); } }
button.secondary { background: var(--panel-alt); color: var(--text); border: 1px solid var(--border); box-shadow: none; }
button.danger { background: var(--error); box-shadow: 0 4px 14px color-mix(in srgb, var(--error) 35%, transparent); }
button:disabled { opacity: 0.5; cursor: not-allowed; }

.btn-row { display: flex; gap: 8px; flex-wrap: wrap; margin: 10px 0; }

.login-box, .boot-box { max-width: 320px; margin: 80px auto; background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); padding: 26px; box-shadow: var(--shadow-lg); }
.login-box form { display: flex; flex-direction: column; gap: 12px; }
.login-box label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--muted); }

.flash { padding: 11px 15px; border-radius: var(--radius-sm); margin-bottom: 16px; font-size: 13.5px; font-weight: 500; }
.flash-error { background: var(--error-bg); color: var(--error); }
.flash-success { background: var(--success-bg); color: var(--success); }

.badge { font-size: 11.5px; color: var(--muted); background: var(--panel-alt); padding: 3px 10px; border-radius: 20px; border: 1px solid var(--border); }
.meta { color: var(--muted); font-size: 13px; }

.pill { display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px; font-weight: 700; padding: 4px 10px; border-radius: 20px; white-space: nowrap; }
.pill-new { background: #182338; color: #7fa8f5; }
.pill-in_progress { background: var(--warn-bg); color: var(--warn); }
.pill-ready { background: var(--success-bg); color: var(--success); }
.pill-issued { background: var(--panel-alt); color: var(--muted); border: 1px solid var(--border); }
.pill-cancelled { background: var(--error-bg); color: var(--error); }
.pill-online { background: #182338; color: #7fa8f5; }
.pill-offline { background: var(--panel-alt); color: var(--muted); }
.pill-parts { background: var(--panel-alt); color: var(--muted); border: 1px solid var(--border); }
.pill-resale { background: var(--success-bg); color: var(--success); }

.timeline { list-style: none; margin: 0; padding: 0; }
.timeline li { padding: 10px 0; border-bottom: 1px solid var(--border); font-size: 13px; }
.timeline li:last-child { border-bottom: none; }
.timeline .t-when { color: var(--muted); font-size: 11.5px; margin-top: 3px; }

.stat-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-bottom: 20px; }
.stat { background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); padding: 14px; box-shadow: var(--shadow); }
.stat-num { font-size: 19px; font-weight: 800; letter-spacing: -0.01em; }
.stat-label { color: var(--muted); font-size: 11px; margin-top: 3px; }

.section-btns { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 4px; margin-bottom: 16px; -webkit-overflow-scrolling: touch; }
.section-btns button { white-space: nowrap; }

@media (min-width: 480px) {
  .stat-row { grid-template-columns: repeat(3, 1fr); }
}
@media (min-width: 720px) {
  .grid-2 { grid-template-columns: 1fr 1fr; align-items: start; }
}

/* Desktop (19.08) — the app was mobile-first (Telegram Mini App on a
   phone), so .container just sat as a narrow 640px column with empty
   space on either side on an actual laptop screen. Widen the container
   so .cards/.table get real room to breathe; a stacked form (.edit-form)
   stretching to that same width would put a "Имя" field a thousand
   pixels wide, so it keeps a comfortable reading width and stays
   left-aligned rather than centering (centering a form under a
   left-aligned page title looks off-balance). */
@media (min-width: 900px) {
  .container { max-width: 1100px; }
  form.edit-form { max-width: 480px; }
  /* Ремонты (19.08): intake form and the repair cards side by side
     instead of stacked — the left column matches .edit-form's own cap
     so there's no dead gap between the form and its column edge. */
  .repairs-layout { display: grid; grid-template-columns: 480px 1fr; gap: 32px; align-items: start; }
  /* Продажи (19.08): item rows need real width to lay out product/qty/
     price side by side without wrapping, so #saleForm gets its own wider
     cap instead of the generic 480px .edit-form one — client contacts
     move into a narrower second column alongside it. */
  #saleForm { max-width: 900px; }
  .sale-layout { display: grid; grid-template-columns: 1fr 300px; gap: 32px; align-items: start; }
  /* Касса (21.08): balance/summary/ledger need the wide column to
     breathe (stat-row, the transactions table); the Расход/Внести-изъять
     forms are secondary input, so they get the same narrow sidebar
     treatment as sale-layout's contact form instead of stretching full
     width or stacking with empty space on either side. */
  .cash-layout { display: grid; grid-template-columns: 1fr 300px; gap: 32px; align-items: start; }
}

/* Tap-to-flip barcode card (product detail, 19.08) — front is the
   on-screen label, back holds the print button for a physical Xprinter
   XP-420B label (30x20mm). */
.barcode-flip { perspective: 1000px; cursor: pointer; margin: 0 auto; max-width: 320px; }
.barcode-flip-inner { position: relative; width: 100%; transition: transform 0.5s; transform-style: preserve-3d; }
.barcode-flip.flipped .barcode-flip-inner { transform: rotateY(180deg); }
.barcode-flip-front, .barcode-flip-back { backface-visibility: hidden; width: 100%; }
.barcode-flip-back {
  position: absolute; top: 0; left: 0; height: 100%; box-sizing: border-box;
  transform: rotateY(180deg); background: var(--panel); border-radius: 10px; padding: 16px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
}
.barcode-print-btn {
  padding: 10px 18px; border-radius: 8px; border: none; cursor: pointer;
  background: var(--accent); color: #fff; font-weight: 700; font-size: 14px;
}

/* Print-only barcode label — everything else on the page is hidden and
   this is scaled to the physical label size via @page. */
#printLabelArea { display: none; }
@media print {
  body * { visibility: hidden; }
  #printLabelArea, #printLabelArea * { visibility: visible; }
  #printLabelArea {
    display: flex; align-items: center; justify-content: center;
    position: fixed; top: 0; left: 0; width: 30mm; height: 20mm;
  }
  #printLabelArea img { width: 28mm; height: auto; }
  @page { size: 30mm 20mm; margin: 0; }
}
