/* ============================================================================
   KOKON CARS & BIKE SERVICE — СТИЛИ
   ============================================================================
   Дизайн ориентирован на использование одной рукой с телефона:
     - крупные тач-зоны (минимум 44px высота у кнопок/полей)
     - основные действия — крупные кнопки внизу экрана (thumb zone)
     - минимум горизонтальных жестов, всё листается вертикально
     - переменные Telegram Web App (--tg-theme-*) используются там, где
       Telegram их предоставляет, с безопасным fallback на светлую тему

   СТРУКТУРА ФАЙЛА:
     1. Переменные и сброс стилей
     2. Общие элементы (кнопки, инпуты, тулбар)
     3. Экраны и навигация (screen show/hide)
     4. Экран загрузки / нет доступа / ошибка
     5. Dashboard (карточки статистики, список техники)
     6. Карточка техники
     7. Форма обновления состояния
     8. Инвентаризация
     9. Тост-уведомления
     10. Адаптивность (media queries)
   ========================================================================== */


/* ==========================================================================
   1. ПЕРЕМЕННЫЕ И СБРОС СТИЛЕЙ
   ========================================================================== */

:root {
  /* Базовая палитра — используем цвета Telegram Web App, если доступны */
  --color-bg: var(--tg-theme-bg-color, #f4f5f7);
  --color-bg-secondary: var(--tg-theme-secondary-bg-color, #ffffff);
  --color-text: var(--tg-theme-text-color, #1c1c1e);
  --color-hint: var(--tg-theme-hint-color, #8e8e93);
  --color-link: var(--tg-theme-link-color, #2481cc);
  --color-button: var(--tg-theme-button-color, #2481cc);
  --color-button-text: var(--tg-theme-button-text-color, #ffffff);

  /* Цветовые индикаторы статусов (требование ТЗ) */
  --color-green: #34c759;
  --color-green-bg: #e8f9ec;
  --color-blue: #2481cc;
  --color-blue-bg: #e8f2fb;
  --color-yellow: #ff9f0a;
  --color-yellow-bg: #fff4e5;
  --color-red: #ff3b30;
  --color-red-bg: #fdeceb;

  --border-radius: 14px;
  --border-radius-sm: 10px;
  --spacing: 16px;
  --shadow-card: 0 1px 3px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.06);
}

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

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 15px;
  line-height: 1.4;
  overscroll-behavior-y: contain;
}

button, input, select, textarea {
  font-family: inherit;
  font-size: inherit;
  color: inherit;
}

ul, p, h1, h2, h3, h4 {
  margin: 0;
}


/* ==========================================================================
   2. ОБЩИЕ ЭЛЕМЕНТЫ
   ========================================================================== */

.hidden {
  display: none !important;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: none;
  border-radius: var(--border-radius-sm);
  padding: 14px 20px;
  min-height: 48px;
  font-weight: 600;
  font-size: 15px;
  cursor: pointer;
  transition: transform 0.08s ease, opacity 0.15s ease;
  -webkit-user-select: none;
  user-select: none;
}

.btn:active {
  transform: scale(0.97);
  opacity: 0.9;
}

.btn--primary {
  background: var(--color-button);
  color: var(--color-button-text);
}

.btn--secondary {
  background: var(--color-bg-secondary);
  color: var(--color-text);
  border: 1px solid rgba(0, 0, 0, 0.08);
}

.btn--danger {
  background: var(--color-red);
  color: #fff;
}

.btn--block {
  display: flex;
  width: 100%;
}

.btn--sticky {
  position: sticky;
  bottom: 0;
  left: 0;
  right: 0;
  margin: var(--spacing);
  width: calc(100% - 32px);
  box-shadow: var(--shadow-card);
}

.btn-icon {
  width: 36px;
  height: 36px;
  border: none;
  background: transparent;
  font-size: 20px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: var(--color-text);
}

.btn-icon:active {
  background: rgba(0, 0, 0, 0.06);
}

.form-label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--color-hint);
  margin: 18px 0 6px;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.form-label:first-child {
  margin-top: 0;
}

.form-input {
  width: 100%;
  border: 1px solid rgba(0, 0, 0, 0.1);
  background: var(--color-bg-secondary);
  border-radius: var(--border-radius-sm);
  padding: 12px 14px;
  min-height: 46px;
  color: var(--color-text);
}

.form-input:focus {
  outline: none;
  border-color: var(--color-button);
}

.form-textarea {
  min-height: 90px;
  resize: vertical;
}

.form-file {
  width: 100%;
  padding: 10px 0;
}

.search-input {
  flex: 1;
  border: 1px solid rgba(0, 0, 0, 0.1);
  background: var(--color-bg-secondary);
  border-radius: var(--border-radius-sm);
  padding: 12px 14px;
  min-height: 46px;
}

.filter-select {
  border: 1px solid rgba(0, 0, 0, 0.1);
  background: var(--color-bg-secondary);
  border-radius: var(--border-radius-sm);
  padding: 12px 10px;
  min-height: 46px;
  max-width: 140px;
}

.toolbar {
  display: flex;
  gap: 8px;
  padding: 0 var(--spacing) 12px;
}


/* ==========================================================================
   3. ЭКРАНЫ И НАВИГАЦИЯ
   ========================================================================== */

.screen {
  display: none;
  /* Strict height (not min-height) + overflow:hidden is what makes this a
     true, fixed-size viewport for its children. Previously this was
     min-height:100vh with no overflow constraint: if a screen's content
     was taller than the viewport (e.g. the Gantt chart with 300 rows),
     the .screen element itself would grow past 100vh and the page/body
     would become the scrolling element instead of the screen's own inner
     `flex:1; overflow-y:auto` container (.gantt-scroll, .card-scroll,
     etc). That's what caused the "only part of the screen is
     touch-scrollable" bug: the real scrollable area was clipped to
     whatever portion of the oversized layout happened to still be within
     the visible viewport, which shifts with orientation/viewport height —
     exactly the symptom of it working differently in landscape.
     100dvh (dynamic viewport height) is preferred where supported since it
     tracks Telegram's WebView chrome show/hide; 100vh is the fallback for
     older WebViews that don't support dvh. */
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  flex-direction: column;
  animation: fadeIn 0.15s ease;
}

.screen--active {
  display: flex;
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

.app-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px var(--spacing);
  background: var(--color-bg-secondary);
  position: sticky;
  top: 0;
  z-index: 10;
  box-shadow: var(--shadow-card);
}

.app-header--sub {
  justify-content: space-between;
}

.app-header__title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 18px;
  font-weight: 700;
}

.app-header__logo {
  font-size: 20px;
}

.app-header__role {
  font-size: 12px;
  font-weight: 700;
  padding: 4px 10px;
  border-radius: 20px;
  background: var(--color-blue-bg);
  color: var(--color-blue);
  text-transform: uppercase;
}


/* ==========================================================================
   4. ЭКРАН ЗАГРУЗКИ / НЕТ ДОСТУПА / ОШИБКА
   ========================================================================== */

.loading-box, .no-access-box {
  margin: auto;
  text-align: center;
  padding: 32px;
  max-width: 320px;
}

.spinner {
  width: 40px;
  height: 40px;
  margin: 0 auto 16px;
  border: 4px solid rgba(0, 0, 0, 0.08);
  border-top-color: var(--color-button);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

.no-access-icon {
  font-size: 48px;
  margin-bottom: 12px;
}

.no-access-box h2 {
  font-size: 18px;
  margin-bottom: 8px;
}

.no-access-box p {
  color: var(--color-hint);
  margin-bottom: 16px;
}


/* ==========================================================================
   5. DASHBOARD
   ========================================================================== */

/* Bounds everything below the header to the screen's remaining height and
   makes it the actual scrolling element (see the .screen height/overflow
   change: without an inner scroll container like this, a long vehicle list
   would either get clipped or force the whole page to scroll instead of
   just this region). */
.dashboard-scroll {
  flex: 1;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

.stats-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
  padding: var(--spacing);
}

.stat-card {
  background: var(--color-bg-secondary);
  border-radius: var(--border-radius);
  padding: 14px;
  box-shadow: var(--shadow-card);
  border-left: 4px solid var(--color-blue);
}

.stat-card__value {
  font-size: 26px;
  font-weight: 800;
  line-height: 1.1;
}

.stat-card__label {
  font-size: 12px;
  color: var(--color-hint);
  margin-top: 4px;
}

.stat-card--green { border-left-color: var(--color-green); }
.stat-card--blue { border-left-color: var(--color-blue); }
.stat-card--yellow { border-left-color: var(--color-yellow); }
.stat-card--red { border-left-color: var(--color-red); }

/* Per-vehicle-type utilization breakdown (Cars / Motorcycles / Scooters) */
.type-breakdown {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 0 var(--spacing) 14px;
}

.type-breakdown-row {
  display: flex;
  align-items: center;
  gap: 6px;
  background: var(--color-bg-secondary);
  border-radius: var(--border-radius-sm);
  padding: 8px 12px;
  font-size: 12px;
  box-shadow: var(--shadow-card);
  flex-wrap: wrap;
}

.type-breakdown-row__name {
  font-weight: 700;
  margin-right: auto;
}

.type-breakdown-row__stat {
  color: var(--color-hint);
  white-space: nowrap;
}

.type-breakdown-row__stat--green { color: var(--color-green); }
.type-breakdown-row__stat--blue { color: var(--color-blue); }
.type-breakdown-row__stat--red { color: var(--color-red); }

/* Distinct color dot per vehicle type — used both in the type-breakdown row
   and as the group section header marker in the vehicle list, so Cars /
   Motorcycles / Scooters are visually distinguishable at a glance (they
   previously all rendered as the same red icon). */
.type-dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}

.type-dot--car { background: var(--color-red); }
.type-dot--moto { background: #1c1c1e; } /* black, distinct from the red car and yellow scooter dots */
.type-dot--scooter { background: var(--color-yellow); }
.type-dot--unspecified { background: var(--color-hint); }

.nav-row {
  padding: 0 var(--spacing) 10px;
}

.vehicle-list {
  display: flex;
  flex-direction: column;
  padding: 0 var(--spacing) 24px;
}

/* Section header for each vehicle-type group (Cars / Motorcycles / Scooters) */
.vehicle-group-header {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--color-hint);
  padding: 14px 2px 4px;
}

.vehicle-group-header:first-child {
  padding-top: 2px;
}

.vehicle-group-header__count {
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
}

.vehicle-item {
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--color-bg-secondary);
  border-radius: var(--border-radius);
  padding: 12px;
  box-shadow: var(--shadow-card);
  cursor: pointer;
  margin-bottom: 10px;
  border-left: 4px solid transparent;
}

/* Whole-card accent reflecting the vehicle's rental status, using the same
   four-color scheme as the Rental Calendar (green/blue/yellow/red). A left
   border (rather than a filled background) keeps this readable alongside
   the type-color thumbnail border and the two status-icon dots. */
.vehicle-item--rental-green { border-left-color: var(--color-green); }
.vehicle-item--rental-blue { border-left-color: var(--color-blue); }
.vehicle-item--rental-yellow { border-left-color: var(--color-yellow); background: var(--color-yellow-bg); }
.vehicle-item--rental-red { border-left-color: var(--color-red); background: var(--color-red-bg); }

.vehicle-item:active {
  transform: scale(0.98);
}

.vehicle-item__thumb {
  width: 52px;
  height: 52px;
  border-radius: var(--border-radius-sm);
  background: var(--color-bg);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  overflow: hidden; /* clip any oversized content instead of letting it push the layout */
  border: 2px solid transparent;
}

/* Distinct accent border per vehicle type so Cars/Motorcycles/Scooters read
   apart from each other even before checking the group header — previously
   both two-wheeler types rendered as the same red thumbnail. */
.vehicle-item__thumb--car { border-color: var(--color-red); }
.vehicle-item__thumb--moto { border-color: #1c1c1e; }
.vehicle-item__thumb--scooter { border-color: var(--color-yellow); }

/* The thumbnail <img> itself must be explicitly constrained to its parent's
   size — without this rule the image renders at its natural resolution and
   balloons over the entire list (the bug seen in production). */
.vehicle-item__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.vehicle-item__info {
  flex: 1;
  min-width: 0;
}

.vehicle-item__title {
  font-weight: 700;
  font-size: 15px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.vehicle-item__meta {
  font-size: 12px;
  color: var(--color-hint);
  margin-top: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.vehicle-item__rental-status {
  display: flex;
  align-items: center;
  font-size: 11px;
  color: var(--color-hint);
  margin-top: 3px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Two independent status icons (maintenance, damage) shown side by side —
   deliberately separate from each other so a vehicle needing an oil change
   but otherwise undamaged doesn't read as "something's wrong" the same way
   a vehicle with critical body damage does, and vice versa. */
.vehicle-item__status-icons {
  display: flex;
  flex-direction: column;
  gap: 4px;
  align-items: center;
  flex-shrink: 0;
}

.status-icon-dot {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  flex-shrink: 0;
}

.status-icon-dot--green { background: var(--color-green-bg); }
.status-icon-dot--yellow { background: var(--color-yellow-bg); }
.status-icon-dot--red { background: var(--color-red-bg); }

.status-dot {
  display: inline-block;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  margin-right: 6px;
  flex-shrink: 0;
}

.status-dot--green { background: var(--color-green); }
.status-dot--blue { background: var(--color-blue); }
.status-dot--yellow { background: var(--color-yellow); }
.status-dot--red { background: var(--color-red); }

.badge {
  font-size: 10px;
  font-weight: 700;
  padding: 3px 8px;
  border-radius: 20px;
  white-space: nowrap;
}

.badge--red { background: var(--color-red-bg); color: var(--color-red); }
.badge--yellow { background: var(--color-yellow-bg); color: var(--color-yellow); }

.empty-state {
  text-align: center;
  padding: 32px;
  color: var(--color-hint);
}


/* ==========================================================================
   6. КАРТОЧКА ТЕХНИКИ
   ========================================================================== */

.card-scroll {
  flex: 1;
  overflow-y: auto;
  padding: var(--spacing);
}

/* Editor action row: three equal-width buttons (Update / Inspect / TO Done)
   sitting below the scrollable card content as a normal flex-column
   sibling — not an overlay — so it doesn't need to reserve scroll padding
   the way the old single sticky button did. */
.card-action-row {
  display: flex;
  gap: 8px;
  padding: 10px var(--spacing);
  padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 10px);
  flex-shrink: 0;
  background: var(--color-bg-secondary);
  box-shadow: 0 -1px 3px rgba(0, 0, 0, 0.06);
}

.card-action-row .btn {
  flex: 1;
  padding-left: 8px;
  padding-right: 8px;
  font-size: 13px;
  white-space: nowrap;
}

.card-photo-strip {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  margin-bottom: 16px;
  padding-bottom: 4px;
}

.card-photo-strip img {
  width: 96px;
  height: 96px;
  border-radius: var(--border-radius-sm);
  object-fit: cover;
  flex-shrink: 0;
  background: var(--color-bg-secondary);
}

.card-title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 4px;
}

.card-title {
  font-size: 20px;
  font-weight: 800;
}

.card-subtitle {
  color: var(--color-hint);
  font-size: 14px;
  margin-bottom: 16px;
}

.info-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-bottom: 20px;
}

.info-tile {
  background: var(--color-bg-secondary);
  border-radius: var(--border-radius-sm);
  padding: 10px 12px;
  box-shadow: var(--shadow-card);
}

.info-tile__label {
  font-size: 11px;
  color: var(--color-hint);
  text-transform: uppercase;
}

.info-tile__value {
  font-size: 15px;
  font-weight: 700;
  margin-top: 2px;
}

.section-title {
  font-size: 15px;
  font-weight: 700;
  margin: 20px 0 10px;
}

.history-item {
  background: var(--color-bg-secondary);
  border-radius: var(--border-radius-sm);
  padding: 10px 12px;
  margin-bottom: 8px;
  box-shadow: var(--shadow-card);
  font-size: 13px;
}

.history-item__date {
  color: var(--color-hint);
  font-size: 11px;
  margin-bottom: 4px;
}

.comment-box {
  background: var(--color-yellow-bg);
  border-radius: var(--border-radius-sm);
  padding: 12px;
  font-size: 13px;
  margin-bottom: 20px;
}


/* ==========================================================================
   7. ФОРМА ОБНОВЛЕНИЯ СОСТОЯНИЯ
   ========================================================================== */

.form-scroll {
  flex: 1;
  overflow-y: auto;
  padding: var(--spacing);
  padding-bottom: 32px;
}

.faults-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
}

.fault-chip {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--color-bg-secondary);
  border: 1px solid rgba(0, 0, 0, 0.08);
  border-radius: var(--border-radius-sm);
  padding: 10px 12px;
  cursor: pointer;
  min-height: 44px;
}

.fault-chip input {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

.fault-chip--checked {
  border-color: var(--color-button);
  background: var(--color-blue-bg);
}

.photo-preview {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 10px;
}

.photo-preview img {
  width: 64px;
  height: 64px;
  border-radius: var(--border-radius-sm);
  object-fit: cover;
}

#btn-save-update, #btn-save-inspection {
  margin-top: 24px;
}


/* ==========================================================================
   8. ИНВЕНТАРИЗАЦИЯ
   ========================================================================== */

.inspection-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: var(--color-bg-secondary);
  border-radius: var(--border-radius);
  padding: 14px;
  margin-bottom: 10px;
  box-shadow: var(--shadow-card);
  cursor: pointer;
}

