/* Vigilo — design system in code.
   Tokens come from «Vigilo Design System.dc.html»: five risk levels defined by
   index ranges, two themes, one accent for actions, radii 28/24/18/999.
   Two platform skins share every token and differ only where the platform
   itself differs — iOS uses the blur bar and 999px pills, Android (Material 3
   Expressive) uses fuller shapes and a solid bar. */

:root {
  --lv1: #3FBF7F; --lv2: #D3B23E; --lv3: #F08A3E; --lv4: #E5484D; --lv5: #B3262E;
  --r-sheet: 28px; --r-card: 24px; --r-btn: 18px; --r-pill: 999px;
  --font: 'Onest', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  --tap: 44px;
}

/* dark is the default; light overrides below */
body {
  --bg: #0B0E13; --s1: #151923; --s2: #1E2430;
  --tx: #F3F5F8; --mu: #8C95A6; --bd: rgba(255,255,255,.10);
  --ac: #3ED3C3; --ai: #062320; --gl: rgba(21,25,35,.55); --glOn: rgba(255,255,255,.10);
  --shadow: 0 18px 40px rgba(0,0,0,.45);
  /* the tab bar is opaque by decision — see the block at the end of this file */
  --tabbar: #1A1F2B; --tabbar-edge: rgba(255,255,255,.10);
  /* the accent, quietly: selected ranges, tints behind chosen things */
  --acSoft: rgba(62,211,195,.16);
}
body[data-theme="light"] {
  --bg: #F4F3EF; --s1: #FFFFFF; --s2: #E7E4DC;
  --tx: #14181F; --mu: #5B6472; --bd: rgba(0,0,0,.06);
  --ac: #087066; --ai: #FFFFFF; --gl: rgba(255,255,255,.55); --glOn: rgba(20,24,31,.08);
  --shadow: 0 14px 34px rgba(20,24,31,.10);
  /* The level ramp was tuned against a near-black background and cannot
     survive #F4F3EF: the index numeral measured 2.5:1, the trend mark 2.0:1.
     Same five levels, same hues, enough ink to read. */
  --lv1: #17784A; --lv2: #7E6210; --lv3: #B4551A; --lv4: #C1272C; --lv5: #8E1D24;
  --tabbar: #FFFFFF; --tabbar-edge: rgba(20,24,31,.10);
  --acSoft: rgba(8,112,102,.13);
}

* { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; }
/* 100% resolves against the LARGE viewport while #app uses 100dvh — the
   dynamic one. On Android Chrome and in the Telegram webview the document was
   therefore taller than the visible area by exactly the toolbar's height, and
   the whole shell scrolled: the tab bar slid up and bare background showed
   under it. Both must speak of the same viewport. */
/* dvh follows the browser's chrome as it hides and shows, which means the tab
   bar sits under the chrome for as long as the animation lasts — and in the
   Telegram webview, longer. svh is the smallest the viewport ever gets, so the
   bar is always on screen; the cost is a strip of background when the chrome
   is hidden, which nobody has ever complained about. */
html, body { height: 100dvh; height: 100svh; }
body {
  background: var(--bg); color: var(--tx); font-family: var(--font);
  -webkit-font-smoothing: antialiased; overscroll-behavior-y: none;
}
img { max-width: 100%; display: block; }
button, input, textarea, select { font: inherit; color: inherit; }

/* ── shell ────────────────────────────────────────────────────────────── */
#app { height: 100dvh; height: 100svh; display: flex; flex-direction: column;
       max-width: 520px; margin: 0 auto; position: fixed; inset: 0; overflow: hidden; }
.screen { flex: 1; min-height: 0; position: relative; display: flex; flex-direction: column; }
.vg-scroll::-webkit-scrollbar { display: none; }
.screen::-webkit-scrollbar { display: none; }
.screen.flush { padding-left: 0; padding-right: 0; padding-top: 0; }

