feat: theme switching system — 4 palettes (ZOV · Foundry · Boardroom · Atelier)

- styles.css v5: replaced old 3-variant system with 4 design-token themes
  extracted from reference dashboards:
  · brand (ЗОВ): #003E7E blue / #76BD22 green, Inter
  · b Foundry: #EFE9D8 cream / #B68A1A mustard, Archivo, sharp corners
  · c Boardroom: #F2E9D6 linen / #D08A55 copper, Geist, petrol tones
  · d Atelier: #E9EBEF dove / #2E5266 steel-blue, Manrope
  Each theme: --paper, --ink, --accent-*, --status-*, --r-*, --font-ui, --warm
- app.js: applyVariant() + savedVariant() helpers with localStorage persistence;
  renderPaletteSwitcher() component (color swatches + name label);
  injected in renderManagerHome + renderStaff; setupTelegram() restores saved variant
- index.html: added Archivo + Manrope to Google Fonts; cache-bust v20260517a
- podbor.css: .role-card .role-icon uses color: var(--accent-1) (was hardcoded walnut);
  SVG strokes switched to currentColor for theme-awareness

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
wasrusgen 2026-05-16 12:17:54 +03:00
parent 5fafdc35fb
commit db6c4f3265
4 changed files with 354 additions and 176 deletions

View File