.inspection-item--done {
  opacity: 0.5;
}

.inspection-item__check {
  font-size: 20px;
}


/* ==========================================================================
   8.5. RENTAL CALENDAR SCREEN — read-only rental summary display
   ========================================================================== */

.rental-summary {
  background: var(--color-bg-secondary);
  border-radius: var(--border-radius-sm);
  padding: 10px 12px;
  margin-bottom: 8px;
  box-shadow: var(--shadow-card);
  font-size: 13px;
  border-left: 4px solid var(--color-blue);
}

.rental-summary--ending-soon {
  border-left-color: var(--color-yellow);
}

.rental-summary--expired {
  border-left-color: var(--color-red);
}

.rental-summary__vehicle {
  font-weight: 700;
  font-size: 14px;
  margin-bottom: 4px;
}

.rental-summary__dates {
  color: var(--color-hint);
  font-size: 12px;
}

.rental-summary__tenant {
  font-size: 12px;
  margin-top: 2px;
}

/* ==========================================================================
   8.5b. RENTAL GANTT CHART (screen-rental-calendar)
   ========================================================================== */

/* --- Design constants (kept in one place; referenced by app.js via
   GANTT_CONFIG so the JS and CSS never drift apart) ---
   Row height: 52px | Day column width: 36px | Label column width: 148px */