/* ── typography (design system scale) ─────────────────────────────────── */
.t-display { font-size: 40px; font-weight: 800; letter-spacing: -.035em; line-height: 1.05; }
.t-screen  { font-size: 28px; font-weight: 800; letter-spacing: -.02em; line-height: 1.1; }
.t-card    { font-size: 17px; font-weight: 700; letter-spacing: -.01em; }
.t-index   { font-size: 44px; font-weight: 800; letter-spacing: -.04em; line-height: 1; }
.t-body    { font-size: 15px; font-weight: 500; line-height: 1.45; }
.t-cap     { font-size: 12px; font-weight: 500; color: var(--mu); }
.t-label   { font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; }
.mu { color: var(--mu); }

/* ── surfaces ─────────────────────────────────────────────────────────── */
.card { background: var(--s1); border: 1px solid var(--bd); border-radius: var(--r-card); padding: 18px; }
.tile { background: var(--s2); border-radius: var(--r-btn); padding: 10px 12px; }
.sheet { background: var(--s1); border-radius: var(--r-sheet); padding: 20px; }
.row { display: flex; align-items: center; gap: 12px; }
.col { display: flex; flex-direction: column; }
.gap8 { gap: 8px; } .gap12 { gap: 12px; } .gap14 { gap: 14px; }
.grid3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; }
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }

/* ── actions ──────────────────────────────────────────────────────────── */
.btn { display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%;
       min-height: var(--tap); padding: 14px 18px; border: 0; border-radius: var(--r-btn);
       font-size: 15px; font-weight: 700; cursor: pointer; transition: transform .12s ease, filter .12s ease; }
.btn:active { transform: scale(.985); }
.btn-primary { background: var(--ac); color: var(--ai); }
.btn-dark { background: var(--tx); color: var(--bg); }
.btn-ghost { background: var(--s2); color: var(--tx); font-weight: 600; }
.btn-line { background: transparent; border: 1px solid var(--bd); color: var(--tx); font-weight: 600; }
.btn[disabled] { opacity: .5; pointer-events: none; }
.pill { display: inline-flex; align-items: center; gap: 6px; padding: 8px 14px; border-radius: var(--r-pill);
        font-size: 12px; font-weight: 700; background: var(--s1); border: 1px solid var(--bd); }
.pill.on { background: var(--tx); color: var(--bg); border-color: transparent; }
.chipbar { display: flex; gap: 8px; overflow-x: auto; scrollbar-width: none; margin: 0 -18px; padding: 0 18px; }
.chipbar::-webkit-scrollbar { display: none; }

/* ── inputs ───────────────────────────────────────────────────────────── */
.field { width: 100%; background: var(--s2); border: 1px solid transparent; border-radius: var(--r-btn);
         padding: 15px 14px; font-size: 16px; line-height: 1.25; min-height: var(--tap);
         appearance: none; -webkit-appearance: none; transition: border-color .15s, background .15s; }
.field::placeholder { color: var(--mu); }
.field:focus { outline: none; background: var(--s1); border-color: var(--ac); }
.field-label { font-size: 12px; font-weight: 600; color: var(--mu); margin: 14px 2px 6px; }
.seg { display: flex; gap: 3px; background: var(--s2); border-radius: 14px; padding: 3px; }
.seg button { flex: 1; min-height: var(--tap); border: 0; background: none; border-radius: 11px;
              font-size: 13.5px; font-weight: 600; color: var(--mu); cursor: pointer; }
.seg button.on { background: var(--s1); color: var(--tx); }

/* ── level colours ────────────────────────────────────────────────────── */
.lv1 { color: var(--lv1); } .lv2 { color: var(--lv2); } .lv3 { color: var(--lv3); }
.lv4 { color: var(--lv4); } .lv5 { color: var(--lv5); }
.dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.bar { height: 4px; border-radius: 2px; flex: 1; background: var(--s2); }

/* The tab bar, the offline notice and the screen chrome all live in the
   design's own markup — the shell used to carry empty copies of them, and an
   empty <nav class="tabs" hidden> still showed because display:flex overrides
   the hidden attribute. Removed rather than patched. */

