/* Vektro MSP app stylesheet (VEK-431, 2026-09-10): the hercules.app design
   language on our dark ground - Geist type, one indigo primary, hairline
   borders, tinted status pills, 14px cards, grouped sidebar, command palette.
   Extracted from base.html on 2026-08-07 (audit item 5) so it caches once via
   whitenoise. Fonts are self-hosted (no Google Fonts round-trip; works
   offline/PWA): Geist + Geist Mono are variable woff2 (SIL OFL), Inter stays
   on disk as the fallback stack. Token NAMES are unchanged on purpose -
   the templates reference var(--mut/--ok/--bad/--warn/--acc/--bd) in 700+
   places - only the values moved. */
@font-face{font-family:'Geist';font-style:normal;font-weight:400 700;font-display:swap;src:url("../fonts/geist-latin.a147f99cd533.woff2") format('woff2')}
@font-face{font-family:'Geist Mono';font-style:normal;font-weight:400 600;font-display:swap;src:url("../fonts/geist-mono-latin.a15f9d568fb0.woff2") format('woff2')}
@font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url("../fonts/inter-latin-400.da03732a27e1.woff2") format('woff2')}
@font-face{font-family:'Inter';font-style:normal;font-weight:500;font-display:swap;src:url("../fonts/inter-latin-500.51205681a1ba.woff2") format('woff2')}
@font-face{font-family:'Inter';font-style:normal;font-weight:600;font-display:swap;src:url("../fonts/inter-latin-600.2ede57db1a3a.woff2") format('woff2')}
@font-face{font-family:'Inter';font-style:normal;font-weight:700;font-display:swap;src:url("../fonts/inter-latin-700.8ca0a5155296.woff2") format('woff2')}
    :root{
      color-scheme:dark;
      /* surfaces */
      --bg:#09090b; --bg-2:#0f0f12; --card:#131316; --panel:#0f0f12; --hover:#1c1c21; --surf-2:#18181b;
      --bd:#27272a; --bd-soft:#1f1f23;
      /* ink */
      --tx:#fafafa; --text:#fafafa; --tx-2:#d4d4d8; --mut:#a1a1aa; --dim:#71717b;
      /* one primary: indigo. --acc is the TEXT/icon shade (AA on the card),
         --btn the fill, --acc-tint the wash behind active nav / chips. */
      --acc:#8e8ef2; --acc-2:#aaaaf3; --acc-ink:#0b0b2e; --acc-tint:rgba(114,114,241,.16); --acc-tint-2:rgba(114,114,241,.24);
      --btn:#5151ef; --btn-hover:#7272f1; --focus:rgba(114,114,241,.28);
      /* status: ink shade + 16% wash */
      --ok:#34d399; --warn:#fbbf24; --bad:#f87171; --info:#60a5fa; --cyan:#2dd4bf;
      --ok-tint:rgba(16,185,129,.16); --warn-tint:rgba(245,158,11,.16); --bad-tint:rgba(239,68,68,.16); --info-tint:rgba(59,130,246,.16); --cyan-tint:rgba(45,212,191,.16);
      --radius:14px; --radius-sm:8px; --sb:236px;
      --font:'Geist','Inter',system-ui,-apple-system,Segoe UI,Roboto,sans-serif;
      --mono:'Geist Mono',ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
      --shadow:0 1px 2px rgba(0,0,0,.35);
    }
    *{box-sizing:border-box}
    /* overflow-x:CLIP not hidden. `hidden` forces overflow-y to `auto`, turning
       <body> into a scroll container that never scrolls — which traps EVERY
       position:sticky element (topbar, sidebar, table headers) relative to a
       body that doesn't move, so none of them stick. `clip` prevents horizontal
       scroll the same way without creating a scroll container. */
    html,body{margin:0;overflow-x:clip;width:100%;max-width:100%}
    body{background:var(--bg);color:var(--tx);font:400 13.5px/1.5 var(--font);-webkit-font-smoothing:antialiased;
      /* the one decorative element: a 64px diagonal hairline grid at 3.5% */
      background-image:linear-gradient(45deg,rgba(255,255,255,.035) 1px,transparent 1px),linear-gradient(-45deg,rgba(255,255,255,.035) 1px,transparent 1px);
      background-size:64px 64px;background-attachment:fixed}
    a{color:var(--acc);text-decoration:none} a:hover{color:var(--acc-2)}
    h1{font-size:22px;font-weight:600;letter-spacing:-.02em;margin:.1rem 0 1rem}
    h2{font-size:14px;font-weight:600;letter-spacing:-.005em}
    code,pre,.mono{font-family:var(--mono)}
    ::selection{background:rgba(114,114,241,.35)}

    .shell{display:flex;min-height:100vh}
    .sidebar{width:var(--sb);flex:0 0 var(--sb);background:var(--bg-2);border-right:1px solid var(--bd);
      position:sticky;top:0;height:100vh;height:100dvh;display:flex;flex-direction:column;min-height:0}
    .brand{display:flex;align-items:center;gap:.6rem;padding:1.1rem 1.2rem;font-weight:700;letter-spacing:-.02em;font-size:1.05rem}
    .brand .dot{width:26px;height:26px;border-radius:8px;background:var(--btn);
      display:grid;place-items:center;color:#fff;font-weight:800;font-size:.8rem}
    .nav{display:flex;flex-direction:column;gap:2px;padding:.2rem .6rem .6rem;flex:1;
      min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:var(--bd) transparent}
    .nav .sec{font-size:10.5px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--mut);padding:.85rem .65rem .35rem}
    .nav .sec:first-child{padding-top:.3rem}
    .nav a{display:flex;align-items:center;gap:.65rem;height:34px;padding:0 .65rem;border-radius:var(--radius-sm);color:var(--tx-2);
      font-weight:500;font-size:13px;transition:background .15s,color .15s;white-space:nowrap;overflow:hidden}
    .nav a span:first-of-type{overflow:hidden;text-overflow:ellipsis}
    .nav a svg{width:17px;height:17px;flex:0 0 17px;stroke-width:1.8;color:var(--mut)}
    .nav a:hover{background:var(--hover);color:var(--tx)}
    .nav a.active{background:var(--acc-tint);color:#e3e3fa;font-weight:600}
    .nav a.active svg{color:var(--acc)}
    .badge{margin-left:auto;min-width:20px;height:20px;padding:0 6px;border-radius:999px;font-size:11px;font-weight:600;display:inline-grid;place-items:center;line-height:1}
    .badge.ok{background:var(--ok-tint);color:var(--ok)} .badge.warn{background:var(--warn-tint);color:var(--warn)}
    .badge.bad{background:var(--bad-tint);color:var(--bad)} .badge.info{background:var(--info-tint);color:var(--info)}
    .side-foot{border-top:1px solid var(--bd);padding:.65rem .8rem;display:flex;align-items:center;gap:.6rem}
    .side-foot .who{min-width:0;flex:1}
    .side-foot .who b{display:block;font-size:12.5px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
    .side-foot .who span{font-size:11px;color:var(--mut)}
    .avatar{width:28px;height:28px;border-radius:50%;display:inline-grid;place-items:center;font-size:12px;font-weight:600;
      background:var(--acc-tint-2);color:#c5c5f6;flex:0 0 28px;text-transform:uppercase}
    .avatar.neutral{background:var(--hover);color:var(--tx-2)}
    .icon-btn{background:var(--card);border:1px solid var(--bd);color:var(--mut);border-radius:var(--radius-sm);padding:.35rem;cursor:pointer;display:grid;place-items:center;transition:.15s}
    .icon-btn:hover{color:var(--bad);border-color:var(--bad)} .icon-btn svg{width:16px;height:16px}
    .icon-btn.refresh:hover{color:var(--acc);border-color:var(--acc)}

    .main-wrap{flex:1;min-width:0;max-width:100%;display:flex;flex-direction:column}
    .topbar{height:calc(56px + env(safe-area-inset-top));display:flex;align-items:center;gap:.8rem;padding:env(safe-area-inset-top) 1.4rem 0;border-bottom:1px solid var(--bd);
      position:sticky;top:0;background:rgba(12,12,15,.85);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);z-index:5}
    .topbar .menu{display:none;background:transparent;border:0;color:var(--tx);cursor:pointer;padding:0}
    .topbar .crumb{font-size:12.5px;color:var(--mut)}
    .topbar .spacer{flex:1}
    /* the search box is a BUTTON that opens the palette (the input lives in
       the palette) so the topbar never holds focus and iOS never zooms it */
    .cmdk-btn{display:inline-flex;align-items:center;gap:.5rem;height:34px;width:min(360px,34vw);padding:0 .7rem;border-radius:var(--radius-sm);
      background:var(--surf-2);border:1px solid var(--bd);color:var(--mut);font:inherit;font-size:12.5px;cursor:pointer;text-align:left}
    .cmdk-btn:hover{border-color:var(--dim);color:var(--tx-2)}
    .cmdk-btn svg{width:15px;height:15px;stroke-width:2;flex:0 0 auto}
    .cmdk-btn span{flex:1;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
    .kbd{font-family:var(--mono);font-size:10.5px;color:var(--mut);border:1px solid var(--bd);border-radius:5px;padding:1px 5px;background:var(--bg-2);line-height:1.3}
    .health{display:none;align-items:center;gap:6px;height:26px;padding:0 10px;border-radius:999px;font-size:11.5px;font-weight:600;white-space:nowrap}
    .health .dot{width:6px;height:6px;border-radius:50%;background:currentColor}
    .health.ok{display:inline-flex;background:var(--ok-tint);color:var(--ok)}
    .health.warn{display:inline-flex;background:var(--warn-tint);color:var(--warn)}
    .health.bad{display:inline-flex;background:var(--bad-tint);color:var(--bad)}
    main{padding:1.6rem 1.8rem 2.4rem;max-width:1140px;width:100%}
    main.auth{max-width:420px;margin:0 auto;padding-top:14vh}

    .card{background:var(--card);border:1px solid var(--bd);border-radius:var(--radius);padding:1.1rem 1.25rem;margin-bottom:1rem;box-shadow:var(--shadow);transition:border-color .15s,transform .15s}
    a > .card:hover,.card.hover:hover{border-color:var(--dim);transform:translateY(-1px)}
    .muted{color:var(--mut)} .sm{font-size:12px} .dim{color:var(--dim)}
    table{width:100%;border-collapse:collapse}
    thead th{color:var(--mut);font-weight:600;font-size:11px;text-transform:uppercase;letter-spacing:.06em;padding:.65rem .9rem;border-bottom:1px solid var(--bd);text-align:left;background:var(--surf-2)}
    tbody td{padding:.6rem .9rem;border-top:1px solid var(--bd-soft)}
    tbody tr{transition:background .12s} tbody tr:hover{background:var(--hover)}
    button,input,select,textarea{font:inherit}
    button{background:var(--btn);color:#fff;border:0;border-radius:var(--radius-sm);padding:.45rem .85rem;font-weight:500;font-size:13px;cursor:pointer;transition:background .15s,transform .05s;box-shadow:0 1px 2px rgba(0,0,0,.25)}
    button:hover{background:var(--btn-hover)} button:active{transform:translateY(1px)}
    button.warn,button.ghost{background:var(--card);color:var(--tx-2);border:1px solid var(--bd);box-shadow:none}
    button.warn:hover,button.ghost:hover{color:var(--tx);background:var(--hover)}
    button.danger{background:var(--card);color:var(--bad);border:1px solid rgba(239,68,68,.4);box-shadow:none}
    button.danger:hover{background:var(--bad-tint)}
    button:disabled{opacity:.45;cursor:not-allowed}
    input,select,textarea{width:100%;background:var(--panel);color:var(--tx);border:1px solid var(--bd);border-radius:var(--radius-sm);padding:.45rem .65rem;margin:.25rem 0 .85rem;transition:border-color .15s,box-shadow .15s}
    input::placeholder,textarea::placeholder{color:var(--dim)}
    input:focus,select:focus,textarea:focus{outline:0;border-color:var(--btn-hover);box-shadow:0 0 0 3px var(--focus)}
    label{font-size:12px;color:var(--mut)}
    .pill{display:inline-flex;align-items:center;gap:.35rem;padding:0 .55rem;height:22px;border-radius:999px;font-size:11.5px;font-weight:600;line-height:1;vertical-align:middle}
    .pill.ok{background:var(--ok-tint);color:var(--ok)} .pill.warn{background:var(--warn-tint);color:var(--warn)}
    .pill.bad{background:var(--bad-tint);color:var(--bad)} .pill.info{background:var(--info-tint);color:var(--info)}
    .pill.acc{background:var(--acc-tint);color:var(--acc-2)} .pill.neutral{background:var(--hover);color:var(--tx-2)}
    .pill .dot{width:6px;height:6px;border-radius:50%;background:currentColor}
    .msg{padding:.6rem .85rem;border-radius:var(--radius-sm);margin-bottom:.7rem;background:var(--info-tint);border:1px solid rgba(59,130,246,.35);color:#bcd4ff}

    .stat-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:.9rem;margin-bottom:1.4rem}
    .stat{background:var(--card);border:1px solid var(--bd);border-radius:var(--radius);padding:1rem 1.1rem .9rem;box-shadow:var(--shadow);transition:.15s}
    .stat:hover{border-color:var(--dim);transform:translateY(-1px)}
    .stat .label{font-size:11px;font-weight:600;letter-spacing:.07em;text-transform:uppercase;color:var(--mut);display:flex;align-items:center;gap:.5rem}
    .stat .label svg{width:14px;height:14px;color:var(--acc);stroke-width:2}
    .stat .value{font-size:28px;font-weight:600;letter-spacing:-.02em;line-height:1.1;margin-top:.5rem}
    .stat .delta{font-size:12px;font-weight:600;margin-left:.4rem}
    .stat .sub{font-size:12px;color:var(--mut);margin-top:.25rem}
    .empty{color:var(--mut);padding:1.6rem;text-align:center}

    /* segmented control (facet tabs): a light pill in a dark track */
    .seg{display:inline-flex;background:var(--surf-2);border:1px solid var(--bd);border-radius:10px;padding:3px;gap:2px;flex-wrap:wrap}
    .seg a,.seg button{height:28px;padding:0 .75rem;border-radius:7px;display:inline-flex;align-items:center;gap:.4rem;font-size:12.5px;font-weight:500;color:var(--tx-2);background:transparent;border:0;box-shadow:none;cursor:pointer}
    .seg a b,.seg button b{font-weight:500;color:var(--mut)}
    .seg a:hover,.seg button:hover{background:var(--hover);color:var(--tx)}
    .seg a.on,.seg button.on,.seg .facet-on{background:var(--card);color:var(--tx);font-weight:600;box-shadow:0 1px 2px rgba(0,0,0,.3),0 0 0 1px var(--bd)}
    .seg a.on b,.seg button.on b,.seg .facet-on b{color:var(--acc)}
    /* the pre-VEK-431 facet pills keep working: same look, no markup change needed */
    .facet-tab{background:transparent;color:var(--mut);border:1px solid var(--bd);box-shadow:none}
    .facet-tab.facet-on{background:var(--acc-tint);color:#e3e3fa;border-color:transparent}

    .two-col{display:grid;grid-template-columns:1fr 1fr;gap:1rem}
    .page-head{display:flex;align-items:center;gap:1rem;margin-bottom:.9rem;flex-wrap:wrap}

    /* command palette (⌘K / Ctrl-K / "/") */
    .cmdk{position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:60;display:none;align-items:flex-start;justify-content:center;padding:10vh 1rem 1rem;backdrop-filter:blur(2px)}
    .cmdk.open{display:flex}
    .cmdk .box{width:min(680px,100%);background:var(--card);border:1px solid var(--bd);border-radius:var(--radius);box-shadow:0 24px 60px rgba(0,0,0,.6);overflow:hidden}
    .cmdk .in{display:flex;align-items:center;gap:.6rem;padding:0 1rem;border-bottom:1px solid var(--bd)}
    .cmdk .in svg{width:17px;height:17px;color:var(--mut);stroke-width:2;flex:0 0 auto}
    .cmdk input{margin:0;border:0;background:transparent;height:52px;font-size:15px;padding:0;box-shadow:none}
    .cmdk input:focus{box-shadow:none;border:0}
    .cmdk .res{max-height:min(60vh,520px);overflow-y:auto;padding:.4rem}
    .cmdk .grp{font-size:10.5px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--mut);padding:.6rem .7rem .25rem}
    .cmdk .it{display:flex;align-items:center;gap:.7rem;padding:.5rem .7rem;border-radius:var(--radius-sm);color:var(--tx);cursor:pointer}
    .cmdk .it .t{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
    .cmdk .it .s{font-size:12px;color:var(--mut);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:45%}
    .cmdk .it.sel,.cmdk .it:hover{background:var(--acc-tint);color:#e3e3fa}
    .cmdk .hint{padding:.55rem .9rem;border-top:1px solid var(--bd-soft);display:flex;gap:1rem;font-size:11.5px;color:var(--dim)}
    .cmdk .none{padding:1.2rem .9rem;color:var(--mut);text-align:center}
    /* Keep table column headers visible while scrolling a long list. Sticks just
       below the (already-sticky) topbar. Desktop only: on phones qualifying
       tables reflow to cards (no header row) and the rest scroll horizontally,
       where a viewport-sticky header fights the scroll container. z-index sits
       below the topbar (5) but above tbody rows. */
    @media(min-width:821px){
      /* A page can pin its whole title/search/tabs block by wrapping it in
         .sticky-band; the column header then sticks just below it (--thead-top
         is measured by JS so it works whatever the band's height). */
      .sticky-band{position:sticky;top:calc(56px + env(safe-area-inset-top));
        background:var(--bg);z-index:4}
      /* A card wrapping one of these tables must clip with overflow:clip,
         never overflow:hidden. hidden makes the card a scroll container, so
         this rule resolves against the card instead of the page: the card
         never scrolls, but the 56px offset still applies, and the header is
         shifted down over the first row -- which stays in the DOM, keeps its
         box, and simply cannot be seen. clip clips identically without
         creating a scrollport. */
      thead th{position:sticky;top:var(--thead-top, calc(56px + env(safe-area-inset-top)));
        background:var(--surf-2);z-index:3}
      /* A wrapper that scrolls a wide table sideways is a scroll container too,
         so the rule above resolves against the wrapper rather than the page --
         exactly the overflow:hidden trap described above, reached a different
         way. The wrapper never scrolls vertically, but the offset still applies
         and shifts the header down over the first row, which keeps its box and
         simply cannot be seen. (Found 2026-08-05: a client's first DR device
         was invisible on the page but present in a full-page capture, because
         that capture renders with the header unstuck.) Pin to the wrapper's own
         top; horizontal scrolling is untouched. */
      .tscroll thead th{top:0}
    }
    @media(max-width:820px){
      .sidebar{position:fixed;left:0;top:0;z-index:30;transform:translateX(-100%);transition:transform .2s;box-shadow:0 0 40px #000a;
        padding-top:env(safe-area-inset-top);height:100vh;height:100dvh;max-height:100vh;max-height:100dvh;overscroll-behavior:contain}
      /* iOS: keep the logout/user footer above the home indicator */
      .side-foot{padding-bottom:calc(.7rem + env(safe-area-inset-bottom))}
      .sidebar.open{transform:none}
      .topbar .menu{display:block}
      .topbar{padding-left:1rem;padding-right:1rem;gap:.6rem}
      .cmdk-btn{width:34px;padding:0;justify-content:center;background:transparent;border-color:transparent}
      .cmdk-btn span,.cmdk-btn .kbd,.cmdk .hint{display:none}
      .health{display:none!important}
      .cmdk{padding:2vh .6rem}
      main{padding:1.1rem 1rem}
      .scrim{position:fixed;inset:0;background:#0008;z-index:20;display:none}
      .scrim.show{display:block}
      /* wide tables scroll inside themselves — NOT the whole card, so forms
         sharing a card with a wide table stay at screen width */
      table{display:block;overflow-x:auto;-webkit-overflow-scrolling:touch}
      /* one-line cells so the table scrolls instead of crushing columns
         (verified in-browser at 392px: header stacks, tables scroll) */
      td,th{white-space:nowrap}
      #board{grid-template-columns:1fr!important}
      .two-col{grid-template-columns:1fr}
      .page-head{flex-direction:column;align-items:stretch;gap:.55rem}
      .page-head>h1{margin:0}
      .page-head .searchbox{width:100%!important;margin:0!important}
      .page-head form{width:100%;margin:0}
      h1{font-size:20px}
      .stat .value{font-size:24px}
      .stat-grid{gap:.7rem;margin-bottom:1.1rem}
      thead th{padding:.55rem .65rem;font-size:.68rem}
      tbody td{padding:.5rem .65rem}
      /* iOS Safari zooms the page when focusing an input <16px — pin to 16px */
      input,select,textarea{font-size:16px}
      /* nothing may widen the viewport; wide tables scroll inside their .card */
      img,canvas,pre,video{max-width:100%}
      /* clamp inline fixed px widths (modals, panels, forms) to the screen */
      div,form,fieldset,section{max-width:100%!important}
      /* data tables: never crush columns — keep natural width, scroll in .card */
      .pill{white-space:nowrap}
      /* collapse fixed multi-column inline grids (forms, panels) to one column */
      div[style*="grid-template-columns:1fr 1fr"],
      div[style*="grid-template-columns:repeat(3,1fr)"],
      div[style*="grid-template-columns:2fr 1fr"],
      div[style*="grid-template-columns:auto 1fr"],
      div[style*="grid-template-columns:110px 1fr"]{grid-template-columns:1fr!important}
      /* 360 router form: single column on phones */
      [id^="rtrf-"]{grid-template-columns:1fr!important;max-width:100%!important}
      /* collapse EVERY inline column-grid to one column on phones */
      [style*="grid-template-columns"]{grid-template-columns:1fr!important}
      /* break long unbroken strings (emails, PPPoE, keys) instead of overflowing */
      main{overflow-wrap:break-word}
      /* --- Phone: reflow qualifying list tables into stacked cards, so there is
         NO sideways scrolling. The script tags safe tables .mobitable and sets
         data-label on each cell from its column header. --- */
      table.mobitable,table.mobitable tbody{display:block;overflow:visible}
      table.mobitable thead{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
      table.mobitable tr{display:block;border:1px solid var(--bd);border-radius:12px;background:var(--card);padding:.5rem .8rem;margin-bottom:.6rem}
      table.mobitable td{display:flex;justify-content:space-between;gap:1rem;align-items:baseline;white-space:normal;text-align:right;border:0;padding:.22rem 0}
      table.mobitable td::before{content:attr(data-label);color:var(--mut);font-size:.72rem;font-weight:600;text-align:left;white-space:nowrap;flex:0 0 auto}
      table.mobitable td:first-child{display:block;text-align:left;font-weight:600;font-size:1.02rem;border-bottom:1px solid var(--bd-soft);padding-bottom:.35rem;margin-bottom:.3rem}
      table.mobitable td:first-child::before{display:none}
      table.mobitable td:not([data-label])::before{display:none}
      /* colspan panel rows (e.g. the 360 service detail) stay full-width blocks, no card chrome */
      table.mobitable td[colspan]{display:block;width:100%;text-align:left;padding:0;border:0;font-weight:400;font-size:.95rem}
      table.mobitable td[colspan]::before{display:none}
      table.mobitable tr:has(td[colspan]){border:0;background:transparent;padding:0;margin:.2rem 0}
      /* never let a fixed-width input/select push the page wide */
      main input:not([type=checkbox]):not([type=radio]),main select,main textarea{max-width:100%}
    }
    @media(max-width:430px){
      .stat-grid{grid-template-columns:1fr 1fr}
      .brand{font-size:1rem;padding:1rem}
      main{padding:1rem .8rem}
    }
    @supports(padding:max(0px)){ body{padding-bottom:env(safe-area-inset-bottom)} }

    /* ---- VEK-433: list pages (Clients, Internet customers) ---------------- */
    main.wide{max-width:none}
    .kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(148px,1fr));gap:.6rem;margin:0 0 .9rem}
    .kpi{background:var(--card);border:1px solid var(--bd);border-radius:var(--radius);padding:.7rem .9rem .75rem;text-align:left;font:inherit;color:var(--tx);cursor:pointer;display:flex;flex-direction:column;gap:.2rem;min-width:0;transition:border-color .15s,background .15s;box-shadow:var(--shadow)}
    .kpi:hover{border-color:var(--acc);background:var(--hover)}
    .kpi.facet-on,.kpi.on{border-color:var(--acc);box-shadow:inset 0 0 0 1px var(--acc);background:var(--acc-tint)}
    .kpi .l{font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--mut)}
    .kpi .v{font-size:22px;font-weight:600;letter-spacing:-.02em;line-height:1.1;font-variant-numeric:tabular-nums}
    .kpi .s{font-size:11.5px;color:var(--mut);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
    .kpi.ok .v{color:var(--ok)} .kpi.bad .v{color:var(--bad)} .kpi.warn .v{color:var(--warn)} .kpi.info .v{color:var(--info)} .kpi.acc .v{color:var(--acc-2)}
    .kpi.zero .v{color:var(--mut)}
    .toolbar{display:flex;align-items:center;gap:.6rem;flex-wrap:wrap;margin-bottom:.8rem}
    .toolbar .grow{flex:1}
    .toolbar select{margin:0;height:32px;width:auto;font-size:12.5px;padding:0 1.6rem 0 .6rem}
    .bar{position:relative;height:5px;border-radius:999px;background:var(--hover);overflow:hidden;min-width:56px;flex:1}
    .bar>i{position:absolute;top:0;bottom:0;left:0;border-radius:999px;background:var(--ok)}
    .bar.warn>i{background:var(--warn)} .bar.bad>i{background:var(--bad)} .bar.acc>i{background:var(--acc)} .bar.info>i{background:var(--info)}
    .sdot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--mut);flex:0 0 auto}
    .sdot.ok{background:var(--ok);box-shadow:0 0 0 3px var(--ok-tint)} .sdot.bad{background:var(--bad);box-shadow:0 0 0 3px var(--bad-tint)}
    .sdot.warn{background:var(--warn);box-shadow:0 0 0 3px var(--warn-tint)} .sdot.info{background:var(--info);box-shadow:0 0 0 3px var(--info-tint)} .sdot.acc{background:var(--acc);box-shadow:0 0 0 3px var(--acc-tint)}
    .st{display:flex;align-items:center;gap:.5rem;white-space:nowrap} .st .t{font-weight:500} .st .d{font-size:11.5px;color:var(--mut)}
    .st.bad .t{color:var(--bad)} .st.ok .t{color:var(--ok)} .st.warn .t{color:var(--warn)} .st.info .t{color:var(--info)} .st.acc .t{color:var(--acc-2)}
    .tbl{padding:0;overflow:clip}
    .tbl tbody tr{transition:background .1s} .tbl tbody tr:hover{background:var(--hover)}
    .tbl td{vertical-align:middle}
    .tbl .who{display:flex;align-items:center;gap:.65rem;min-width:0}
    .tbl .who .n{font-weight:500;color:var(--tx);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:34ch}
    .tbl .who .n a{color:inherit;text-decoration:none} .tbl .who .n a:hover{color:var(--acc-2)}
    .tbl .who .sub{font-size:11.5px;color:var(--mut);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:34ch}
    .tbl .svc .p{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:36ch;display:block}
    .tbl .svc .m{font-size:11.5px;color:var(--mut);display:flex;gap:.35rem;align-items:center;margin-top:.15rem}
    .tag{display:inline-flex;align-items:center;height:18px;padding:0 .4rem;border-radius:5px;font-size:10.5px;font-weight:600;letter-spacing:.02em;background:var(--hover);color:var(--tx-2);white-space:nowrap}
    .tag.acc{background:var(--acc-tint);color:var(--acc-2)} .tag.info{background:var(--info-tint);color:var(--info)} .tag.ok{background:var(--ok-tint);color:var(--ok)} .tag.warn{background:var(--warn-tint);color:var(--warn)} .tag.bad{background:var(--bad-tint);color:var(--bad)}
    .usage{display:flex;align-items:center;gap:.6rem;min-width:150px} .usage .g{font-variant-numeric:tabular-nums;white-space:nowrap;min-width:5.5ch;text-align:right} .usage .pc{font-size:11.5px;color:var(--mut);white-space:nowrap;min-width:3.5ch}
    .ract{display:inline-flex;gap:.25rem;opacity:0;transition:opacity .12s;justify-content:flex-end}
    tr:hover .ract,tr:focus-within .ract{opacity:1}
    .ract a,.ract button{height:26px;width:26px;display:inline-grid;place-items:center;border-radius:7px;border:1px solid var(--bd);background:var(--card);color:var(--tx-2);padding:0;margin:0;text-decoration:none}
    .ract a:hover,.ract button:hover{color:var(--tx);border-color:var(--acc);background:var(--card)}
    .ract svg{width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
    th.sortable{cursor:pointer;user-select:none;white-space:nowrap} th.sortable:hover{color:var(--tx)}
    th.sortable::after{content:"\2195";opacity:.35;margin-left:.35rem;font-size:10px}
    th.sortable.asc::after{content:"\2191";opacity:1;color:var(--acc-2)} th.sortable.desc::after{content:"\2193";opacity:1;color:var(--acc-2)}
    .mono{font-family:var(--mono);font-size:12px} .num{font-variant-numeric:tabular-nums}
    .tbl .empty{padding:2.2rem 1rem}
    @media(max-width:820px){.kpis{grid-template-columns:repeat(2,1fr)} .ract{opacity:1} .tbl .who .n,.tbl .who .sub{max-width:22ch} .kpi .v{font-size:19px}}

    th[data-sort]{cursor:pointer;user-select:none;white-space:nowrap} th[data-sort]:hover{color:var(--tx)}
    th[data-sort]::after{content:"\2195";opacity:.35;margin-left:.35rem;font-size:10px}
    th[data-sort].asc::after{content:"\2191";opacity:1;color:var(--acc-2)} th[data-sort].desc::after{content:"\2193";opacity:1;color:var(--acc-2)}

    .st .d{max-width:36ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} .st>div{min-width:0}
    a.kpi{text-decoration:none}

    /* ---- VEK-433 detail pages ---------------------------------------------- */
    .dhead{display:flex;align-items:flex-start;gap:.9rem;flex-wrap:wrap;margin:0 0 1rem}
    .dhead .avatar.lg{width:46px;height:46px;flex:0 0 46px;font-size:18px;border-radius:13px}
    .dhead h1{margin:0;font-size:21px;letter-spacing:-.02em;display:flex;align-items:center;gap:.55rem;flex-wrap:wrap;line-height:1.2}
    .dhead h1 .tag{max-width:40ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:inline-block;vertical-align:middle}
    .dhead .sub{color:var(--mut);font-size:12.5px;margin-top:.3rem;display:flex;gap:.35rem .6rem;flex-wrap:wrap;align-items:center}
    .dhead .sub a{color:var(--tx-2)}
    .dhead .acts{margin-left:auto;display:flex;gap:.45rem;align-items:center;flex-wrap:wrap}
    .dhead .acts button,.dhead .acts a>button{margin:0}
    .dgrid{display:grid;grid-template-columns:minmax(0,1.55fr) minmax(0,1fr);gap:1rem;align-items:start}
    .dgrid.even{grid-template-columns:1fr 1fr}
    @media(max-width:1000px){.dgrid,.dgrid.even{grid-template-columns:1fr}}
    .facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(165px,1fr));gap:.75rem 1.2rem}
    .facts .f .k{font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--mut)}
    .facts .f .v{font-size:13.5px;margin-top:.15rem;word-break:break-word}
    .kv{display:grid;grid-template-columns:auto 1fr;gap:.4rem 1rem;font-size:13px;align-items:baseline}
    .kv .k{color:var(--mut);white-space:nowrap}
    .sh{display:flex;align-items:center;gap:.55rem;margin:1.25rem 0 .55rem}
    .sh h2{margin:0;font-size:15px;letter-spacing:-.01em}
    .sh .r{margin-left:auto;display:flex;gap:.4rem;align-items:center}
    .card>h2:first-child,.card>.sh:first-child{margin-top:0}
    .card>.sh:first-child{margin-bottom:.7rem}
    .timeline .ev{display:flex;gap:.7rem;padding:.7rem 0;border-top:1px solid var(--bd-soft)}
    .timeline .ev:first-child{border-top:0;padding-top:.1rem}
    .timeline .ev .body{min-width:0;flex:1}
    .timeline .ev .meta{font-size:11.5px;color:var(--mut);margin-bottom:.2rem;display:flex;gap:.4rem;flex-wrap:wrap;align-items:center}
    .timeline .ev .txt{white-space:pre-wrap;font-size:13.5px;line-height:1.5}
    .timeline .ev.internal .txt{background:var(--warn-tint);border:1px solid rgba(245,158,11,.3);border-radius:10px;padding:.55rem .75rem}
    .composer textarea{width:100%;min-height:84px;margin:0}
    .composer .row{display:flex;align-items:center;gap:1rem;margin-top:.5rem}
    .bub{max-width:78%;padding:.55rem .8rem;border-radius:14px;background:var(--card);border:1px solid var(--bd);font-size:13.5px;line-height:1.45;white-space:pre-wrap}
    .bub.out{background:var(--acc-tint);border-color:rgba(81,81,239,.35);border-bottom-right-radius:4px}
    .bub.in{border-bottom-left-radius:4px}
    .bub .m{font-size:10.5px;color:var(--mut);margin-top:.3rem;text-align:right;white-space:normal}
    .bubwrap{display:flex;margin-bottom:.45rem} .bubwrap.out{justify-content:flex-end}
    .fgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:0 .9rem}
    .fgrid .full{grid-column:1/-1}
    .cred{display:grid;grid-template-columns:110px 1fr;gap:.5rem .9rem;align-items:center;font-size:13px}
    .cred .k{color:var(--mut)} .cred input{margin:0}
    .cred .pw{display:flex;gap:.35rem;align-items:center;flex-wrap:wrap}
    /* .stat tiles (client 360 header numbers) match the KPI cards */
    .stat-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(148px,1fr));gap:.6rem;margin:0 0 1rem}
    .stat{padding:.7rem .9rem .75rem}
    .stat .value{font-size:22px;margin-top:.2rem}
    h2[id^="sec-"]{font-size:15px!important;letter-spacing:-.01em;display:flex;align-items:center;gap:.5rem;margin:1.3rem 0 .6rem!important}
    /* ---- VEK-448 client 360 (templates/client_detail.html + js/client360.js) -- */
    /* section tabs, shared with Server 360 (was inline <style> in both templates) */
    .c360tabs{position:sticky;top:calc(56px + env(safe-area-inset-top));z-index:4;display:flex;gap:2px;overflow-x:auto;scrollbar-width:none;background:var(--bg);margin:0 0 .9rem;padding:.35rem 0;border-bottom:1px solid var(--bd)}
    .c360tabs::-webkit-scrollbar{display:none}
    .c360tabs a{flex:0 0 auto;height:30px;padding:0 .75rem;border-radius:7px;display:inline-flex;align-items:center;gap:.35rem;font-size:12.5px;font-weight:500;color:var(--tx-2);white-space:nowrap;text-decoration:none}
    .c360tabs a b{font-weight:500;color:var(--mut);font-size:11.5px}
    .c360tabs a:hover{background:var(--hover);color:var(--tx)}
    .c360tabs a.on{background:var(--acc-tint);color:#e3e3fa;font-weight:600}
    .c360tabs a.on b{color:var(--acc)}
    @media(max-width:820px){.c360tabs{position:static}}
    .dhead .main{min-width:0;flex:1}
    .dhead h1 .edit-link{font-size:11.5px;font-weight:500;text-decoration:none;letter-spacing:0}
    .dhead .acts form{margin:0}
    .dhead .acts .danger{color:var(--bad);border-color:var(--bad)}
    .sh h2[id^="sec-"]{margin:0!important;scroll-margin-top:110px}
    .sh h2 a{color:inherit;text-decoration:none}
    .anchor{scroll-margin-top:110px}
    .c-ok{color:var(--ok)} .c-bad{color:var(--bad)} .c-warn{color:var(--warn)}
    .xs{font-size:11px}
    .errline{margin:-.4rem 0 .8rem}
    .c360 .idcopy{font-family:var(--mono);font-size:11.5px;user-select:all;cursor:text}
    .c360 .stat .value .of{font-size:15px;font-weight:500} .c360 .stat .value .unit{font-size:13px;font-weight:500}
    .c360 .kv{gap:.3rem .9rem} .c360 .kv .full{grid-column:1/-1}
    .c360 .edit{margin-top:.7rem;padding-top:.6rem;border-top:1px solid var(--bd-soft)}
    .c360 .card.edit.wide{margin-top:0;padding-top:1.1rem;border-top:1px solid var(--bd);max-width:640px}
    .c360 .edit label{display:block;font-size:12px;margin-top:.35rem}
    .c360 .edit input,.c360 .edit select,.c360 .edit textarea{width:100%;margin:.15rem 0 0}
    .c360 .row{display:flex;gap:.5rem;align-items:center;margin-top:.55rem} .c360 .row.wrap{flex-wrap:wrap;gap:.6rem;margin-top:0}
    .c360 .chk{display:inline-flex;align-items:center;gap:.35rem;cursor:pointer;margin:0;white-space:nowrap} .c360 .chk select{margin:0}
    .c360 .hint{margin:.45rem 0 0}
    .c360 .line{display:flex;justify-content:space-between;gap:1rem;padding:.4rem 0;border-bottom:1px solid var(--bd-soft)} .c360 .line>:last-child{text-align:right}
    .c360 .devs{margin-top:.5rem}
    .c360 .devrow{display:flex;align-items:center;gap:.55rem;padding:.32rem 0} .c360 .devrow .led{font-size:.7rem} .c360 .devrow .model{margin-left:auto} .c360 .devrow .ip{min-width:118px;text-align:right}
    .c360 .card.alert{border-color:rgba(248,113,113,.45)}
    .c360 .cams{display:flex;flex-wrap:wrap;gap:.45rem}
    .c360 .cam{border:1px solid var(--bd);border-radius:99px;padding:.12rem .6rem;font-size:12px}
    .c360 .cam.bad{border-color:rgba(248,113,113,.5);color:var(--bad)} .c360 .cam.dim{border-style:dashed;color:var(--mut)}
    .c360 .usage{min-width:120px} .c360 .usage .pc{font-weight:600}
    .c360 td.sub2{padding:0 0 .6rem 1rem;background:#ffffff05} .c360 td.sub2>.muted{margin:.4rem 0 .2rem} .c360 table.inner{width:100%}
    .c360 .drbox{margin-bottom:1.2rem}
    .c360 .timeline{padding:.5rem 1.25rem}
    .c360 .timeline .avatar.xs{width:24px;height:24px;flex:0 0 24px;font-size:10.5px}
    .c360 .timeline .ev .txt a{color:var(--tx)}