.gantt-toolbar {
  padding: 10px var(--spacing);
  flex-shrink: 0;
}

.gantt-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.gantt-legend__item {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  color: var(--color-hint);
}

.gantt-legend__swatch {
  width: 12px;
  height: 12px;
  border-radius: 3px;
  flex-shrink: 0;
  display: inline-block;
}

/* --- Scroll container: the ONE element that scrolls in both directions.
   Sticky header/column live inside it, which is what keeps both axes
   scrolling together natively (no JS scroll-sync, no jank at 100+ rows). --- */
.gantt-scroll {
  flex: 1;
  overflow: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  background: var(--color-bg);
  /* Isolates the whole Gantt subtree (which can be 2000+ DOM nodes at
     300 vehicles) from the rest of the document during layout, so
     scrolling this container never triggers a layout pass over
     unrelated parts of the page. */
  contain: layout style;
}

/* .gantt-inner holds two stacked flex rows: the sticky header row (corner +
   date header) and the content row (sticky label column + scrollable body).
   Both the corner and the label column pin themselves horizontally via
   `position: sticky; left: 0`; the header row additionally pins itself
   vertically via `position: sticky; top: 0`. Because everything lives
   inside the single .gantt-scroll scroll container, the browser keeps all
   of this in sync natively — no JS scroll-position mirroring needed, which
   is what keeps this smooth with 100-300+ rows. */