@ -9,12 +9,35 @@ const BACKEND_URL = "https://api.wasrusgen1.pro";
const app = document.getElementById("app");
/* ----------------- Theme / variant helpers ----------------- */
const THEME_KEY = "zov_variant";
const THEMES = [
{ id: "", name: "ЗОВ", dotA: "#003E7E", dotB: "#76BD22", outline: false },
{ id: "b", name: "Foundry", dotA: "#15140F", dotB: "#B68A1A", outline: false },
{ id: "c", name: "Boardroom",dotA: "#0E2A2E", dotB: "#D08A55", outline: false },
{ id: "d", name: "Atelier", dotA: "#2E5266", dotB: "#E9EBEF", outline: true },
];
function applyVariant(id) {
const html = document.documentElement;
if (id) {
html.setAttribute("data-variant", id);
} else {
html.removeAttribute("data-variant");
}
try { localStorage.setItem(THEME_KEY, id); } catch(e) {}
}
function savedVariant() {
try { return localStorage.getItem(THEME_KEY) ?? ""; } catch(e) { return ""; }
}
/* ----------------- Telegram WebApp setup ----------------- */
function setupTelegram() {
const scheme = tg?.colorScheme || (window.matchMedia?.("(prefers-color-scheme: dark)").matches ? "dark" : "light");
document.documentElement.setAttribute("data-theme", scheme);
// Зафиксирован вариант A — Editorial Calm
document.documentElement.setAttribute("data-variant", "a");
// Восстанавливаем тему из localStorage (по умолч. — brand)
applyVariant(savedVariant());
if (!tg) return;
try {
@ -36,6 +59,38 @@ function haptic(type = "selection") {
} catch (e) {}
}
/* ----------------- Palette switcher UI ----------------- */
function renderPaletteSwitcher() {
const current = savedVariant();
const wrap = el(`<div class="palette-switcher"></div>`);
// Маленький ярлык слева
const lbl = el(`<span class="palette-switcher__label">Тема</span>`);
wrap.appendChild(lbl);
THEMES.forEach(t => {
const btn = el(`
<button class="ps-btn${current === t.id ? " active" : ""}" title="${t.name}">
<span class="ps-swatches">
<span class="ps-dot${t.outline ? " ps-dot--outline" : ""}" style="background:${t.dotA}"></span>
<span class="ps-dot${t.outline ? " ps-dot--outline" : ""}" style="background:${t.dotB}"></span>
</span>
<span class="ps-name">${t.name}</span>
</button>
`);
btn.addEventListener("click", () => {
haptic();
applyVariant(t.id);
// Перерисовываем все кнопки
wrap.querySelectorAll(".ps-btn").forEach((b, i) => {
b.classList.toggle("active", THEMES[i].id === t.id);
});
});
wrap.appendChild(btn);
});
return wrap;
}
/* ----------------- Data ----------------- */
async function fetchMe() {
if (!BACKEND_URL) {
@ -122,6 +177,9 @@ async function renderManagerHome(me) {
app.innerHTML = "";
document.body.classList.add("has-bottom-nav");
// Palette (theme) switcher — вверху экрана
app.appendChild(renderPaletteSwitcher());
// Greeting + bell (placeholder)
const greetingEl = el(`
<header class="greeting">
@ -683,7 +741,7 @@ function renderRoleChooser() {
<div class="role-cards">
<button class="role-card" data-role="manager">
<div class="role-icon">
<svg viewBox="0 0 24 24" width="40" height="40" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="#6B4A2B" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<svg viewBox="0 0 24 24" width="40" height="40" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<path d="M8 7a4 4 0 1 0 8 0a4 4 0 0 0 -8 0"/>
<path d="M6 21v-2a4 4 0 0 1 4 -4h.5"/>
<path d="M17.8 20.817l-2.172 1.138a.392 .392 0 0 1 -.568 -.41l.415 -2.411l-1.757 -1.707a.389 .389 0 0 1 .217 -.665l2.428 -.352l1.086 -2.193a.392 .392 0 0 1 .702 0l1.086 2.193l2.428 .352a.39 .39 0 0 1 .217 .665l-1.757 1.707l.414 2.41a.39 .39 0 0 1 -.567 .411z"/>
@ -697,7 +755,7 @@ function renderRoleChooser() {
</button>
<button class="role-card" data-role="client">
<div class="role-icon">
<svg viewBox="0 0 24 24" width="40" height="40" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="#6B4A2B" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<svg viewBox="0 0 24 24" width="40" height="40" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<path d="M5 12l-2 0l9 -9l9 9l-2 0"/>
<path d="M5 12v7a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-7"/>
<path d="M10 12h4v4h-4l0 -4"/>
@ -711,7 +769,7 @@ function renderRoleChooser() {
</button>
<button class="role-card" data-role="staff">
<div class="role-icon">
<svg viewBox="0 0 24 24" width="40" height="40" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="#6B4A2B" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<svg viewBox="0 0 24 24" width="40" height="40" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 21h4l13 -13a1.5 1.5 0 0 0 -4 -4l-13 13v4"/>
<path d="M14.5 5.5l4 4"/>
<path d="M12 8l-5 -5l-4 4l5 5"/>
@ -790,6 +848,8 @@ async function renderStaff(me) {
</div>
`));
app.appendChild(renderPaletteSwitcher());
// Загружаем заявки и рендерим: week strip + сгруппированный инбокс
const stripPlaceholder = el(`<div id="weekStrip"></div>`);
const inboxSection = el(`

View File

@ -1,5 +1,5 @@
/* ============================================================
Подбор техники стили (Editorial Calm)
/* ============================================================
РџРѕРґР±РѕСЂ СРµСРЅРёРєРё †сСили (Editorial Calm)
============================================================ */
/* ----- Header ----- */
@ -63,7 +63,7 @@
.podbor-progress-meta .num { color: var(--ink); }
/* ----- Лента категорий ----- */
/* ----- Лента категорий ----- */
.cat-strip {
display: flex;
gap: 6px;
@ -310,7 +310,7 @@
min-width: 0;
}
.niche-inputs input {
min-width: 0; /* критично — иначе input не даёт колонке сжиматься */
min-width: 0; /* критично — иначе input не даёт колонке сжиматься */
width: 100%;
font-family: var(--font-mono);
font-size: 12.5px;
@ -334,7 +334,7 @@
text-align: right; color: var(--ink);
}
/* ----- Price range (от — до по категориям) ----- */
/* ----- Price range (РѕС вЂ” РґРѕ РїРѕ категориям) ----- */
.price-list { display: flex; flex-direction: column; gap: var(--s3); }
.price-row {
@ -425,8 +425,8 @@
}
/* ----- Brand chips ----- */
/* Тиры (Premium/Middle/Budget) различаются цветом, без явных текстовых ярлыков.
Внутренне храним tier для аналитики «температуры» клиента. */
/* РўРёСЂС (Premium/Middle/Budget) разлиСаюССЃСЏ СРІРµСРѕРј, без СЏРІРЅСС СексСРѕРІСС СЏСЂР»СРєРѕРІ.
РРЅСѓСренне Сраним tier для аналиСРёРєРё В«СемпераССѓСЂСВ» клиенСР°. */
.brand-chips {
display: flex;
@ -453,7 +453,7 @@
position: relative;
}
/* Базовый цвет покоя по тирам — без слов, только тёплый/холодный оттенок */
/* Базовый цвет покоя по тирам — без слов, только тёплый/холодный оттенок */
.chip.tier-premium {
background: var(--paper);
color: var(--accent-2); /* walnut */
@ -472,7 +472,7 @@
border-color: var(--line);
}
/* Состояние preferred — заливка цветом тира */
/* Состояние preferred — заливка цветом тира */
.chip.tier-premium.status-preferred {
background: var(--accent-2); /* walnut */
color: var(--paper);
@ -494,9 +494,9 @@
font-weight: 600;
}
.chip.status-preferred::before { content: " "; }
.chip.status-preferred::before { content: "★ "; }
/* Состояние acceptable — обводка цветом тира, прозрачная заливка */
/* Состояние acceptable — обводка цветом тира, прозрачная заливка */
.chip.status-acceptable {
background: var(--paper-2);
}
@ -505,9 +505,9 @@
.chip.tier-middle.status-acceptable { border-color: var(--ink); color: var(--ink); }
.chip.tier-budget.status-acceptable { border-color: var(--muted); color: var(--ink-2); }
.chip.status-acceptable::before { content: " "; }
.chip.status-acceptable::before { content: "вњ“ "; }
/* Состояние avoid — приглушённый, перечёркнутый */
/* Состояние avoid — приглушённый, перечёркнутый */
.chip.status-avoid {
background: #F5E1DC;
border-color: #C7705A;
@ -515,9 +515,9 @@
text-decoration: line-through;
opacity: 0.85;
}
.chip.status-avoid::before { content: " "; text-decoration: none; display: inline-block; }
.chip.status-avoid::before { content: "вњ— "; text-decoration: none; display: inline-block; }
/* Disabled кнопка */
/* Disabled РєРЅРѕРїРєР° */
.btn-primary[disabled],
.btn-secondary[disabled] {
opacity: 0.4;
@ -639,7 +639,7 @@
.empty { text-align: center; color: var(--muted); padding: var(--s7) 0; }
/* ============================================================
Detail menu list of categories with status
Detail menu †list of categories with status
============================================================ */
.detail-list {
display: flex;
@ -774,7 +774,7 @@
}
/* ============================================================
Accordion "Подробнее"
Accordion "Подробнее"
============================================================ */
.accordion-head {
display: flex;
@ -886,7 +886,7 @@
.feature.on .feature-tick svg { width: 12px; height: 12px; stroke-width: 2.5; }
/* ============================================================
Иерархический wizard (новая схема steps[])
ИерарСРёСескиРwizard (новая СЃСема steps[])
============================================================ */
.podbor-wizard { gap: var(--s4); }
@ -933,7 +933,7 @@
}
.wiz-cat-icon svg { width: 22px; height: 22px; }
/* Чипы прошлых ответов */
/* Чипы прошлых ответов */
.wiz-chips {
display: flex;
flex-wrap: wrap;
@ -956,7 +956,7 @@
}
.wiz-chip:active { background: #EAD9B6; }
/* Заголовок шага */
/* Заголовок шага */
.wiz-title {
font-family: var(--font-display);
font-style: italic;
@ -977,7 +977,7 @@
color: var(--muted);
}
/* Сетка карточек (cards-режим — с пиктограммами) */
/* Сетка карточек (cards-режим — с пиктограммами) */
.wiz-grid { gap: 10px; }
.wiz-grid--cards {
display: grid;
@ -987,7 +987,7 @@
.wiz-grid--cards { grid-template-columns: repeat(3, 1fr); }
}
/* Пин-режим (без пиктограмм, компактные таблетки) */
/* Пин-режим (без пиктограмм, компактные таблетки) */
.wiz-grid--pins {
display: flex;
flex-wrap: wrap;
@ -1017,7 +1017,7 @@
box-shadow: 0 0 0 1px var(--accent-2) inset;
}
.wiz-card.star::before {
content: "";
content: "в­ђ";
position: absolute;
top: 6px;
left: 8px;
@ -1071,7 +1071,7 @@
}
.wiz-tick svg { width: 11px; height: 11px; stroke-width: 2.5; }
/* Пин-карточка (компактная таблетка, без пиктограммы) */
/* Пин-карточка (компактная таблетка, без пиктограммы) */
.wiz-card--pin {
display: inline-flex;
align-items: center;
@ -1106,7 +1106,7 @@
.wiz-card--pin.star { padding-left: 26px; }
.wiz-card--pin.star::before { top: 50%; transform: translateY(-50%); }
/* Review-экран */
/* Review-экран */
.rev-list {
background: #fff;
border: 1px solid var(--line);
@ -1148,7 +1148,7 @@
.rev-val .muted { color: var(--muted); font-weight: 400; }
/* ============================================================
Inline-отчёт после отправки подбора
Inline-РѕСССС РїРѕСЃР»Рµ РѕСправки РїРѕРґР±РѕСЂР°
============================================================ */
.report {
@ -1241,7 +1241,7 @@
background: repeating-linear-gradient(45deg, var(--warm), var(--warm) 5px, #F0E8D5 5px, #F0E8D5 10px);
}
.report-model-img.placeholder::after {
content: "📷";
content: "рџ“·";
font-size: 24px;
opacity: 0.4;
}
@ -1315,7 +1315,7 @@
margin-top: 2px;
}
/* Блоки плюсов/минусов с маркированными списками */
/* Блоки плюсов/минусов с маркированными списками */
.report-pros-block, .report-cons-block {
margin-top: 8px;
padding: 8px 10px;
@ -1359,7 +1359,7 @@
color: var(--walnut);
}
/* Технические характеристики */
/* Технические характеристики */
.report-specs {
margin-top: 10px;
background: #FFFCF6;
@ -1413,7 +1413,7 @@
color: var(--accent-2);
}
/* Утилитарные ссылки — инструкция, схема установки */
/* Утилитарные ссылки — инструкция, схема установки */
.report-util-links {
display: flex;
flex-wrap: wrap;
@ -1470,7 +1470,7 @@
margin-top: 8px;
}
/* Цветовая дифференциация бейджей магазинов */
/* Цветовая дифференциация бейджей магазинов */
.report-link--ozon { border-color: #0044CC; color: #0044CC; }
.report-link--citilink { border-color: #FFBA00; color: #B57E00; }
.report-link--wb { border-color: #CB11AB; color: #CB11AB; }
@ -1499,7 +1499,7 @@
.report-link:active { background: var(--warm); }
/* ============================================================
Матрица цен по магазинам (PRIMARY view категории)
РњР°ССЂРёСР° Сен РїРѕ магазинам (PRIMARY view РєР°Сегории)
============================================================ */
.report-matrix-wrap {
@ -1640,7 +1640,7 @@
border-top: 1px dashed var(--line);
}
/* Сравнительная таблица — accordion (legacy, оставлен для совместимости) */
/* Сравнительная таблица — accordion (legacy, оставлен для совместимости) */
.report-compare {
background: #fff;
border: 1px solid var(--line);
@ -1664,7 +1664,7 @@
}
.report-compare summary::-webkit-details-marker { display: none; }
.report-compare summary::after {
content: "";
content: "↓";
font-size: 12px;
color: var(--muted);
transition: transform 0.2s;
@ -1694,7 +1694,7 @@
}
.report-compare td strong { font-weight: 600; color: var(--ink); }
/* Итого */
/* ИСРѕРіРѕ */
.report-total {
padding: 14px 16px;
background: var(--ink);
@ -1740,7 +1740,7 @@
}
.report-warnings > div { margin: 2px 0; }
/* Экспорт отчёта */
/* Экспорт отчёта */
.report-export {
margin-top: 16px;
padding: 16px;
@ -1791,7 +1791,7 @@
}
/* ============================================================
Клиенты список + история
КлиенСС вЂ СЃРїРёСЃРѕРє + РёСЃСРѕСЂРёСЏ
============================================================ */
.client-list {
@ -1799,11 +1799,11 @@
flex-direction: column;
gap: 8px;
margin-top: 8px;
/* отступ чтобы FAB не перекрывал последний элемент */
/* отступ чтобы FAB не перекрывал последний элемент */
padding-bottom: 84px;
}
/* ── FAB «Новый клиент» ─────────────────────────────── */
/* ── FAB «Новый клиент» ─────────────────────────────── */
.clients-fab {
position: fixed;
bottom: calc(24px + env(safe-area-inset-bottom, 0px));
@ -1834,7 +1834,7 @@
}
/* ============================================================
Секция отгрузок на главном дашборде менеджера (ОТГРУЗКИ.xlsx)
СекСРёСЏ РѕСРіСЂСѓР·РѕРє РЅР° главном РґР°СР±РѕСЂРґРµ менедРера (РћРўРР РЈРКИ.xlsx)
============================================================ */
.ship-group {
@ -2044,7 +2044,7 @@
}
.client-footer .muted { color: var(--muted); }
/* Детальный экран клиента */
/* Детальный экран клиента */
.client-detail-head {
display: flex;
align-items: center;
@ -2121,7 +2121,7 @@
font-size: 18px;
}
/* Заглушка-loader */
/* Заглушка-loader */
.loader-inline {
display: flex;
justify-content: center;
@ -2153,7 +2153,7 @@
overflow-x: auto;
}
/* ===== Role chooser — первый экран ===== */
/* ===== Role chooser — первый экран ===== */
.role-chooser {
padding: 32px 18px;
max-width: 480px;
@ -2209,6 +2209,7 @@
background: var(--warm, rgba(107, 74, 43, 0.08));
border-radius: 14px;
flex-shrink: 0;
color: var(--accent-1);
}
.role-card .role-text { flex: 1; min-width: 0; }
.role-card .role-title {
@ -2230,7 +2231,7 @@
flex-shrink: 0;
}
/* ===== Бейдж номера клиента + договор ===== */
/* ===== Бейдж номера клиента + договор ===== */
.client-no-badge {
display: inline-block;
background: var(--warm, rgba(107, 74, 43, 0.10));
@ -2277,7 +2278,7 @@
}
.map-link-btn:active { background: rgba(107,74,43,0.16); }
/* ===== Опасная зона удаления ===== */
/* ===== Опасная зона удаления ===== */
.danger-zone {
border: 1px dashed rgba(192, 57, 43, 0.35);
border-radius: 10px;
@ -2308,7 +2309,7 @@
.btn-danger:active { background: #A93226; }
.btn-danger:disabled { opacity: 0.6; cursor: wait; }
/* ===== Карточка клиента: шапка + действия ===== */
/* ===== Карточка клиента: шапка + действия ===== */
.client-detail-head { position: relative; display: flex; align-items: center; gap: 14px; }
.client-call-btn {
display: grid;
@ -2325,7 +2326,7 @@
}
.client-call-btn:active { transform: scale(0.95); }
/* ===== Быстрые действия — 2×2 объёмные кнопки-карточки ===== */
/* ===== Быстрые действия — 2×2 объёмные кнопки-карточки ===== */
.client-quick-actions {
display: grid;
grid-template-columns: 1fr 1fr;
@ -2364,7 +2365,7 @@
inset 0 0 0 1px rgba(107, 74, 43, 0.10);
}
/* Круглый орехово-коричневый чип с иконкой */
/* Круглый орехово-коричневый чип с иконкой */
.qa-icon {
display: flex;
align-items: center;
@ -2385,7 +2386,7 @@
height: 22px;
}
/* Подпись под иконкой */
/* РџРѕРґРїРёСЃСЊ РїРѕРґ РёРєРѕРЅРєРѕР№ */
.qa-label {
font-size: 11.5px;
font-weight: 600;
@ -2395,7 +2396,7 @@
letter-spacing: 0.01em;
}
/* ===== Хронология клиента ===== */
/* ===== Хронология клиента ===== */
.client-timeline-block .timeline { padding: 10px 4px 4px; position: relative; }
.client-timeline-block .timeline::before {
content: "";
@ -2439,7 +2440,7 @@
.tl-icon { margin-right: 6px; }
.tl-sub { font-size: 12px; color: var(--muted, #998877); margin-top: 2px; }
/* ===== Файлы клиента ===== */
/* ===== Файлы клиента ===== */
.client-files-block .file-group { padding: 8px 4px 12px; }
.client-files-block .file-group-head {
display: flex;
@ -2474,7 +2475,7 @@
text-decoration: none;
}
/* ===== Свёрнутые детали (подборы / замеры) ===== */
/* ===== Свёрнутые детали (подборы / замеры) ===== */
.client-details { margin-top: 14px; }
.client-details-collapse {
background: var(--card, #fff);
@ -2496,7 +2497,7 @@
.client-details-collapse[open] summary { border-bottom: 1px solid rgba(107, 74, 43, 0.10); }
.client-details-collapse .leads-list { padding: 4px 8px 8px; }
/* ===== Примечание по клиенту ===== */
/* ===== Примечание по клиенту ===== */
.client-note-block .block-head {
display: flex;
align-items: center;
@ -2506,7 +2507,7 @@
flex: 1;
}
/* Кнопка-переключатель Изменить / Свернуть */
/* Кнопка-переключатель Изменить / Свернуть */
.note-edit-toggle {
padding: 4px 12px;
background: transparent;
@ -2524,7 +2525,7 @@
background: rgba(107, 74, 43, 0.10);
}
/* Лента примечаний */
/* Лента примечаний */
.note-history {
margin-top: 6px;
}
@ -2615,7 +2616,7 @@
.client-note-block .note-status.ok { color: #27AE60; }
.client-note-block .note-status.err { color: #C0392B; }
/* ===== Заявка на замер: выбор «когда удобно» ===== */
/* ===== Заявка на замер: выбор «когда удобно» ===== */
.preferred-options {
display: grid;
grid-template-columns: 1fr 1fr;
@ -2652,13 +2653,13 @@
flex: 1;
}
/* Блок «когда удобно» в карточке замерщика */
/* Блок «когда удобно» в карточке замерщика */
.preferred-block {
background: var(--warm, rgba(107, 74, 43, 0.08));
border-left: 3px solid var(--walnut, #6B4A2B);
}
/* Блок «дата назначена» */
/* Блок «дата назначена» */
.date-set-block {
background: linear-gradient(180deg, rgba(0, 62, 126, 0.04), transparent);
border-left: 3px solid var(--accent-1, #003E7E);
@ -2677,7 +2678,7 @@
margin-top: 12px;
}
/* ===== Логистика (подъезд, GPS, парковка) ===== */
/* ===== Логистика (подъезд, GPS, парковка) ===== */
.logistics-block .block-head {
display: flex;
align-items: center;
@ -2714,7 +2715,7 @@
grid-template-columns: 1fr 1fr;
}
/* ===== Замер: фото с тегами ===== */
/* ===== Замер: фото с тегами ===== */
.podbor-header .podbor-help {
background: transparent;
border: none;
@ -2778,7 +2779,7 @@
font-family: var(--font-ui, "Inter", sans-serif);
}
/* ===== Чек-лист — страница markdown ===== */
/* ===== Чек-лист — страница markdown ===== */
.checklist-page .checklist-md {
font-family: var(--font-ui, "Inter", sans-serif);
font-size: 14px;
@ -2795,7 +2796,7 @@
.checklist-md li .cl-check { position: absolute; left: 0; top: 0; font-size: 16px; color: var(--walnut, #6B4A2B); line-height: 1.3; }
.checklist-md li:has(.cl-check)::before { display: none; }
/* Активный чекбокс — кликабельный с подсветкой */
/* Активный чекбокс — кликабельный с подсветкой */
.checklist-md .cl-item {
cursor: pointer;
user-select: none;
@ -2812,7 +2813,7 @@
display: inline-block;
}
/* Прогресс-бар чек-листа */
/* Прогресс-бар чек-листа */
.checklist-progress {
position: sticky;
top: 0;
@ -2843,7 +2844,7 @@
text-align: right;
}
.checklist-md hr { margin: 18px 0; border: none; border-top: 1px dashed rgba(107, 74, 43, 0.25); }
/* Эскизы-пиктограммы в чек-листе */
/* Эскизы-пиктограммы в чек-листе */
.checklist-md .cl-pict {
margin: 14px auto;
max-width: 320px;
@ -2865,7 +2866,7 @@
.checklist-md .cl-table th, .checklist-md .cl-table td { border: 1px solid rgba(107, 74, 43, 0.18); padding: 4px 8px; text-align: left; }
.checklist-md .cl-table th { background: rgba(107, 74, 43, 0.08); font-weight: 600; }
/* ===== Главная менеджера: список «На сегодня» ===== */
/* ===== Главная менеджера: список «На сегодня» ===== */
.today-list { display: flex; flex-direction: column; gap: 6px; }
.inbox-row.overdue {
border-color: rgba(192, 57, 43, 0.35);
@ -2873,9 +2874,9 @@
}
.inbox-row.overdue .inbox-time { color: #C0392B; }
/* ===== Кабинет замерщика: week strip + grouped inbox ===== */
/* ===== Кабинет замерщика: week strip + grouped inbox ===== */
/* Week strip — загрузка по дням */
/* Week strip — загрузка по дням */
.cal-strip-block {
background: var(--card, #fff);
border: 1px solid rgba(107, 74, 43, 0.12);
@ -3040,7 +3041,7 @@
}
.inbox-call:active { background: rgba(39, 174, 96, 0.18); }
/* ===== Кабинет сотрудника (замерщик/сборщик) ===== */
/* ===== Кабинет сотрудника (замерщик/сборщик) ===== */
.staff-head {
display: flex;
align-items: center;
@ -3080,7 +3081,7 @@
font-size: 12px;
}
/* ===== Фото замера ===== */
/* ===== Фото замера ===== */
.photo-uploader { margin: 12px 0 14px; }
.photo-add-btn {
@ -3154,7 +3155,7 @@
.photo-rm:active { background: rgba(0, 0, 0, 0.75); }
.photo-tile.static { cursor: default; }
/* ===== Карточка замера (детальная страница) ===== */
/* ===== Карточка замера (детальная страница) ===== */
.measurement-detail-head {
margin-bottom: 18px;
}
@ -3183,7 +3184,7 @@
}
.measurement-kv-grid .v { color: var(--ink); }
/* ===== Кнопка "Скачать PDF" / "Печать" ===== */
/* ===== Кнопка "Скачать PDF" / "Печать" ===== */
.report-print-btn {
display: inline-flex;
align-items: center;
@ -3200,7 +3201,7 @@
}
.report-print-btn:active { background: rgba(107, 74, 43, 0.12); }
/* ===== Карточки «Замер готов — что с подбором?» на главной менеджера ===== */
/* ===== Карточки «Замер РіРѕСРѕРІ — что СЃ РїРѕРґР±РѕСЂРѕРј?В» РЅР° главной менеджера ===== */
.pending-card {
background: var(--card, #FFFFFF);
border: 1px solid var(--line, rgba(15,15,14,0.08));
@ -3267,7 +3268,7 @@
}
.pending-result:empty { display: none; }
/* ===== Загрузка DWG/чертежей замера ===== */
/* ===== Загрузка DWG/чертежей замера ===== */
.design-upload {
margin-top: 14px;
padding: 12px;
@ -3328,7 +3329,7 @@
flex-shrink: 0;
}
/* ===== Тулбар управления карточкой клиента — объёмные кнопки ===== */
/* ===== Тулбар управления карточкой клиента — объёмные кнопки ===== */
.client-toolbar {
display: grid;
grid-template-columns: 1fr 1fr;
@ -3337,7 +3338,7 @@
align-items: stretch;
}
.client-toolbar.is-locked {
grid-template-columns: 1fr; /* только «Редактировать», когда в работе */
grid-template-columns: 1fr; /* только «Редактировать», когда в работе */
}
.ct-btn {
@ -3369,7 +3370,7 @@
filter: drop-shadow(0 1px 0 rgba(0,0,0,0.18));
}
/* Edit — глубокий орех */
/* Edit — глубокий орех */
.ct-edit {
background:
linear-gradient(180deg,
@ -3393,7 +3394,7 @@
0 1px 2px rgba(0,0,0,0.10);
}
/* Delete — благородный кирпично-красный, не «алярм» */
/* Delete — благородный кирпично-красный, не «алярм» */
.ct-delete {
background:
linear-gradient(180deg,
@ -3438,9 +3439,9 @@
.ct-ok { color: #4A8016; font-weight: 500; }
.ct-err { color: #A6382A; font-weight: 500; }
/* ===== Сворачиваемые блоки (хронология и т.п.) ===== */
/* ===== Сворачиваемые блоки (хронология Рё С.Рї.) ===== */
.client-collapse {
/* убираем дефолтный маркер */
/* убираем дефолтный маркер */
}
.client-collapse > summary {
list-style: none;
@ -3465,7 +3466,7 @@
}
.client-collapse[open] .collapse-chev { transform: rotate(-90deg); }
/* ===== Сборки (Phase 4) ===== */
/* ===== РЎР±РѕСЂРєРё (Phase 4) ===== */
.assembly-list {
display: flex;
flex-direction: column;
@ -3522,7 +3523,7 @@
border-top: 1px dashed var(--line);
}
/* ===== Поиск по списку клиентов ===== */
/* ===== Поиск по списку клиентов ===== */
.client-search-wrap {
padding: 0 0 10px;
}
@ -3546,7 +3547,7 @@
.client-search::placeholder { color: var(--muted, #998877); }
.client-search-meta { transition: color 0.15s; }
/* ===== Поля адреса (addr-grid) ===== */
/* ===== Поля адреса (addr-grid) ===== */
.addr-grid {
display: grid;
grid-template-columns: 1fr 1fr;
@ -3576,7 +3577,7 @@
.geo-ok { color: #27AE60; }
.geo-warn { color: #C0392B; }
/* ===== Загрузка фото замера ===== */
/* ===== Загрузка фото замера ===== */
.photo-upload-block {}
.photo-preview-grid {
display: grid;
@ -3591,7 +3592,7 @@
.photo-upload-actions .btn-primary { flex: 2; }
.photo-upload-actions .btn-secondary { flex: 1; }
/* ===== Статус замера ===== */
/* ===== Статус замера ===== */
.mz-status-badge {
font-size: 12px;
font-weight: 600;
@ -3608,7 +3609,7 @@
.ct-ok { color: #27AE60; font-size: 13px; }
.ct-err { color: #C0392B; font-size: 13px; }
/* ===== Пикер клиента (замер) ===== */
/* ===== Пикер клиента (замер) ===== */
.client-picker-wrap { margin-bottom: 2px; }
.picker-open-btn {
width: 100%;
@ -3676,7 +3677,7 @@
}
.picker-change-btn:active { background: rgba(107,74,43,0.08); }
/* Оверлей пикера */
/* Оверлей пикера */
.client-picker-overlay {
position: fixed;
inset: 0;
@ -3764,7 +3765,7 @@
font-size: 14px;
}
/* ===== Печать / PDF ===== */
/* ===== Печать / PDF ===== */
@media print {
body { background: white !important; color: black !important; }
body.has-bottom-nav, #bottom-nav,
@ -3806,12 +3807,12 @@
.photo-tile { border: 1px solid #ccc; }
.report-matrix table { font-size: 10pt; }
a { color: black !important; text-decoration: none !important; }
/* Скрываем стрелки и иконки навигации */
/* Скрываем стрелки и иконки навигации */
.lead-arrow, .client-arrow { display: none !important; }
}
/* ============================================================
Подбор техники цикл согласования (Proposals)
РџРѕРґР±РѕСЂ СРµСРЅРёРєРё †СРёРєР» согласования (Proposals)
============================================================ */
/* ----- Common helpers ----- */
@ -4001,7 +4002,7 @@
.prop-variant-img.placeholder {
background: repeating-linear-gradient(45deg, var(--warm), var(--warm) 5px, #F0E8D5 5px, #F0E8D5 10px);
}
.prop-variant-img.placeholder::after { content: "📷"; font-size: 22px; opacity: 0.35; }
.prop-variant-img.placeholder::after { content: "рџ“·"; font-size: 22px; opacity: 0.35; }
.prop-variant-body {
display: flex;
@ -4202,8 +4203,8 @@
user-select: none;
}
.prop-brief-toggle::-webkit-details-marker { display: none; }
.prop-brief-toggle::before { content: " "; font-size: 9px; }
.prop-brief-details[open] .prop-brief-toggle::before { content: " "; }
.prop-brief-toggle::before { content: "в–¶ "; font-size: 9px; }
.prop-brief-details[open] .prop-brief-toggle::before { content: "в–ј "; }
.prop-brief-content { padding: 12px 14px; background: var(--paper); }
.brief-rows { display: flex; flex-direction: column; gap: 6px; }
.brief-row {
@ -4375,7 +4376,7 @@
.prop-section-open-link:active { opacity: 0.6; }
/* ============================================================
AI-проверка договора (Contract Review)
AI-проверка договора (Contract Review)
============================================================ */
/* Textarea + char counter */
@ -4604,3 +4605,4 @@
margin-top: 12px;
}

View File

@ -1,11 +1,22 @@
/* ============================================================
ЗОВ MiniApp design system v4
Три варианта: brand (default) · a (Editorial Calm) · c (Architectural Clean)
Переключатель `<html data-variant="a|c|brand">`, состояние в localStorage.
ЗОВ MiniApp design system v5
4 темы: brand (ЗОВ) · b (Foundry) · c (Boardroom) · d (Atelier)
Переключатель `<html data-variant="b|c|d">`, состояние в localStorage.
Палитры B/C/D извлечены из дашбордов (Figma Claude HTML).
============================================================ */
/* ===========================================================
1. BRAND (default :root) мой гибрид с палитрой ЗОВ
Общие константы не зависят от темы
=========================================================== */
:root {
--s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px;
--s5: 20px; --s6: 24px; --s7: 32px; --s8: 40px;
--font-mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
}
/* ===========================================================
1. BRAND ЗОВ (default, без data-variant)
Синий + зелёный, Inter, мягкие скругления
=========================================================== */
:root {
--paper: var(--tg-theme-bg-color, #FAFAF7);
@ -16,7 +27,7 @@
--muted: var(--tg-theme-hint-color, #6E6A62);
--muted-2: #A09C92;
--line: rgba(15, 15, 14, 0.08);
--line-strong: rgba(15, 15, 14, 0.16);
--line-strong: rgba(15, 15, 14, 0.18);
--accent-1: #003E7E; /* brand blue */
--accent-2: #76BD22; /* brand green */
@ -27,22 +38,21 @@
--r-card: 14px;
--r-btn: 12px;
--r-tag: 4px;
--r-tag: 6px;
--r-pill: 999px;
--s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px;
--s5: 20px; --s6: 24px; --s7: 32px; --s8: 40px;
--font-ui: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, system-ui, sans-serif;
--font-display: "Instrument Serif", Georgia, "Times New Roman", serif;
--font-mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
--ribbon: linear-gradient(90deg, var(--accent-1) 0%, var(--accent-2) 100%);
--warm: rgba(0, 62, 126, 0.08); /* icon bg tint */
/* palette-switch swatches */
--ps-a: #003E7E;
--ps-b: #76BD22;
}
@media (prefers-color-scheme: dark) { :root { color-scheme: dark; } }
html[data-theme="dark"]:not([data-variant="a"]):not([data-variant="c"]) {
html[data-theme="dark"]:not([data-variant]) {
--paper: var(--tg-theme-bg-color, #14130E);
--paper-2: var(--tg-theme-secondary-bg-color, #1F1D17);
--card: var(--tg-theme-section-bg-color, #1C1A14);
@ -50,77 +60,122 @@ html[data-theme="dark"]:not([data-variant="a"]):not([data-variant="c"]) {
--ink-2: #C8C3B5;
--muted: var(--tg-theme-hint-color, #A5A299);
--muted-2: #807D74;
--line: rgba(255, 255, 255, 0.10);
--line-strong: rgba(255, 255, 255, 0.20);
--line: rgba(255, 255, 255, 0.09);
--line-strong: rgba(255, 255, 255, 0.18);
}
/* ===========================================================
2. VARIANT A Editorial Calm
(палитра/шрифты дословно из мокапа)
2. VARIANT B Foundry
Тёплый крем + горчица. Archivo, острые углы.
Палитра: --paper #EFE9D8 · --ink #15140F · --accent #B68A1A
=========================================================== */
html[data-variant="a"] {
--paper: #FBF7F0;
--paper-2: #F5EDDC;
--card: #FBF7F0;
--ink: #1F1A14;
--ink-2: #8B8275;
--muted: #8B8275;
--muted-2: #9A9085;
--line: rgba(31, 26, 20, 0.18);
--line-strong: rgba(31, 26, 20, 0.40);
html[data-variant="b"] {
--paper: #EFE9D8;
--paper-2: #E2DAC1;
--card: #EAE3CC;
--ink: #15140F;
--ink-2: #2A2820;
--muted: #5C5849;
--muted-2: #8C8773;
--line: rgba(21, 20, 15, 0.10);
--line-strong: rgba(21, 20, 15, 0.22);
--accent-1: #3C5278; /* editorial blue */
--accent-2: #6B4A2B; /* walnut */
--accent-3: #B85A2D; /* terracotta */
/* Active = зелёный сигнал (бренд ЗОВ); lapsed/grace остаются в палитре A */
--status-active: #76BD22;
--status-lapsed: #B85A2D;
--status-grace: #6B4A2B;
--accent-1: #B68A1A; /* mustard / горчица */
--accent-2: #4B6B26; /* тёмно-зелёный */
--accent-3: #8B2B16; /* бордо */
--status-active: #4B6B26;
--status-lapsed: #8B2B16;
--status-grace: #B68A1A;
/* Скругления: editorial был с 0px, но пользователь хочет мягкую форму */
--r-card: 16px;
--r-btn: 12px;
--r-tag: 6px;
--r-pill: 100px;
--r-card: 4px;
--r-btn: 4px;
--r-tag: 2px;
--r-pill: 999px;
--font-ui: "Geist", "Manrope", -apple-system, system-ui, sans-serif;
--font-display: "Newsreader", "Cormorant Garamond", Georgia, serif;
--font-mono: "JetBrains Mono", ui-monospace, monospace;
--font-ui: "Archivo", -apple-system, system-ui, sans-serif;
--font-display: "Instrument Serif", Georgia, serif;
--ribbon: linear-gradient(90deg, var(--accent-1) 0%, var(--accent-2) 50%, var(--accent-3) 100%);
--ribbon: linear-gradient(90deg, #15140F 0%, #B68A1A 100%);
--warm: rgba(182, 138, 26, 0.10);
--ps-a: #EFE9D8;
--ps-b: #B68A1A;
}
/* ===========================================================
3. VARIANT C Architectural Clean
3. VARIANT C Boardroom
Петроль + медь. Geist, умеренные скругления.
Палитра: --paper #F2E9D6 · --ink #0E2A2E · --accent #D08A55
=========================================================== */
html[data-variant="c"] {
--paper: #FAFAF7;
--paper-2: #EEEAE0;
--card: #FAFAF7;
--ink: #0F0F0E;
--ink-2: #1F1A14;
--muted: #6E6A62;
--muted-2: #A09C92;
--line: rgba(15, 15, 14, 0.18);
--line-strong: rgba(15, 15, 14, 0.40);
--paper: #F2E9D6;
--paper-2: #D8CFBB;
--card: #EDE5D0;
--ink: #0E2A2E;
--ink-2: #1B3E43;
--muted: #6E7B77;
--muted-2: #9DA8A4;
--line: rgba(14, 42, 46, 0.10);
--line-strong: rgba(14, 42, 46, 0.22);
--accent-1: #3A6B44; /* blueprint green */
--accent-2: #5A3F26; /* walnut */
--accent-3: #8C3F1E;
--status-active: #3A6B44;
--status-lapsed: #8C3F1E;
--status-grace: #5A3F26;
--accent-1: #D08A55; /* copper / медь */
--accent-2: #143438; /* petrol / петроль */
--accent-3: #8B2B16;
--status-active: #7FB58A;
--status-lapsed: #E07D6C;
--status-grace: #D08A55;
--r-card: 0;
--r-btn: 0;
--r-tag: 4px;
--r-pill: 100px;
--r-card: 6px;
--r-btn: 6px;
--r-tag: 3px;
--r-pill: 999px;
--font-ui: "Geist", -apple-system, system-ui, sans-serif;
--font-display: "Instrument Serif", "Cormorant Garamond", Georgia, serif;
--font-mono: "JetBrains Mono", ui-monospace, monospace;
--font-display: "Newsreader", Georgia, serif;
--ribbon: linear-gradient(90deg, var(--accent-2) 0%, var(--accent-1) 100%);
--ribbon: linear-gradient(90deg, #0E2A2E 0%, #D08A55 100%);
--warm: rgba(208, 138, 85, 0.10);
--ps-a: #143438;
--ps-b: #D08A55;
}
/* ===========================================================
4. VARIANT D Atelier
Серо-голубой голубь + стальной синий. Manrope, мягкие скругления.
Палитра: --paper #E9EBEF · --ink #14181F · --accent #2E5266
=========================================================== */
html[data-variant="d"] {
--paper: #E9EBEF;
--paper-2: #DCDFE6;
--card: #FFFFFF;
--ink: #14181F;
--ink-2: #2D3340;
--muted: #5F6573;
--muted-2: #8A8F9C;
--line: rgba(20, 24, 31, 0.09);
--line-strong: rgba(20, 24, 31, 0.20);
--accent-1: #2E5266; /* steel blue / стальной синий */
--accent-2: #2F6B45; /* зелёный */
--accent-3: #99362E; /* красный */
--status-active: #2F6B45;
--status-lapsed: #99362E;
--status-grace: #B07A1A;
--r-card: 12px;
--r-btn: 10px;
--r-tag: 6px;
--r-pill: 999px;
--font-ui: "Manrope", -apple-system, system-ui, sans-serif;
--font-display: "Newsreader", Georgia, serif;
--ribbon: linear-gradient(90deg, #2E5266 0%, #2F6B45 100%);
--warm: rgba(46, 82, 102, 0.10);
--ps-a: #2E5266;
--ps-b: #E9EBEF;
}
/* ============================================================
@ -156,8 +211,75 @@ button { font: inherit; cursor: pointer; border: none; background: none; color:
}
/* ============================================================
Theme switcher (top of page)
Palette switcher 4 кнопки-образца цветов
============================================================ */
.palette-switcher {
display: flex;
gap: 6px;
align-items: center;
margin-bottom: var(--s4);
padding: 2px 0;
}
.palette-switcher__label {
font-family: var(--font-mono);
font-size: 9px;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--muted-2);
margin-right: 2px;
user-select: none;
}
.ps-btn {
display: flex;
align-items: center;
gap: 5px;
padding: 5px 9px 5px 7px;
border-radius: 20px;
border: 1.5px solid transparent;
cursor: pointer;
transition: border-color 0.14s, background 0.14s;
background: var(--card);
}
.ps-btn:active { opacity: 0.7; }
.ps-btn.active {
border-color: var(--ink);
}
.ps-swatches {
display: flex;
gap: 3px;
align-items: center;
}
.ps-dot {
display: block;
width: 9px;
height: 9px;
border-radius: 50%;
flex-shrink: 0;
}
.ps-dot--outline {
box-shadow: inset 0 0 0 1px rgba(0,0,0,0.18);
}
.ps-name {
font-family: var(--font-mono);
font-size: 9px;
font-weight: 500;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--muted);
white-space: nowrap;
}
.ps-btn.active .ps-name { color: var(--ink); }
/* Legacy .theme-switch — оставлен для совместимости */
.theme-switch {
display: flex;
gap: 0;
@ -167,7 +289,6 @@ button { font: inherit; cursor: pointer; border: none; background: none; color:
overflow: hidden;
background: var(--card);
}
.theme-switch button {
flex: 1;
padding: 8px 6px;
@ -180,13 +301,8 @@ button { font: inherit; cursor: pointer; border: none; background: none; color:
border-right: 1px solid var(--line-strong);
transition: all 0.12s;
}
.theme-switch button:last-child { border-right: none; }
.theme-switch button.active {
background: var(--ink);
color: var(--paper);
}
.theme-switch button.active { background: var(--ink); color: var(--paper); }
/* ============================================================
Loader (брендированный логотип ЗОВ + дыхание)

View File

@ -10,10 +10,10 @@
<title>WASRUSGEN1 · Кабинет</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Geist:wght@400;500;600&family=Newsreader:ital,wght@0,400..600;1,400..600&family=Instrument+Serif:ital@0;1&family=JetBrains+Mono:wght@400;500&family=Cormorant+Garamond:ital,wght@1,400;1,500;1,600&family=Caveat:wght@500;700&display=swap">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Archivo:wght@400;500;600;700&family=Inter:wght@400;500;600;700;800&family=Geist:wght@400;500;600&family=Manrope:wght@400;500;600;700&family=Newsreader:ital,wght@0,400..600;1,400..600&family=Instrument+Serif:ital@0;1&family=JetBrains+Mono:wght@400;500&family=Cormorant+Garamond:ital,wght@1,400;1,500;1,600&family=Caveat:wght@500;700&display=swap">
<script src="https://telegram.org/js/telegram-web-app.js"></script>
<link rel="stylesheet" href="assets/styles.css?v=20260516h">
<link rel="stylesheet" href="assets/podbor.css?v=20260516h">
<link rel="stylesheet" href="assets/styles.css?v=20260517a">
<link rel="stylesheet" href="assets/podbor.css?v=20260517a">
</head>
<body>
<!-- Splash — лого @wasrusgen1 + опилки (16) + вращающийся диск -->
@ -45,6 +45,6 @@
<script src="assets/request.js?v=20260516h"></script>
<script src="assets/assembly.js?v=20260516h"></script>
<script src="assets/proposals.js?v=20260516h"></script>
<script src="assets/app.js?v=20260516j"></script>
<script src="assets/app.js?v=20260517a"></script>
</body>
</html>