/* * Site Finder v2 — «ПТИЦА» cockpit, ported 1:1 from the approved static * prototype (ptica-v2/index.html). EVERY token and rule is scoped under * `.v2Root[data-theme="dark"]` / `[data-theme="light"]` so the cockpit theme * NEVER leaks into the rest of the (light) application — the wrapper carries the * class AND the data-theme attribute. * * Fonts come from the globally-wired next/font CSS vars (--font-inter / * --font-plex-mono — see app/layout.tsx); no new font deps. */ /* ===================== SCOPED TOKENS ===================== */ .v2Root { --font-ui: var(--font-inter), "Inter", "Manrope", -apple-system, "Segoe UI", system-ui, sans-serif; --font-mono: var(--font-plex-mono), "IBM Plex Mono", "Roboto Mono", ui-monospace, monospace; --radius-xs: 4px; --radius-sm: 8px; --radius-md: 12px; --radius-lg: 16px; --line: 1px; --line-strong: 1.5px; --accent-blue: #2f6f9f; --accent-cyan: #7fd0ee; --accent-cyan-strong: #8ed3ff; --accent-green: #38c172; --accent-green-soft: #2faa63; --accent-yellow: #e0a93b; --accent-red: #d2655b; --accent-purple: #9b80d6; --accent-orange: #e46c35; --res-electric: #e6b23c; --res-water: #4d9bd7; --res-sewer: #9b80d6; --res-heat: #e46c35; --res-gas: #d2655b; --res-poi: #3fa77d; --gauge-track: 9px; } .v2Root[data-theme="dark"] { --bg: #060f16; --bg-2: #08131c; --grid-line: rgba(120, 165, 190, 0.06); --surface: rgba(11, 26, 36, 0.72); --surface-2: rgba(9, 22, 31, 0.62); --surface-strong: rgba(12, 30, 42, 0.94); --surface-muted: rgba(26, 52, 67, 0.55); --surface-inset: rgba(4, 12, 18, 0.6); --text: #dcebf2; --text-strong: #f2fafe; --text-muted: #8ba6b3; --text-soft: #5f7886; --border: rgba(150, 192, 214, 0.18); --border-strong: rgba(150, 192, 214, 0.4); --border-faint: rgba(150, 192, 214, 0.1); --map-bg: #0a1820; --glow: rgba(110, 200, 240, 0.28); --glow-strong: rgba(110, 200, 240, 0.55); --shadow: 0 18px 70px rgba(0, 0, 0, 0.5); --verdict: var(--accent-green); --gauge-good: var(--accent-green); --chip-bg: rgba(20, 42, 56, 0.6); --topbar-bg: rgba(7, 16, 23, 0.9); } .v2Root[data-theme="light"] { --bg: #eaeef2; --bg-2: #e4e9ee; --grid-line: rgba(70, 110, 135, 0.07); --surface: #ffffff; --surface-2: rgba(255, 255, 255, 0.85); --surface-strong: #ffffff; --surface-muted: rgba(222, 231, 238, 0.7); --surface-inset: rgba(232, 238, 243, 0.8); --text: #102132; --text-strong: #06141f; --text-muted: #51616f; --text-soft: #768493; --border: rgba(40, 70, 95, 0.2); --border-strong: rgba(40, 70, 95, 0.36); --border-faint: rgba(40, 70, 95, 0.1); --map-bg: #d9e4ea; --glow: rgba(70, 140, 180, 0.2); --glow-strong: rgba(70, 140, 180, 0.4); --shadow: 0 1px 2px rgba(16, 24, 40, 0.06), 0 10px 28px rgba(40, 68, 92, 0.09); --verdict: #1f9d57; --gauge-good: #1f9d57; --chip-bg: rgba(225, 234, 241, 0.85); --topbar-bg: rgba(255, 255, 255, 0.92); } /* ===================== ROOT / BASE ===================== */ .v2Root { position: relative; width: 100%; min-height: 100vh; font-family: var(--font-ui); background: var(--bg); color: var(--text); -webkit-font-smoothing: antialiased; font-size: 12px; line-height: 1.3; font-variant-numeric: tabular-nums; } .v2Root :where(button) { font: inherit; cursor: pointer; color: inherit; border: none; background: none; } .v2Root svg { display: block; } .mono { font-family: var(--font-mono); } .muted { color: var(--text-muted); } .soft { color: var(--text-soft); } .dash { color: var(--text-soft); font-family: var(--font-mono); } .app { width: 100%; height: 100vh; display: grid; grid-template-rows: 56px 1fr 26px; background: linear-gradient(var(--grid-line) 1px, transparent 1px) 0 0 / 34px 34px, linear-gradient(90deg, var(--grid-line) 1px, transparent 1px) 0 0 / 34px 34px, radial-gradient(1200px 700px at 30% -10%, var(--bg-2), var(--bg)); position: relative; overflow: hidden; } .lbl { font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.13em; text-transform: uppercase; color: var(--text-muted); font-weight: 500; } .sectionTitle { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--text-strong); font-weight: 600; } .sectionSub { font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.13em; text-transform: uppercase; color: var(--text-soft); font-weight: 500; } /* ===================== TOPBAR ===================== */ .topbar { grid-row: 1; display: grid; grid-template-columns: 300px 1fr 300px; align-items: center; border-bottom: 1px solid var(--border); background: var(--topbar-bg); padding: 0 18px; backdrop-filter: blur(6px); z-index: 10; } .brand { display: flex; align-items: center; gap: 11px; text-decoration: none; color: inherit; } .brandLogo { width: 30px; height: 30px; color: var(--accent-cyan); flex: 0 0 auto; } .brandLogo svg { width: 100%; height: 100%; filter: drop-shadow(0 0 6px var(--glow)); } .brandName { font-family: var(--font-mono); font-weight: 600; font-size: 18px; letter-spacing: 0.34em; color: var(--text-strong); } .brandSub { font-size: 7.5px; letter-spacing: 0.05em; color: var(--text-soft); text-transform: uppercase; margin-top: 2px; line-height: 1.25; max-width: 200px; } .tabs { display: flex; justify-content: center; align-items: center; gap: 30px; height: 100%; } .tab { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-soft); font-weight: 500; position: relative; height: 100%; display: flex; align-items: center; } .tabActive { color: var(--text-strong); } .tabActive::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--accent-cyan); box-shadow: 0 0 8px var(--glow-strong); } .topbarRight { display: flex; align-items: center; justify-content: flex-end; gap: 14px; } .clock { text-align: right; } .clock .time { font-family: var(--font-mono); font-size: 15px; font-weight: 500; color: var(--text-strong); letter-spacing: 0.04em; } .clock .date { font-family: var(--font-mono); font-size: 8.5px; color: var(--text-soft); letter-spacing: 0.06em; margin-top: 1px; } .ver { font-family: var(--font-mono); font-size: 8.5px; letter-spacing: 0.08em; color: var(--accent-cyan); padding: 3px 7px; border: 1px solid var(--border); border-radius: var(--radius-xs); background: var(--surface-2); } .tbIcons { display: flex; gap: 6px; } .tbIc { width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; border: 1px solid var(--border); border-radius: var(--radius-xs); color: var(--text-muted); background: var(--surface-2); } .tbIc svg { width: 13px; height: 13px; } /* ===================== BODY GRID ===================== */ .body { grid-row: 2; display: grid; grid-template-columns: 76px 1fr; min-height: 0; } /* rail */ .rail { display: flex; flex-direction: column; align-items: center; border-right: 1px solid var(--border); background: var(--surface-2); padding: 10px 0; gap: 2px; } .railItem { width: 100%; display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 9px 0; color: var(--text-soft); position: relative; } .railItem svg { width: 19px; height: 19px; } .railItem .rlbl { font-family: var(--font-mono); font-size: 7px; letter-spacing: 0.06em; text-transform: uppercase; } .railItemActive { color: var(--accent-cyan); } .railItemActive::before { content: ""; position: absolute; left: 0; top: 6px; bottom: 6px; width: 2px; background: var(--accent-cyan); box-shadow: 0 0 8px var(--glow-strong); } .railSpacer { flex: 1; } /* content area */ .content { display: grid; min-width: 0; min-height: 0; gap: 8px; padding: 8px; grid-template-rows: minmax(0, 2.18fr) minmax(0, 1.18fr) minmax(0, 1.3fr) minmax(0, 1fr); overflow-y: auto; } /* card primitive */ .card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm); display: flex; flex-direction: column; min-width: 0; min-height: 0; position: relative; overflow: hidden; } .cardH { display: flex; align-items: center; justify-content: space-between; padding: 8px 11px 7px; border-bottom: 1px solid var(--border-faint); flex: 0 0 auto; } .cardH .ttl { display: flex; align-items: baseline; gap: 8px; min-width: 0; } .cardB { padding: 9px 11px; flex: 1; min-height: 0; } .more { font-family: var(--font-mono); font-size: 8.5px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--accent-cyan); white-space: nowrap; display: flex; align-items: center; gap: 3px; } .moreRow { text-align: right; margin-top: 6px; } .moreRowAuto { text-align: right; margin-top: auto; } /* bracket corners (light only). bc1 = bottom-left, bc2 = bottom-right; the two top corners are the ::before / ::after of the card itself. */ .brk::before, .brk::after, .bc1, .bc2 { content: ""; position: absolute; width: 15px; height: 15px; pointer-events: none; z-index: 3; } .v2Root[data-theme="light"] .brk::before { top: -1px; left: -1px; border-top: 2px solid var(--border-strong); border-left: 2px solid var(--border-strong); } .v2Root[data-theme="light"] .brk::after { top: -1px; right: -1px; border-top: 2px solid var(--border-strong); border-right: 2px solid var(--border-strong); } .v2Root[data-theme="light"] .brk .bc1 { bottom: -1px; left: -1px; border-bottom: 2px solid var(--border-strong); border-left: 2px solid var(--border-strong); } .v2Root[data-theme="light"] .brk .bc2 { bottom: -1px; right: -1px; border-bottom: 2px solid var(--border-strong); border-right: 2px solid var(--border-strong); } /* rows */ .row1 { display: grid; grid-template-columns: 1.74fr 1.06fr 0.86fr; gap: 8px; min-height: 0; } .row2 { display: grid; grid-template-columns: repeat(6, 1fr); gap: 8px; min-height: 0; } .row3 { display: grid; grid-template-columns: 1fr 1fr 1.25fr 1fr; gap: 8px; min-height: 0; } .row4 { display: grid; grid-template-columns: 1.55fr 1.05fr 1.1fr; gap: 8px; min-height: 0; } /* ===================== MAP ===================== */ .mapCard { padding: 0; } /* The Leaflet map fills the card; PticaMapInner brings its own internal overlay/controls (reused plumbing). */ .mapMount { position: absolute; inset: 0; border-radius: var(--radius-sm); overflow: hidden; } .mapLoading { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; background: var(--map-bg); color: var(--text-soft); font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; } .mapHead { position: absolute; top: 9px; left: 11px; z-index: 5; display: flex; align-items: baseline; gap: 8px; pointer-events: none; } .mapHead .ttl { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-strong); font-weight: 600; text-shadow: 0 1px 4px rgba(0, 0, 0, 0.6); } /* ===================== PASSPORT ===================== */ .passport .cardB { display: flex; flex-direction: column; gap: 0; padding: 0; } .ppId { display: flex; align-items: center; gap: 8px; padding: 9px 11px; border-bottom: 1px solid var(--border-faint); } .ppId .v { font-family: var(--font-mono); font-size: 14px; color: var(--text-strong); letter-spacing: 0.02em; } .ppId .cp { width: 14px; height: 14px; color: var(--text-soft); margin-left: auto; } .ppGrid { display: grid; grid-template-columns: 1fr 1fr; } .ppCell { padding: 9px 11px; border-bottom: 1px solid var(--border-faint); } .ppCell:nth-child(odd) { border-right: 1px solid var(--border-faint); } .ppCell .k { font-family: var(--font-mono); font-size: 8px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-soft); margin-bottom: 4px; } .ppCell .vv { font-size: 12px; color: var(--text); font-weight: 500; line-height: 1.3; } .ppCell .vv.big { font-family: var(--font-mono); font-size: 13px; } .ppCellWide { grid-column: span 2; border-right: none; } .statusOn { color: var(--accent-green); font-family: var(--font-mono); letter-spacing: 0.06em; text-transform: uppercase; font-size: 12px; } /* ===================== RIGHT COLUMN row1 ===================== */ .colStack { display: grid; grid-template-rows: 1.35fr 1fr; gap: 8px; min-height: 0; } .gaugeCard .cardB { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; } .gaugeWrap { position: relative; width: 118px; height: 118px; } .gaugeWrap svg { width: 100%; height: 100%; transform: rotate(-90deg); } .gaugeCenter { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; } .gaugeCenter .pct { font-family: var(--font-mono); font-size: 30px; font-weight: 600; line-height: 1; } .gaugeCenter .pct.mutedG { color: var(--text-soft); } .gaugeCenter .cap { font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase; margin-top: 3px; text-align: center; } .gaugeFoot { font-family: var(--font-mono); font-size: 8px; color: var(--text-soft); letter-spacing: 0.06em; } .invest .cardB { display: flex; flex-direction: column; gap: 8px; } .invest .scoreRow { display: flex; align-items: center; justify-content: space-between; } .invest .score { font-family: var(--font-mono); font-size: 26px; font-weight: 600; color: var(--text-strong); } .invest .score .u { font-size: 13px; color: var(--text-soft); } .invest .score.dashed { color: var(--text-soft); } .invest .spark { height: 26px; color: var(--accent-cyan); opacity: 0.8; } .invest .spark svg { height: 100%; width: auto; } .invest .prRow { display: flex; gap: 10px; } .invest .pr { flex: 1; } .invest .pr .k { font-family: var(--font-mono); font-size: 8px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-soft); margin-bottom: 3px; } .invest .pr .vv { font-size: 13px; font-weight: 600; color: var(--accent-green); } .invest .pr .vv.amb { color: var(--accent-yellow); } .invest .pr .vv.none { color: var(--text-soft); font-family: var(--font-mono); } /* ===================== ROW2 dev scan ===================== */ .kv { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; padding: 3.5px 0; } .kv .k { font-family: var(--font-mono); font-size: 8.5px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-soft); white-space: nowrap; } .kv .v { font-size: 11px; color: var(--text); font-weight: 500; text-align: right; font-variant-numeric: tabular-nums; } .kv .v.mono { font-family: var(--font-mono); } .kv .v.dash { color: var(--text-soft); font-family: var(--font-mono); } .engRow { display: flex; align-items: center; justify-content: space-between; gap: 6px; padding: 3px 0; font-size: 9.5px; } .engRow .nm { font-family: var(--font-mono); font-size: 8.5px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--text); display: flex; align-items: center; gap: 6px; } .engRow .nm .sd { width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto; box-shadow: 0 0 5px currentColor; } .engRow .st { display: flex; align-items: center; gap: 6px; } .engRow .st .stt { font-size: 9.5px; font-weight: 500; } .engRow .st .dm { font-family: var(--font-mono); font-size: 9px; color: var(--text-soft); min-width: 46px; text-align: right; } .ok { color: var(--accent-green); } .warnc { color: var(--accent-orange); } .badge { font-family: var(--font-mono); font-size: 7.5px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--accent-yellow); border: 1px solid var(--accent-yellow); border-radius: 3px; padding: 1px 5px; opacity: 0.85; } .badge.soon { color: var(--accent-cyan); border-color: var(--accent-cyan); } .note { font-family: var(--font-mono); font-size: 8px; letter-spacing: 0.04em; color: var(--text-soft); margin-top: 3px; } .emptyState { font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.04em; color: var(--text-soft); text-align: center; padding: 10px 0; } /* small risk gauge in row2 */ .minigauge { position: relative; width: 74px; height: 74px; margin: 0 auto; } .minigauge svg { width: 100%; height: 100%; transform: rotate(-90deg); } .minigauge .c { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; } .minigauge .c .p { font-family: var(--font-mono); font-size: 18px; font-weight: 600; color: var(--accent-cyan); } .riskCard .cardB { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; } .riskCard .rk { font-family: var(--font-mono); font-size: 8px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-soft); } /* ===================== ROW3 ===================== */ .oksPlan { flex: 1; display: flex; gap: 9px; min-height: 0; } .oksMini { flex: 0 0 96px; background: var(--surface-inset); border: 1px solid var(--border-faint); border-radius: var(--radius-xs); position: relative; overflow: hidden; } .oksMini svg { position: absolute; inset: 0; width: 100%; height: 100%; } .oksKv { flex: 1; display: flex; flex-direction: column; justify-content: center; } .dpGrid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 7px 10px; flex: 1; align-content: center; } .dpCell .k { font-family: var(--font-mono); font-size: 8px; letter-spacing: 0.07em; text-transform: uppercase; color: var(--text-soft); margin-bottom: 3px; } .dpCell .v { font-family: var(--font-mono); font-size: 15px; font-weight: 600; color: var(--text-strong); white-space: nowrap; } .dpCell .v .u { font-size: 10px; color: var(--text-soft); } .dpCell .v.dash { color: var(--text-soft); } .dpCellWide { grid-column: span 3; border-top: 1px solid var(--border-faint); padding-top: 6px; margin-top: 2px; } /* product card */ .chips { display: flex; gap: 5px; margin-bottom: 9px; flex-wrap: wrap; } .chip { font-family: var(--font-mono); font-size: 8.5px; letter-spacing: 0.04em; padding: 3px 8px; border: 1px solid var(--border); border-radius: var(--radius-xs); color: var(--text-soft); background: var(--surface-2); } .chipActive { color: var(--accent-cyan); border-color: var(--accent-cyan); background: var(--chip-bg); box-shadow: 0 0 8px var(--glow); } .chipDim { opacity: 0.45; } .aptrow { display: flex; align-items: center; gap: 8px; padding: 2.5px 0; } .aptrow .nm { font-family: var(--font-mono); font-size: 8.5px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--text-soft); width: 34px; flex: 0 0 auto; } .aptrow .track { flex: 1; height: 6px; background: var(--surface-inset); border-radius: 3px; overflow: hidden; } .aptrow .track i { display: block; height: 100%; background: var(--accent-cyan); opacity: 0.85; border-radius: 3px; } .aptrow .pc { font-family: var(--font-mono); font-size: 9px; color: var(--text-soft); width: 30px; text-align: right; } .qgTitle { font-family: var(--font-mono); font-size: 7.5px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-soft); margin-bottom: 5px; } .dimBars .track i { background: var(--text-soft); opacity: 0.3; } /* insolation */ .insoCard .cardB { display: flex; align-items: center; gap: 12px; } .insoIso { flex: 0 0 110px; height: 100%; display: flex; align-items: center; justify-content: center; color: var(--text-soft); } .insoIso svg { width: 108px; height: 96px; } .insoTxt { flex: 1; } .insoTxt .d { font-size: 10px; color: var(--text-soft); margin-top: 6px; line-height: 1.4; max-width: 150px; } /* ===================== ROW4 ===================== */ .finCard .cardB { display: flex; align-items: stretch; gap: 14px; } .finMain { display: flex; gap: 18px; flex: 1; align-items: center; flex-wrap: wrap; } .finBig .k { font-family: var(--font-mono); font-size: 8px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-soft); margin-bottom: 4px; } .finBig .v { font-family: var(--font-mono); font-size: 25px; font-weight: 600; color: var(--text-strong); line-height: 1; } .finBig .v.dashed { color: var(--text-soft); } .finBig .u { font-family: var(--font-mono); font-size: 9px; color: var(--text-soft); margin-top: 3px; letter-spacing: 0.06em; } .finSep { width: 1px; background: var(--border-faint); align-self: stretch; } .finRatios { display: flex; gap: 16px; align-items: center; } .finRatios .r .k { font-family: var(--font-mono); font-size: 8px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-soft); margin-bottom: 4px; } .finRatios .r .v { font-family: var(--font-mono); font-size: 18px; font-weight: 600; color: var(--text-strong); } .finRatios .r .v.dashed { color: var(--text-soft); } .buyGauge { flex: 0 0 auto; display: flex; flex-direction: column; align-items: center; gap: 3px; border-left: 1px solid var(--border-faint); padding-left: 14px; } /* legal */ .legalGrid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; flex: 1; align-content: start; } .legalRow { display: flex; align-items: baseline; justify-content: space-between; padding: 4px 0; border-bottom: 1px solid var(--border-faint); } .legalRow .k { font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--text-soft); } .legalRow .v { font-size: 11px; color: var(--text); font-weight: 500; } .legalRow .v.no { color: var(--accent-green); } .legalRow .v.dash { color: var(--text-soft); font-family: var(--font-mono); } /* verdict */ .verdictCard .cardB { display: flex; align-items: center; gap: 16px; } .verdictBig { flex: 0 0 auto; display: flex; flex-direction: column; justify-content: center; } .verdictBig .v { font-family: var(--font-mono); font-size: 34px; font-weight: 700; letter-spacing: 0.04em; color: var(--verdict); line-height: 1; text-shadow: 0 0 14px var(--glow); } .verdictBig .v.warn { color: var(--accent-yellow); } .verdictBig .v.bad { color: var(--accent-red); } .verdictBig .note { margin-top: 8px; } .verdictCheck { flex: 1; display: flex; flex-direction: column; gap: 0; min-width: 0; } .vchk { display: flex; align-items: center; gap: 8px; padding: 4px 0; border-bottom: 1px solid var(--border-faint); font-size: 10.5px; } .vchk svg { width: 14px; height: 14px; flex: 0 0 auto; } .vchk.okRow { color: var(--text); } .vchk.okRow svg { color: var(--accent-green); } .vchk.warnRow svg { color: var(--accent-orange); } .vchk.warnRow { color: var(--text); } .vchk.badRow svg { color: var(--accent-red); } .vchk.badRow { color: var(--text); } /* ===================== FOOTER ===================== */ .footer { grid-row: 3; display: flex; align-items: center; justify-content: space-between; border-top: 1px solid var(--border); background: var(--topbar-bg); padding: 0 18px; font-family: var(--font-mono); font-size: 8.5px; letter-spacing: 0.06em; color: var(--text-soft); text-transform: uppercase; } .footer .left { display: flex; gap: 10px; align-items: center; } .footer .left b { color: var(--text-muted); font-weight: 600; } .footDot { color: var(--text-soft); opacity: 0.6; } .footer .right { color: var(--text-soft); } /* ===================== TOAST ===================== */ .toast { position: fixed; left: 50%; bottom: 64px; z-index: 90; transform: translateX(-50%) translateY(14px); background: var(--surface-strong); border: 1px solid var(--border-strong); border-radius: var(--radius-sm); padding: 11px 18px; font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.04em; color: var(--text-strong); box-shadow: var(--shadow); opacity: 0; visibility: hidden; transition: opacity 0.2s, transform 0.2s, visibility 0.2s; } .toastShow { opacity: 1; visibility: visible; transform: translateX(-50%) translateY(0); } /* theme toggle */ .themeToggle { position: fixed; right: 14px; bottom: 38px; z-index: 50; width: 38px; height: 38px; border-radius: 50%; background: var(--surface-strong); border: 1px solid var(--border-strong); color: var(--accent-cyan); display: flex; align-items: center; justify-content: center; box-shadow: var(--shadow); font-size: 16px; } /* ===================== STATE SCREENS ===================== */ .stateScreen { grid-row: 2; display: flex; align-items: center; justify-content: center; padding: 40px; } .stateBox { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.08em; color: var(--text-muted); text-transform: uppercase; } .stateError { font-family: var(--font-mono); font-size: 12px; color: var(--accent-red); margin-bottom: 12px; } .stateLink { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.06em; color: var(--accent-cyan); text-transform: uppercase; text-decoration: none; } /* ===================== OVERLAY (shared scrim) ===================== */ .scrim { position: fixed; inset: 0; z-index: 60; background: rgba(2, 8, 12, 0.55); opacity: 0; visibility: hidden; transition: opacity 0.22s ease, visibility 0.22s ease; backdrop-filter: blur(1.5px); } .v2Root[data-theme="light"] .scrim { background: rgba(30, 50, 70, 0.32); } .scrimOpen { opacity: 1; visibility: visible; } /* ===================== DRAWER ===================== */ .drawer { position: fixed; top: 0; right: 0; bottom: 0; z-index: 70; width: 480px; max-width: 92vw; background: var(--surface-strong); border-left: 1px solid var(--border-strong); box-shadow: -24px 0 70px rgba(0, 0, 0, 0.42); transform: translateX(100%); transition: transform 0.26s cubic-bezier(0.4, 0, 0.2, 1); display: flex; flex-direction: column; background-image: linear-gradient(var(--grid-line) 1px, transparent 1px), linear-gradient(90deg, var(--grid-line) 1px, transparent 1px); background-size: 34px 34px, 34px 34px; } .v2Root[data-theme="light"] .drawer { box-shadow: -18px 0 50px rgba(40, 68, 92, 0.18); } .drawerOpen { transform: translateX(0); } .drawerH { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; padding: 16px 18px 13px; border-bottom: 1px solid var(--border); flex: 0 0 auto; background: var(--topbar-bg); } .drawerH .dhLeft { min-width: 0; } .drawerH .dhEyebrow { font-family: var(--font-mono); font-size: 8.5px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--accent-cyan); margin-bottom: 5px; } .drawerH .dhTitle { font-family: var(--font-mono); font-size: 15px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-strong); font-weight: 600; line-height: 1.15; } .drawerH .dhSum { font-size: 11px; color: var(--text-muted); margin-top: 7px; line-height: 1.45; max-width: 380px; } .drawerClose { flex: 0 0 auto; width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; border: 1px solid var(--border); border-radius: var(--radius-xs); background: var(--surface-2); color: var(--text-muted); font-size: 15px; line-height: 1; } .drawerClose:hover { color: var(--text-strong); border-color: var(--border-strong); } .drawerB { flex: 1; min-height: 0; overflow-y: auto; padding: 16px 18px 22px; } .drawerB::-webkit-scrollbar { width: 7px; } .drawerB::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 4px; } /* drawer content primitives */ .dsec { margin-bottom: 18px; } .dsec:last-child { margin-bottom: 0; } .dsecT { font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-soft); margin-bottom: 9px; display: flex; align-items: center; gap: 8px; } .dsecT::after { content: ""; flex: 1; height: 1px; background: var(--border-faint); } .drow { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; padding: 7px 0; border-bottom: 1px solid var(--border-faint); } .drow:last-child { border-bottom: none; } .drow .k { font-family: var(--font-mono); font-size: 9.5px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--text-soft); flex: 0 0 auto; max-width: 48%; } .drow .v { font-size: 12px; color: var(--text); font-weight: 500; text-align: right; font-variant-numeric: tabular-nums; line-height: 1.35; } .drow .v.mono { font-family: var(--font-mono); } .drow .v.dash { color: var(--text-soft); font-family: var(--font-mono); } .drow .v.ok { color: var(--verdict); } .drow .v.warnc { color: var(--accent-orange); } .dnote { font-family: var(--font-mono); font-size: 8.5px; letter-spacing: 0.04em; color: var(--text-soft); margin-top: 10px; line-height: 1.5; } .dsource { font-family: var(--font-mono); font-size: 8.5px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-soft); margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--border-faint); display: flex; align-items: center; gap: 7px; } .dsource svg { width: 12px; height: 12px; flex: 0 0 auto; opacity: 0.8; } .dbadge { display: inline-block; font-family: var(--font-mono); font-size: 8px; letter-spacing: 0.08em; text-transform: uppercase; padding: 2px 7px; border-radius: 3px; border: 1px solid var(--accent-yellow); color: var(--accent-yellow); } .dbadge.cyan { border-color: var(--accent-cyan); color: var(--accent-cyan); } .dbadge.green { border-color: var(--verdict); color: var(--verdict); } .dbadgeRight { margin-left: auto; } /* drawer data table */ .dtable { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; } .dtable th, .dtable td { text-align: right; padding: 6px 6px; border-bottom: 1px solid var(--border-faint); white-space: nowrap; } .dtable th { font-family: var(--font-mono); font-size: 7.5px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-soft); font-weight: 500; } .dtable td { font-size: 10px; color: var(--text); } .dtable th:first-child, .dtable td:first-child { text-align: left; } .dtable td.mono { font-family: var(--font-mono); } .dtable tr.me td { color: var(--accent-cyan); } .dtable td.dash { color: var(--text-soft); font-family: var(--font-mono); } /* factor bars */ .dfac { margin: 9px 0; } .dfacH { display: flex; justify-content: space-between; font-family: var(--font-mono); font-size: 9px; color: var(--text-soft); text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 4px; } .dfacH b { color: var(--text); font-weight: 500; } .dfacTrack { height: 7px; background: var(--surface-inset); border-radius: 4px; overflow: hidden; } .dfacTrack i { display: block; height: 100%; border-radius: 4px; } /* drawer export buttons */ .dexport { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; } .dbtn { display: flex; align-items: center; gap: 9px; padding: 11px 12px; border: 1px solid var(--border); border-radius: var(--radius-xs); background: var(--surface-2); color: var(--text); font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.04em; text-transform: uppercase; text-align: left; } .dbtn:hover { border-color: var(--accent-cyan); color: var(--accent-cyan); box-shadow: 0 0 10px var(--glow); } .dbtn svg { width: 15px; height: 15px; flex: 0 0 auto; opacity: 0.85; } .dbtn .ds { font-size: 7.5px; color: var(--text-soft); text-transform: none; letter-spacing: 0; } .dbtn b { font-weight: 600; display: block; } /* ===================== CHAT ===================== */ .chatFab { position: fixed; right: 14px; bottom: 84px; z-index: 55; width: 46px; height: 46px; border-radius: 50%; background: var(--accent-blue); border: 1px solid var(--accent-cyan); color: #fff; display: flex; align-items: center; justify-content: center; box-shadow: 0 8px 28px rgba(0, 0, 0, 0.4), 0 0 14px var(--glow-strong); } .chatFab svg { width: 21px; height: 21px; } .chatPanel { position: fixed; right: 0; top: 0; bottom: 0; z-index: 75; width: 380px; max-width: 90vw; background: var(--surface-strong); border-left: 1px solid var(--border-strong); box-shadow: -24px 0 70px rgba(0, 0, 0, 0.42); transform: translateX(110%); transition: transform 0.26s cubic-bezier(0.4, 0, 0.2, 1); display: flex; flex-direction: column; } .v2Root[data-theme="light"] .chatPanel { box-shadow: -18px 0 50px rgba(40, 68, 92, 0.18); } .chatPanelOpen { transform: translateX(0); } .chatH { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 14px 16px 12px; border-bottom: 1px solid var(--border); background: var(--topbar-bg); flex: 0 0 auto; } .chatH .chL { display: flex; align-items: center; gap: 9px; min-width: 0; } .chatH .chIc { width: 26px; height: 26px; border-radius: 50%; background: var(--accent-blue); display: flex; align-items: center; justify-content: center; color: #fff; flex: 0 0 auto; } .chatH .chIc svg { width: 14px; height: 14px; } .chatH .chT { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-strong); font-weight: 600; } .chatH .chS { font-family: var(--font-mono); font-size: 8px; letter-spacing: 0.06em; color: var(--text-soft); margin-top: 2px; } .chatMsgs { flex: 1; min-height: 0; overflow-y: auto; padding: 16px; display: flex; flex-direction: column; gap: 12px; } .chatMsgs::-webkit-scrollbar { width: 7px; } .chatMsgs::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 4px; } .msg { max-width: 84%; font-size: 12px; line-height: 1.5; padding: 10px 12px; border-radius: 12px; white-space: pre-wrap; } .msgBot { align-self: flex-start; background: var(--surface-muted); border: 1px solid var(--border-faint); color: var(--text); border-top-left-radius: 3px; } .msgUser { align-self: flex-end; background: var(--accent-blue); color: #fff; border-top-right-radius: 3px; } .chatChips { display: flex; flex-wrap: wrap; gap: 7px; padding: 0 16px 12px; flex: 0 0 auto; } .chatChip { font-family: var(--font-mono); font-size: 9.5px; letter-spacing: 0.02em; padding: 6px 11px; border: 1px solid var(--border); border-radius: 14px; color: var(--text-muted); background: var(--surface-2); } .chatChip:hover { border-color: var(--accent-cyan); color: var(--accent-cyan); } .chatInput { display: flex; gap: 8px; padding: 12px 14px; border-top: 1px solid var(--border); background: var(--topbar-bg); flex: 0 0 auto; } .chatInput input { flex: 1; background: var(--surface-inset); border: 1px solid var(--border); border-radius: var(--radius-xs); color: var(--text); font-family: var(--font-ui); font-size: 12px; padding: 9px 11px; outline: none; } .chatInput input:focus { border-color: var(--accent-cyan); } .chatInput input::placeholder { color: var(--text-soft); } .chatSend { flex: 0 0 auto; width: 38px; border: 1px solid var(--accent-cyan); border-radius: var(--radius-xs); background: var(--accent-blue); color: #fff; display: flex; align-items: center; justify-content: center; } .chatSend svg { width: 16px; height: 16px; } .chatTyping { align-self: flex-start; display: flex; gap: 4px; padding: 11px 13px; background: var(--surface-muted); border: 1px solid var(--border-faint); border-radius: 12px; border-top-left-radius: 3px; } .chatTyping i { width: 5px; height: 5px; border-radius: 50%; background: var(--text-soft); animation: tdot 1s infinite; } .chatTyping i:nth-child(2) { animation-delay: 0.2s; } .chatTyping i:nth-child(3) { animation-delay: 0.4s; } @keyframes tdot { 0%, 60%, 100% { opacity: 0.3; transform: translateY(0); } 30% { opacity: 1; transform: translateY(-3px); } } /* ===================================================================== * MAP — per-theme title + resource legend overlay * (matches prototype `ptica-v2/index.html` `.map-head` + `.legend .lg-res`) * ===================================================================== */ /* Per-theme map title — both spans rendered, CSS shows one. Mirrors the prototype `.tnum-d` / `.tnum-l` toggle. */ .mapTitleDark, .mapTitleLight { display: none; } .v2Root[data-theme="dark"] .mapTitleDark { display: inline; } .v2Root[data-theme="light"] .mapTitleLight { display: inline; } /* Resource legend (top-left, under the map title) — compact 5-row panel. */ .mapLegend { position: absolute; left: 11px; top: 34px; z-index: 6; min-width: 168px; max-width: 200px; background: var(--surface-strong); border: 1px solid var(--border); border-radius: var(--radius-xs); padding: 8px 9px; backdrop-filter: blur(3px); pointer-events: none; } .mapLegendTitle { font-family: var(--font-mono); font-size: 7.5px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-soft); margin: 0 0 5px; } .mapLegendRow { display: flex; align-items: center; gap: 6px; height: 15px; font-size: 9px; } .mapLegendDot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; box-shadow: 0 0 5px currentColor; } .mapLegendLabel { font-family: var(--font-mono); letter-spacing: 0.04em; text-transform: uppercase; color: var(--text); font-size: 8.5px; } .mapLegendDist { margin-left: auto; font-family: var(--font-mono); font-size: 8.5px; color: var(--text-muted); font-variant-numeric: tabular-nums; } .mapLegendDistEmpty { color: var(--text-soft); opacity: 0.7; } /* ===================================================================== * LIGHT THEME — targeted contrast polish * Tokens stay; just bump the value-side text and the cyan accents that * appear washed-out on white. Dark theme is untouched. * ===================================================================== */ /* kv-row: value text on white needs darker ink. */ .v2Root[data-theme="light"] .kv .v { color: var(--text-strong); } /* Инженерия status-row: distance was --text-soft (#768493 ≈ AA-borderline at 12px on white); push to --text-muted (#51616f) for solid AA. */ .v2Root[data-theme="light"] .engRow .st .dm { color: var(--text-muted); } /* Status-dot glow on white reads as a halo — soften it. */ .v2Root[data-theme="light"] .engRow .nm .sd { box-shadow: none; } /* Map-legend value column — same readability bump on white. */ .v2Root[data-theme="light"] .mapLegendDist { color: var(--text-strong); } .v2Root[data-theme="light"] .mapLegendLabel { color: var(--text-strong); } .v2Root[data-theme="light"] .mapLegendDot { box-shadow: none; } /* Map title (light): drop the dark text-shadow that makes thin uppercase look smudgy on a satellite-light map base. */ .v2Root[data-theme="light"] .mapHead .ttl { text-shadow: 0 1px 2px rgba(255, 255, 255, 0.6); color: var(--text-strong); } /* Cards `Подробнее →` — cyan on white is faint. Swap to the deeper blue. */ .v2Root[data-theme="light"] .more { color: var(--accent-blue); } /* Drawer eyebrow (cyan in dark) — use blue on white for AA. */ .v2Root[data-theme="light"] .drawerH .dhEyebrow { color: var(--accent-blue); } /* Topbar version-chip: cyan text on a white pill is illegible. */ .v2Root[data-theme="light"] .ver { color: var(--accent-blue); border-color: var(--border-strong); background: var(--surface); } /* Topbar clock — separator-like vertical line between time + date is faint; strengthen the date line and the chip border for visible structure. */ .v2Root[data-theme="light"] .clock .date { color: var(--text-muted); } /* Active tab underline — cyan + glow on white reads as a pale smudge. Swap to brand blue + drop the glow halo. */ .v2Root[data-theme="light"] .tabActive::after { background: var(--accent-blue); box-shadow: none; } /* Rail active marker — same treatment. */ .v2Root[data-theme="light"] .railItemActive { color: var(--accent-blue); } .v2Root[data-theme="light"] .railItemActive::before { background: var(--accent-blue); box-shadow: none; } /* Generic note / drawer note / source — bump from --text-soft to --text-muted on white so the caveat copy stays readable but still secondary. */ .v2Root[data-theme="light"] .note, .v2Root[data-theme="light"] .dnote, .v2Root[data-theme="light"] .dsource { color: var(--text-muted); } /* Section separator line inside drawer (`::after` on .dsecT) — barely visible on white at 10% alpha; strengthen the border-faint reach within drawer. */ .v2Root[data-theme="light"] .dsecT::after, .v2Root[data-theme="light"] .drow { border-color: rgba(40, 70, 95, 0.16); }