.gantt-inner {
  display: flex;
  flex-direction: column;
  /* width set inline by app.js based on day count */
}

.gantt-header-row {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  flex-shrink: 0;
  /* Promote to its own compositor layer so the browser can reposition it
     on scroll via GPU transform alone, without repainting its contents
     (180 date cells). Without this hint, some WebViews (notably the
     Android WebView Telegram's Mini App runs in) repaint this whole wide
     row on every vertical scroll frame even though only its position
     changes — that repaint cost was the actual cause of vertical-scroll
     jank. Horizontal scrolling never triggers sticky-top repositioning,
     which is why only the vertical direction was affected. translateZ(0)
     is added alongside will-change as a fallback: some older
     Chromium/Android WebView builds honor it more reliably.
     Note: `contain` is deliberately NOT used here — contain on a
     position:sticky element itself is inconsistently supported across
     WebView engines and can interfere with sticky positioning; layer
     promotion via will-change/transform is the safer, well-supported
     technique for this specific element. */
  will-change: transform;
  transform: translateZ(0);
}

/* Top-left corner cell: pinned on both axes via double sticky (sticky
   top from the parent header row's stacking, sticky left of its own) */
.gantt-corner {
  position: sticky;
  left: 0;
  z-index: 2;
  width: 148px;
  height: 52px;
  flex-shrink: 0;
  background: var(--color-bg-secondary);
  box-shadow: var(--shadow-card);
  display: flex;
  align-items: center;
  padding: 0 12px;
  font-size: 11px;
  font-weight: 700;
  color: var(--color-hint);
  text-transform: uppercase;
  will-change: transform;
  transform: translateZ(0);
}