/* ── Android (Material 3 Expressive) ──────────────────────────────────── */
body[data-platform="android"] {
  --r-sheet: 28px; --r-card: 28px; --r-btn: 20px;
}
body[data-platform="android"] .tabs {
  left: 0; right: 0; bottom: 0; width: 100%; transform: none; border-radius: 0;
  border-left: 0; border-right: 0; border-bottom: 0; background: var(--s1); backdrop-filter: none;
  padding: 10px 6px calc(10px + env(safe-area-inset-bottom));
}
body[data-platform="android"] .tabs button.on { color: var(--ac); }
body[data-platform="android"] .btn { border-radius: var(--r-pill); font-weight: 600; }
body[data-platform="android"] .card { border-width: 0; box-shadow: var(--shadow); }

/* ── states ───────────────────────────────────────────────────────────── */
.skeleton { border-radius: var(--r-card); background: linear-gradient(90deg, var(--s1), var(--s2), var(--s1));
            background-size: 200% 100%; animation: sk 1.2s infinite; }
@keyframes sk { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
.empty { text-align: center; padding: 30px 18px; }
.toast { position: fixed; left: 50%; transform: translateX(-50%);
         bottom: calc(92px + env(safe-area-inset-bottom)); z-index: 50; max-width: min(460px, calc(100% - 32px));
         background: var(--s1); border: 1px solid var(--bd); border-radius: var(--r-btn);
         box-shadow: var(--shadow); padding: 13px 16px; font-size: 14px; opacity: 0;
         pointer-events: none; transition: opacity .2s ease; }
.toast.on { opacity: 1; }


/* The tab bar is the one surface that is always on screen, and the canvas gave
   it 55 % opacity over a 22 px blur — headings and photographs showed through
   it and the labels lost their edges. It is a solid surface now; everything
   else about it is the designer's. */
/* ── the tab bar: a decision, not a drift ──────────────────────────────────
   The design system draws it as «плавающее меню · жидкое стекло»: 55 % alpha
   over blur(22px) saturate(1.6). On a phone that reads as a smear of whatever
   is behind it — headings and photographs show through the one surface that is
   always on screen, and the labels lose their edges. The owner asked for it
   solid twice, and the taste the rest of the app follows is «restrained,
   native, no glass». So: opaque, with a hairline and a shadow to lift it off
   the page. If the canvas is re-exported, this block stays. */
/* The bar is painted, and then the page is painted over it. It is absolutely
   positioned with no z-index, so anything positioned inside the scroller — a
   sticky heading, a card with its own layer — lands on top of it, and «Мои
   страны» reads straight through a surface that is, in fact, opaque. That is
   the transparency the owner keeps seeing. The bar is the topmost thing on the
   screen; it should say so. */
.vg-tabs { position: relative; z-index: 50; }
.vg-tabs > div { z-index: 50 !important; background: var(--tabbar) !important;
                 backdrop-filter: none !important; -webkit-backdrop-filter: none !important;
                 border: 1px solid var(--tabbar-edge) !important;
                 box-shadow: 0 10px 34px rgba(0, 0, 0, .30) !important; }
body[data-platform="android"] .vg-tabs > div {
                 border-left: 0 !important; border-right: 0 !important; border-bottom: 0 !important;
                 box-shadow: 0 -8px 26px rgba(0, 0, 0, .26) !important; }

/* A flex item's default min-height is «auto», which means «as tall as my
   content» — so a scroller full of cards grew past the screen instead of
   scrolling inside it, the screen grew with it, and the tab bar, which is
   anchored to the screen's bottom, went down with them. The reports list is
   where it showed first because that is where the cards are tallest. */
.screen > *, .vg-scroll { min-height: 0; }

/* The canvas positions the bar 22 px from the bottom of a frame that has no
   home indicator. On a notched phone those 22 px are inside it. */
.vg-tabs > div { bottom: calc(22px + env(safe-area-inset-bottom)) !important; }
body[data-platform="android"] .vg-tabs > div { bottom: 0 !important;
  padding-bottom: calc(14px + env(safe-area-inset-bottom)) !important; }
/* …and what scrolls under the bar ends above it — one rule for every screen,
   because some canvas screens carry the 96 px themselves and some (country,
   report, news, trip) carry none, and two rules stacked into a 228 px hole. */
.vg-scroll[style*="flex:1"] { padding-bottom: calc(96px + env(safe-area-inset-bottom)) !important; }

/* A control in this app is a div with a word in it. On Android a tap that the
   page does not obviously consume is handed to the system as a text selection,
   and the browser answers with «искать в Google» over the button's own label —
   the app looked like it was searching the web for «Отчёт». Controls are not
   selectable; the text a person may actually want to copy still is. */
[data-act], .vg-tabs, .vg-tabs * {
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
}
input, textarea, [contenteditable] { -webkit-user-select: text; user-select: text; }

/* Every control here is a div, the stylesheet's only :active rule matched a
   class the canvas never uses, and the browser's own tap highlight is switched
   off at the top of this file. So a tap produced no pixel of acknowledgement
   anywhere in the app: a person could not tell a working button from a missed
   one. This is that acknowledgement. */
#screen [data-act] { transition: transform .12s ease, filter .12s ease; }
#screen [data-act]:active { transform: scale(.97); filter: brightness(1.10); }

/* A 17px text link is a 17px target. The box grows, the layout does not.
   Not inside a grid or a chip row, though: there the controls already touch,
   and a box ten pixels wider on every side steals its neighbour's taps — in
   the calendar that means the day beside the one you pressed. */
#screen [data-act] { position: relative; }
#screen [data-act]::after { content: ''; position: absolute; inset: -10px; }
#screen [data-act] > * { position: relative; z-index: 1; }
#screen [style*="grid-template-columns"] > [data-act]::after,
#screen [style*="overflow-x:auto"] > [data-act]::after,
#screen [style*="display:grid"] > [data-act]::after { content: none; }

/* An action in flight is not the same as an action ignored. */
#screen [data-act].vg-busy { opacity: .55; pointer-events: none; }

/* Printing a report — which is how a phone makes a PDF — is the one time the
   app should stop being an app: no tab bar, no sticky contents, no dark
   background, every section open, pages one after another. */
@media print {
  #app { position: static; height: auto; max-width: none; overflow: visible; }
  .screen, .vg-scroll { height: auto !important; overflow: visible !important;
                        padding-bottom: 0 !important; }
  .vg-tabs, .demo-note, [data-act^="toc:"], [data-act^="share"], [data-act="back"] { display: none !important; }
  #screen > div > div[style*="display:none"] { display: block !important; }
  body { background: #fff !important; color: #14181F !important; }
  [style*="position:sticky"] { position: static !important; }
}

/* ── shell corrections, not design changes ────────────────────────────── */
/* The canvas draws inside a fixed 402×874 frame. On a real phone the scroll
   area is whatever the device gives us, so the bottom padding has to clear the
   platform's own bar — on Android it is solid and taller than the iOS pill. */
/* …but only to the screen's own scroller. The class also hides the scrollbar
   on the horizontal chip rows — the report's contents, the category filters,
   the language sheet — and those were each given 118 px of bottom padding they
   had no use for: a finger-tall hole under the chips and above the text. The
   page scrollers are the ones that carry flex:1. */
body[data-platform="android"] .vg-scroll[style*="flex:1"] {
  padding-bottom: calc(104px + env(safe-area-inset-bottom)) !important; }
.vg-scroll { -webkit-overflow-scrolling: touch; }

/* The demo notice belongs in the flow, not over the greeting. */
.demo-note-x { position: absolute; right: 10px; top: 50%; transform: translateY(-50%);
               padding: 6px 8px; opacity: .7; font-size: 13px; }
.demo-note { position: relative; flex: none; background: var(--ac); color: #0B0E13; font-size: 12px;
             font-weight: 600; padding: 6px 14px; text-align: center; }

/* ── the canvas's own helpers ─────────────────────────────────────────────
   Copied from the design file: the generated markup uses these three and
   nothing else, and without them the inputs fall back to the browser's own
   bordered boxes and the pulses do not animate. */
.vg-in { border: 0; outline: 0; background: transparent; font: inherit; color: inherit;
         width: 100%; min-width: 0; }
.vg-in::placeholder { color: var(--mu); }
@keyframes vgPulse { 0%, 100% { opacity: .35; transform: scale(1); } 50% { opacity: 0; transform: scale(2.2); } }
@keyframes vgShimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
@keyframes vgBob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-2px); } }
