/* base.css — The whole app: fonts, the two palettes, the shell, the rail and tab bar,
   the generic pieces every screen uses, the modal. */
/* Self-hosted, not a CDN: the app is offline-capable and sits behind a private
   login, so it may not depend on a third-party host to render its own name.
   One variable file covers 600 and 700. */
@font-face{font-family:"Montserrat";src:url("../fonts/montserrat-latin-var.woff2") format("woff2");
  font-weight:100 900;font-style:normal;font-display:swap;
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215}
:root{
 --bg:#050917;--surface:#0b1226;--raise:#131c36;--line:#22305a;--line2:#161f3b;
 --txt:#eaf1ff;--dim:#9fb2d4;--faint:#7186ad;
 /* --acc is the FILL, which carries ground ink at 6.2:1. --acc-txt is the same
    Challenge blue brightened for use AS TEXT on a dark ground, where the fill
    itself only reaches 5.0:1. --on-acc is whatever sits on top of a fill. */
 --acc:#198dc6;--acc-txt:#2ba6e0;--on-acc:#050917;
 --air:#3ed9a4;--flt:#2ba6e0;--dh:#a98bff;--trn:#ffc24a;--bad:#ff6b77;
 /* Rest had to move off blue when the accent became blue: a layover day and
    the active nav item must never read as the same colour. */
 --rest:#8ca3c7;
 --ocean:#071023;--land:#16203a;--track:#0a1226;
 --display:"Montserrat",-apple-system,BlinkMacSystemFont,"SF Pro Display",sans-serif;
 --mono:ui-monospace,"SF Mono",Menlo,monospace;
 --sans:-apple-system,BlinkMacSystemFont,"SF Pro Display","Segoe UI",Roboto,sans-serif;
}
/* Daylight palette. A flight deck in sunlight is unreadable on the dark theme,
   so this is a genuine second mode rather than an inversion: the accent stays
   put and the status colours are darkened to keep contrast against white. */