/* Date header row: part of the sticky header-row, scrolls horizontally
   along with the rest of the row's natural content flow */
.gantt-header {
  display: flex;
  background: var(--color-bg-secondary);
  box-shadow: var(--shadow-card);
  height: 52px;
  flex-shrink: 0;
  contain: layout style paint;
}

.gantt-header__day {
  width: 36px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: 10px;
  color: var(--color-hint);
  border-right: 1px solid rgba(0, 0, 0, 0.05);
}

.gantt-header__day--weekend {
  background: rgba(0, 0, 0, 0.035);
}

.gantt-header__day--today {
  background: var(--color-blue-bg);
  color: var(--color-blue);
  font-weight: 700;
}

.gantt-header__day-num {
  font-size: 13px;
  font-weight: 700;
  color: var(--color-text);
}

.gantt-header__day--today .gantt-header__day-num {
  color: var(--color-blue);
}

.gantt-header__month-label {
  font-size: 10px;
  font-weight: 700;
  color: var(--color-hint);
  padding: 4px 0 0 4px;
  white-space: nowrap;
}

/* Content row: holds the sticky label column + the scrollable body,
   side by side, below the sticky header row */
.gantt-content-row {
  display: flex;
  position: relative;
}

/* Vehicle label column: pinned to the left (horizontal axis only — it
   scrolls normally with the vertical axis, it just re-sticks horizontally).
   will-change/translateZ here matter because up to 300 text rows live
   inside this element; without a compositing hint, some WebViews repaint
   the whole column on every vertical scroll tick even though sticky is
   only active on the other axis. `contain` is deliberately avoided on this
   sticky element itself for the same reason noted on .gantt-header-row. */
.gantt-label-col {
  position: sticky;
  left: 0;
  z-index: 10;
  width: 148px;
  flex-shrink: 0;
  background: var(--color-bg-secondary);
  box-shadow: 2px 0 4px rgba(0, 0, 0, 0.06);
  will-change: transform;
  transform: translateZ(0);
}

.gantt-label {
  height: 52px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 0 12px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.06);
  cursor: pointer;
}

/* Group-header row (Cars / Motorcycles / Scooters) within the label column.
   Keeps the same 52px height as a regular .gantt-label — this must stay in
   lockstep with .gantt-row--group-header in the body, since both are built
   from the same shared rowItems list (see buildGanttRowItems) and any
   height mismatch here would shift every bar out of alignment with its
   vehicle's label below this point. */
.gantt-label--group {
  flex-direction: row;
  align-items: center;
  gap: 8px;
  background: var(--color-bg);
  cursor: default;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--color-hint);
}

.gantt-label--group .gantt-label__title {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--color-hint);
}

.gantt-label:active {
  background: rgba(0, 0, 0, 0.04);
}

.gantt-label__title {
  font-size: 12px;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.gantt-label__meta {
  font-size: 10px;
  color: var(--color-hint);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-top: 1px;
}

/* Body: rows of day cells behind which the rental bars are absolutely
   positioned. Built as one flex row per vehicle to keep markup simple and
   fast to generate even for 300 rows. */
.gantt-body {
  position: relative;
  flex: 1;
  /* Isolates this (potentially 300-row) subtree's layout/paint from the
     rest of the page, so the browser doesn't need to re-evaluate it as
     part of a larger scroll-driven layout pass. */
  contain: layout style;
  /* background-image / background-size for the day-separator lines and
     weekend striping are set inline by app.js (buildGanttGridBackground),
     applied once here rather than duplicated on every .gantt-row — see the
     comment in renderGanttBody (app.js) for why that single-application
     approach is what keeps scrolling smooth at 100-300+ vehicle rows. */
}

.gantt-row {
  height: 52px;
  display: flex;
  position: relative;
  border-bottom: 1px solid rgba(0, 0, 0, 0.06);
}

.gantt-row:nth-child(even) {
  background-color: rgba(0, 0, 0, 0.015);
}

/* Group-header row on the body side — must stay exactly 52px, matching
   .gantt-label--group, so vehicle rows below it stay aligned with their
   labels. background-color is opaque so it visually covers the parent
   .gantt-body's shared grid-line/weekend background for this one row,
   making the divider read as a flat, distraction-free band. */
.gantt-row--group-header {
  background-color: var(--color-bg);
}

/* Rental bars: absolutely positioned over the row, left/width computed in
   app.js from the rental's start/end date relative to the visible range. */
.gantt-bar {
  position: absolute;
  top: 9px;
  height: 34px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  padding: 0 8px;
  font-size: 11px;
  font-weight: 700;
  color: #fff;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
}

.gantt-bar--active {
  background: var(--color-blue);
}

.gantt-bar--ending-soon {
  background: var(--color-yellow);
}

.gantt-bar--upcoming {
  background: var(--color-green);
}

.gantt-bar--expired {
  background: var(--color-red);
  opacity: 0.75;
}

/* "Today" indicator: a vertical line spanning the full height of the chart
   body, positioned absolutely by app.js at the current day's x-offset. */
.gantt-today-line {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--color-button);
  z-index: 5;
  pointer-events: none;
}