:root[data-theme="light"]{
 --bg:#edf3fb;--surface:#ffffff;--raise:#e3ebf7;--line:#c6d4e8;--line2:#dce5f2;
 --txt:#05003b;--dim:#42568a;--faint:#526492;
 /* Daylight runs the rule the other way: the fill darkens so WHITE passes on
    it (4.9:1), where the dark theme brightens the fill and puts ink on top. */
 --acc:#1478ab;--acc-txt:#106190;--on-acc:#ffffff;
 --air:#04704a;--flt:#1478ab;--dh:#5b36c4;--trn:#8a5a00;--bad:#c22b3a;
 --rest:#42568a;
 --ocean:#dbe5f4;--land:#c2cfe3;--track:#e3e9f3;
}
:root[data-theme="light"] .cc.me{color:#fff}
:root[data-theme="light"] .mk,:root[data-theme="light"] .seg button.on,
:root[data-theme="light"] .pill.on,:root[data-theme="light"] .youin,
:root[data-theme="light"] nav a.on{color:#fff}
:root[data-theme="light"] .wa,:root[data-theme="light"] .wabtn{color:#08301c}
:root[data-theme="light"] .plane{fill:var(--txt)}
:root[data-theme="light"] .aplabel{fill:#42568a}
:root[data-theme="light"] .grat{stroke:#cbd7e8}
:root[data-theme="light"] .arc-net{stroke:#a9b8d0}
:root[data-theme="light"] .navwrap{--nav-bg:#ffffff}
:root[data-theme="light"] .top{background:linear-gradient(var(--bg) 82%,transparent)}
*{box-sizing:border-box;margin:0;padding:0}
body{background:var(--bg);color:var(--txt);font-family:var(--sans);font-size:15px;line-height:1.5;-webkit-font-smoothing:antialiased;overflow-x:hidden;font-variant-numeric:tabular-nums}
button,input,select{font-family:inherit;font-size:inherit;color:inherit}
.hidden{display:none!important}
/* ── shell ── */
/* The nav rail is fixed and outside normal flow, so appView carries the offset
   for it — .shell itself stays centred within whatever width that leaves. */
:root{--rail-w:64px}
#appView{padding-left:calc(var(--rail-w) + env(safe-area-inset-left));padding-right:env(safe-area-inset-right);transition:padding-left .22s ease}
:root[data-nav-collapsed] #appView{padding-left:env(safe-area-inset-left)}
.shell{max-width:1000px;margin:0 auto;padding:0 18px 28px}
/* The installed iPhone app draws under the status bar — viewport-fit=cover and
   a translucent status bar are what make it look like an app rather than a
   page. The cost is that a header pinned to top:0 is pinned UNDER the Dynamic
   Island: EDI's name and the bell sat behind it, cropped, on his first day. So
   the bar carries the inset itself; on anything without one it is plain 18px. */
.top{display:flex;align-items:center;gap:12px;padding:calc(18px + env(safe-area-inset-top)) 0 14px;border-bottom:1px solid var(--line);position:sticky;top:0;background:linear-gradient(var(--bg) 82%,transparent);z-index:20}
/* The demo (core/demo.js): no bell, no settings — there is no account behind it —
   and a chip in the header that says so and leads out. */
[data-demo] #bellBtn,[data-demo] #settingsBtn{display:none}
.demochip{flex:none;font:700 10px/1 var(--mono);letter-spacing:.14em;text-transform:uppercase;color:#1c1300;
  background:#ffb020;border:0;border-radius:999px;padding:7px 11px;cursor:pointer}
.mk{width:34px;height:34px;border-radius:8px;background:linear-gradient(135deg,var(--acc),#4fc3f7);display:grid;place-items:center;font-weight:800;color:var(--on-acc);font-size:15px;flex:none}
.who{min-width:0;flex:1}
.who b{font-size:15px;font-weight:650;display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.who span{display:block;color:var(--faint);font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* Freshness badge doubles as the sync button. It must never claim "live" over
   stale data — the colour and the label follow how old the harvest actually is. */
.badge{margin-left:auto;font-size:11px;font-weight:700;letter-spacing:.6px;color:var(--air);background:none;border:1px solid rgba(56,210,154,.35);border-radius:999px;padding:5px 11px;display:flex;align-items:center;gap:6px;flex:none;cursor:pointer;white-space:nowrap}
.badge:hover{filter:brightness(1.25)}
.badge .p{width:7px;height:7px;border-radius:50%;background:currentColor;animation:pulse 2s infinite;flex:none}
.badge.stale{color:var(--trn);border-color:rgba(255,202,74,.4)}
.badge.old{color:var(--bad);border-color:rgba(255,93,108,.4)}
.badge.busy{color:var(--flt);border-color:rgba(61,155,255,.45)}
.badge.busy .p{animation:spin 1s linear infinite;border-radius:2px}
.badge:disabled{cursor:default}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.35}}
@keyframes spin{to{transform:rotate(360deg)}}
.toast{position:fixed;left:calc(50% + var(--rail-w) / 2);transform:translateX(-50%);bottom:calc(22px + env(safe-area-inset-bottom));z-index:80;background:var(--raise);border:1px solid var(--line);border-radius:12px;padding:10px 16px;font-size:13px;color:var(--txt);box-shadow:0 8px 26px rgba(0,0,0,.45);max-width:88vw;text-align:center;transition:left .22s ease}
:root[data-nav-collapsed] .toast{left:50%}
.toast.ok{border-color:rgba(56,210,154,.45)}
.toast.bad{border-color:rgba(255,93,108,.45);color:#ffb3ba}
.lo{background:none;border:1px solid var(--line);color:var(--faint);border-radius:8px;padding:5px 10px;font-size:11px;cursor:pointer}
.lo:hover{color:var(--txt);border-color:var(--faint)}
/* ── nav ── */
/* A left rail, not a bottom bar: a solid panel reads far better than a
   translucent strip in the dark theme, and a column avoids the horizontal
   scroll a phone-width bottom bar forced. Six sections fit any screen with
   room to spare, which is why the scroll fades and the auto-centring that
   eleven items needed are gone — the rail no longer scrolls. */
.navwrap{position:fixed;top:0;left:0;bottom:0;z-index:40;width:var(--rail-w);--nav-bg:var(--surface);background:var(--nav-bg);border-right:1px solid var(--line);transition:transform .22s ease}
:root[data-nav-collapsed] .navwrap{transform:translateX(-100%);pointer-events:none}
/* The rail can be hidden entirely to reclaim its width for content. This tab
   is the one thing that stays put either way — a handle anchored to the
   bottom-left corner, which reads as a control rather than a stray box the
   way it did floating mid-height between two nav items — attached to the
   rail's edge when shown, pulled back flush to the viewport edge when
   hidden, so there is always something to find and click to bring it back.
   The accent border + fill is deliberate: --line alone all but disappeared
   against the dark panel on a real phone. */
.navtoggle{position:fixed;bottom:calc(16px + env(safe-area-inset-bottom));left:var(--rail-w);margin-left:-1px;width:28px;height:52px;z-index:42;display:flex;align-items:center;justify-content:center;background:var(--raise);border:1px solid var(--acc);border-left:0;border-radius:0 14px 14px 0;color:var(--acc);font-size:16px;font-weight:800;cursor:pointer;box-shadow:0 4px 16px rgba(0,0,0,.4);transition:left .22s ease,background .15s,color .15s,transform .1s}
.navtoggle:hover{background:var(--acc);color:var(--on-acc)}
.navtoggle:active{transform:scale(.94)}
:root[data-nav-collapsed] .navtoggle{left:0}
@media(max-width:620px){.navtoggle{width:32px;height:56px}}
nav{display:flex;flex-direction:column;align-items:stretch;gap:3px;height:100%;padding:calc(10px + env(safe-area-inset-top)) 5px calc(10px + env(safe-area-inset-bottom));overflow-y:auto;overflow-x:hidden;scrollbar-width:none;-webkit-overflow-scrolling:touch}
nav::-webkit-scrollbar{display:none}
nav a{flex:none;text-align:center;text-decoration:none;color:var(--dim);font-size:10px;font-weight:600;letter-spacing:.2px;padding:10px 1px;border-radius:12px;transition:.15s;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
nav a .ic{display:flex;align-items:center;justify-content:center;margin-bottom:4px;line-height:0}
nav a .ic svg{width:21px;height:21px}
/* Solid accent fill, not a low-opacity tint — the same "on" treatment as
   .pill/.seg elsewhere, and one that stays legible against the dark panel. */
nav a.on{color:var(--on-acc);background:var(--acc);font-weight:700}
nav a:hover{color:var(--txt);background:var(--raise)}
/* Second level of navigation: the screens that used to be siblings in the rail,
   now sitting inside the section they belong to. Underline rather than fill, so
   it never competes with the rail's solid accent for "you are here". */
/* Folding Flights into Roster gave that section seven tabs, which overflow on
   a phone. The bar already scrolled; what it never did was say so. A tab you
   can only reach by guessing it is there is a tab nobody uses — the same
   mistake that made the old eleven-item rail unusable. The fade is only
   painted while there is actually something past the edge. */
.tabs{display:flex;gap:2px;margin:12px 0 4px;border-bottom:1px solid var(--line);
  overflow-x:auto;scrollbar-width:none;scroll-snap-type:x proximity;
  -webkit-mask-image:linear-gradient(90deg,#000 calc(100% - 26px),transparent);
          mask-image:linear-gradient(90deg,#000 calc(100% - 26px),transparent)}
.tabs button{scroll-snap-align:start}
/* nothing to scroll to: drop the fade so a short bar is not dimmed for no reason */
.tabs:not(:has(button:nth-child(5))){-webkit-mask-image:none;mask-image:none}
.tabs::-webkit-scrollbar{display:none}
.tabs button{flex:0 0 auto;background:none;border:0;border-bottom:2px solid transparent;margin-bottom:-1px;color:var(--dim);padding:9px 13px;font-size:13px;font-weight:600;cursor:pointer;white-space:nowrap}
.tabs button:hover{color:var(--txt)}
.tabs button.on{color:var(--txt);border-bottom-color:var(--acc)}
/* ── generic ── */
h2{font-size:12px;text-transform:uppercase;letter-spacing:1.5px;color:var(--faint);margin:26px 2px 10px;font-weight:700;display:flex;align-items:center;gap:8px}
/* The tab bar above already separates the screen from the toolbar; a full
   26px on top of that leaves the first heading floating. Whatever a screen
   opens with gets the same measured gap. */
#view > h2:first-child{margin-top:14px}
#view > .mapwrap:first-child,#view > .filters:first-child,#view > .mnav:first-child{margin-top:14px}
h2 .n{color:var(--acc)}
.card{border:1px solid var(--line);border-radius:12px;background:var(--surface)}
.sum{display:flex;border:1px solid var(--line);border-radius:12px;overflow:hidden;background:var(--surface);flex-wrap:wrap}
.sum .s{flex:1;min-width:88px;padding:12px 14px;border-right:1px solid var(--line)}
.sum .s:last-child{border-right:0}
.sum .v{font-family:var(--mono);font-size:23px;font-weight:600}
.sum .v.acc{color:var(--acc)}.sum .v.air{color:var(--air)}.sum .v.flt{color:var(--flt)}
.sum .v small{font-size:12px;color:var(--faint)}
.sum .k{color:var(--dim);font-size:11px;text-transform:uppercase;letter-spacing:.7px;margin-top:3px}
.src{color:var(--faint);font-size:11px;text-align:center;padding-top:26px;font-family:var(--mono)}
.cc{font-size:11px;font-family:var(--mono);background:var(--raise);border:1px solid var(--line);padding:3px 8px;border-radius:999px;color:var(--dim);white-space:nowrap}
.cc.me{background:var(--acc);color:var(--on-acc);border-color:var(--acc);font-weight:700}
.cc .pos{opacity:.6}
.crew{display:flex;flex-wrap:wrap;gap:6px;margin-top:9px}
.dot{width:7px;height:7px;border-radius:50%;flex:none}
.st-ENRT{color:var(--air)}.st-ENRT .dot{background:var(--air)}
.st-PDEP{color:var(--flt)}.st-PDEP .dot{background:var(--flt)}
.st-OFBL{color:var(--trn)}.st-OFBL .dot{background:var(--trn)}
.st-ARVD{color:var(--faint)}.st-ARVD .dot{background:var(--faint)}
.st-CNLD{color:var(--bad)}.st-CNLD .dot{background:var(--bad)}
.st-SCHED{color:var(--faint)}.st-SCHED .dot{background:var(--faint)}
/* ── whatsapp ── */
.wa{display:inline-grid;place-items:center;width:19px;height:19px;border-radius:50%;background:#25D366;color:var(--on-acc);font-size:11px;font-weight:800;text-decoration:none;flex:none;line-height:1;vertical-align:middle}
.wa:hover{filter:brightness(1.12)}
.cc .wa{width:14px;height:14px;font-size:8.5px;margin-left:4px}
.wabtn{display:inline-flex;align-items:center;gap:7px;background:#25D366;color:var(--on-acc);font-weight:700;font-size:13px;padding:8px 14px;border-radius:12px;text-decoration:none;margin-bottom:14px}
.wabtn:hover{filter:brightness(1.12)}
/* ── modal ── */
.modal{position:fixed;inset:0;background:rgba(6,9,15,.72);backdrop-filter:blur(4px);z-index:60;display:none;align-items:center;justify-content:center;padding:20px}
.modal.on{display:flex}
.modal .box{background:var(--surface);border:1px solid var(--line);border-radius:16px;max-width:520px;width:100%;max-height:84vh;overflow:auto;padding:20px}
.modal .x{float:right;background:none;border:0;color:var(--faint);font-size:22px;cursor:pointer;line-height:1}
/* Clear of the status bar and the home indicator on a notched iPhone. */
.modal{padding:max(20px, env(safe-area-inset-top)) 20px max(20px, env(safe-area-inset-bottom))}
[dir=rtl] .modal .x{float:left}
.fn{font-family:var(--mono);font-size:12px;color:var(--dim);margin-bottom:4px}
.rtt{font-size:26px;font-weight:700;margin-bottom:14px}.rtt .ar{color:var(--faint);margin:0 8px}
.kvs{display:grid;grid-template-columns:repeat(auto-fit,minmax(108px,1fr));gap:10px;margin-bottom:16px}
/* ★ Scoped by .kvs: a second, older .kv rule (the grid of .b boxes above) made
   every one of these tiles a grid of 118px columns too. On an iPhone the tile
   is ~95px, so its date ran out of the box — to the left, in Hebrew — and the
   figure sat beside its label outside the tile (EDI's bid screen, 28/09/2026). */
.kvs .kv{display:block;min-width:0}
.kv{background:var(--raise);border:1px solid var(--line);border-radius:12px;padding:9px 11px}
.kv .k{font-size:10px;color:var(--faint);text-transform:uppercase;letter-spacing:.6px}
.kv .v{font-family:var(--mono);font-size:15px;font-weight:600;margin-top:1px}
.kv .v.air{color:var(--air)}.kv .v.flt{color:var(--flt)}
.kv .s{font-size:11px;color:var(--dim);margin-top:1px}
/* The caution mark is drawn once here rather than typed as ⚠ at ten call
   sites, where it inherited whatever the device's emoji font decided and
   sat a few pixels off the baseline in every one of them. */
.warn,.cvioe,.swioe{position:relative}
.warn::before,.cvioe::before,.swioe::before{content:"";position:absolute;left:11px;top:10px;
  width:14px;height:14px;background:var(--trn);
  -webkit-mask:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22%23000%22%20stroke-width%3D%221.9%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M10.3%203.9%201.9%2018.4A2%202%200%200%200%203.6%2021.4h16.8a2%202%200%200%200%201.7-3L13.7%203.9a2%202%200%200%200-3.4%200z%22%2F%3E%3Cpath%20d%3D%22M12%209.4v4M12%2016.8v.1%22%2F%3E%3C%2Fsvg%3E") center/contain no-repeat;mask:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22none%22%20stroke%3D%22%23000%22%20stroke-width%3D%221.9%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M10.3%203.9%201.9%2018.4A2%202%200%200%200%203.6%2021.4h16.8a2%202%200%200%200%201.7-3L13.7%203.9a2%202%200%200%200-3.4%200z%22%2F%3E%3Cpath%20d%3D%22M12%209.4v4M12%2016.8v.1%22%2F%3E%3C%2Fsvg%3E") center/contain no-repeat}
.cvioe,.swioe{padding-left:30px}
.cvioe::before,.swioe::before{left:10px;top:11px}
.tabn{display:inline-block;min-width:17px;height:17px;padding:0 5px;margin-inline-start:6px;border-radius:999px;
  background:var(--acc);color:var(--on-acc);font-style:normal;font-size:11px;font-weight:800;line-height:17px;
  text-align:center;vertical-align:1px}
a.rosbtn{display:block;text-align:center;text-decoration:none}

/* The demo's welcome, for an airline it was prepared for (core/demo.js). */
.demopitch{display:grid;gap:12px;padding:4px 2px 2px}
.demopitch .dp-eye{font:700 10px/1 var(--mono);letter-spacing:.18em;text-transform:uppercase;color:var(--acc-txt)}
.demopitch .dp-h{font-size:22px;font-weight:800;line-height:1.2;letter-spacing:-.01em}
.demopitch .dp-sub{font-size:14px;line-height:1.5;opacity:.8}
.demopitch .dp-list{list-style:none;margin:2px 0;padding:0;display:grid;gap:10px}
.demopitch .dp-list li{display:grid;gap:2px;padding-inline-start:12px;border-inline-start:2px solid var(--acc)}
.demopitch .dp-list b{font-size:14px}
.demopitch .dp-list span{font-size:13px;line-height:1.45;opacity:.75}
.demopitch .dp-note{font-size:12px;opacity:.6;line-height:1.4}
.demopitch .rosbtn{justify-self:stretch;padding:13px;font-weight:700;background:var(--acc);color:var(--on-acc);border-color:var(--acc)}
.demonote{margin:8px 0;padding:10px 12px;border-radius:10px;font-size:12.5px;line-height:1.45;
  background:color-mix(in srgb,var(--acc) 12%,transparent);border:1px solid color-mix(in srgb,var(--acc) 35%,transparent)}
.demochip .dc-s{display:none}
@media (max-width:440px){[dir=ltr] .demochip .dc-l{display:none}[dir=ltr] .demochip .dc-s{display:inline}}