.gantt-today-line::before {
  content: '';
  position: absolute;
  top: -6px;
  left: 50%;
  transform: translateX(-50%);
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-button);
}

.gantt-empty-state {
  padding: 32px;
  text-align: center;
  color: var(--color-hint);
}


/* ==========================================================================
   8.6. PHOTO LIGHTBOX (fullscreen viewer with zoom/pan)
   ========================================================================== */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 2000;
  background: rgba(0, 0, 0, 0.94);
  display: none;
  flex-direction: column;
  /* touch-action is set per-element below; this just prevents the page
     behind the lightbox from scrolling while it's open */
  overscroll-behavior: contain;
}

.lightbox--visible {
  display: flex;
}

.lightbox__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px;
  /* Push the header down out of Telegram's own WebView title bar / close
     button area. env(safe-area-inset-top) covers notches/rounded corners;
     the extra fixed offset covers Telegram's own chrome, which isn't
     reported as a safe-area inset but still occupies the top of the
     viewport and overlaps anything placed at padding-top:14px alone —
     that overlap was the original bug (tapping here hit Telegram's own
     close control instead of ours). */
  padding-top: calc(env(safe-area-inset-top, 0px) + 56px);
  flex-shrink: 0;
  z-index: 1;
}

.lightbox__close {
  color: #fff;
  font-size: 22px;
}

.lightbox__close:active {
  background: rgba(255, 255, 255, 0.12);
}

/* Redundant bottom exit control — the primary, unmistakable way to leave
   the viewer. Sits in the bottom safe zone, styled like every other
   sticky primary action in the app for visual consistency. */
.lightbox__close-bottom {
  flex-shrink: 0;
  margin: 12px 16px calc(env(safe-area-inset-bottom, 0px) + 12px);
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.18);
}

.lightbox__close-bottom:active {
  background: rgba(255, 255, 255, 0.2);
}

.lightbox__counter {
  color: rgba(255, 255, 255, 0.8);
  font-size: 13px;
  font-weight: 600;
}

.lightbox__viewport {
  flex: 1;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  /* We handle pinch-zoom and panning ourselves via JS (pointer events), so
     the browser's own touch gestures (scroll/zoom) must be disabled here —
     otherwise they fight with our transform-based zoom. */
  touch-action: none;
  cursor: grab;
}

.lightbox__viewport:active {
  cursor: grabbing;
}

.lightbox__image {
  max-width: 100%;
  max-height: 100%;
  -webkit-user-select: none;
  user-select: none;
  pointer-events: none; /* the viewport (parent) handles all gestures */
  will-change: transform;
  transform-origin: 0 0;
}

.lightbox__nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  font-size: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 1;
}

.lightbox__nav:active {
  background: rgba(255, 255, 255, 0.24);
}

.lightbox__nav--prev {
  left: 10px;
}

.lightbox__nav--next {
  right: 10px;
}

.lightbox__nav.hidden {
  display: none;
}


/* ==========================================================================
   9. ТОСТ-УВЕДОМЛЕНИЯ
   ========================================================================== */

.toast {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%) translateY(20px);
  background: #1c1c1e;
  color: #fff;
  padding: 12px 20px;
  border-radius: 30px;
  font-size: 13px;
  font-weight: 600;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease;
  z-index: 1000;
  max-width: 90%;
  text-align: center;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.3);
}

.toast.toast--visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

.toast--error {
  background: var(--color-red);
}

.toast--success {
  background: var(--color-green);
}


/* ==========================================================================
   10. АДАПТИВНОСТЬ
   ========================================================================== */

/* Планшеты и десктоп: ограничиваем ширину контента, центрируем как "телефон" */
@media (min-width: 600px) {
  body {
    display: flex;
    justify-content: center;
    background: #d9dbe0;
  }

  .screen {
    max-width: 480px;
    width: 100%;
    min-height: 100vh;
    background: var(--color-bg);
    box-shadow: 0 0 40px rgba(0, 0, 0, 0.15);
  }
}

/* Очень маленькие экраны: чуть уменьшаем отступы */
@media (max-width: 340px) {
  :root {
    --spacing: 12px;
  }

  .stats-grid {
    grid-template-columns: 1fr 1fr;
    gap: 8px;
  }

  .stat-card__value {
    font-size: 22px;
  }
}
