/* ============================================================
   Mesh Commander — Tabler theme layer
   Native Tabler theming is used (color mode / scheme / base / radius
   via tabler-themes.min.css + the Theme Settings customizer). This
   file only does what native theming can't:
     1. Point Tabler's sans-serif face at our self-hosted Noto Sans
        (the demo uses Inter via CDN; we must stay offline-capable).
     2. A few bridges for shell elements carried over from app.css.
   MUST load AFTER tabler.min.css / tabler-themes.min.css and the
   font @font-face rules (which live in app.css), BEFORE app.css's
   body/background rules are neutralised below.
   ============================================================ */

/* ---- Self-hosted fonts (offline-capable; the Tabler demo pulls Inter from a
   CDN, which we can't depend on). Oswald is used by the navbar brand mark. ---- */
@font-face { font-family: "Noto Sans"; src: url("/static/fonts/noto-sans-latin-400-normal.woff2") format("woff2"); font-weight: 400; font-display: swap; }
@font-face { font-family: "Noto Sans"; src: url("/static/fonts/noto-sans-latin-500-normal.woff2") format("woff2"); font-weight: 500; font-display: swap; }
@font-face { font-family: "Noto Sans"; src: url("/static/fonts/noto-sans-latin-700-normal.woff2") format("woff2"); font-weight: 700; font-display: swap; }
@font-face { font-family: "Noto Sans Mono"; src: url("/static/fonts/noto-sans-mono-latin-400-normal.woff2") format("woff2"); font-weight: 400; font-display: swap; }
@font-face { font-family: "Noto Sans Mono"; src: url("/static/fonts/noto-sans-mono-latin-700-normal.woff2") format("woff2"); font-weight: 700; font-display: swap; }
@font-face { font-family: "Oswald"; src: url("/static/fonts/oswald-latin-500-normal.woff2") format("woff2"); font-weight: 500; font-display: swap; }
@font-face { font-family: "Oswald"; src: url("/static/fonts/oswald-latin-600-normal.woff2") format("woff2"); font-weight: 600; font-display: swap; }

/* ---- Offline font: map the "sans-serif" theme-font to Noto Sans ---- */
:root {
  --tblr-font-sans-serif: "Noto Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  --tblr-font-monospace: "Noto Sans Mono", ui-monospace, SFMono-Regular, monospace;
}

/* ---- Shell bridge: the connection lamp lives in the Tabler header --- */
.linklamp { width: 9px; height: 9px; border-radius: 50%; background: var(--tblr-secondary, #888); flex: none; }
.linklamp.connected { background: var(--tblr-success); box-shadow: 0 0 8px rgba(47,179,68,.7); animation: lamp 2.4s ease-in-out infinite; }
.linklamp.connecting,
.linklamp.rebooting { background: var(--tblr-warning); box-shadow: 0 0 8px rgba(245,159,0,.7); animation: lampfast .7s ease-in-out infinite; }
.linklamp.error { background: var(--tblr-danger); }
@keyframes lamp { 50% { opacity: .55; } }
@keyframes lampfast { 50% { opacity: .3; } }

#topbar .linkinfo { min-width: 0; line-height: 1.15; }
#topbar .linkinfo .l1 { font-weight: 600; font-size: .8125rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#topbar .linkinfo .l2 { font-family: var(--tblr-font-monospace); font-size: .6875rem; color: var(--tblr-secondary-color); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#topbar .meters { display: flex; gap: 16px; align-items: center; }

/* Neutralize Tabler's scrollbar anti-jump hack. Tabler sets
   `:root { margin-left: calc(100vw - 100%); margin-right: 0 }` at ≥992px, which
   pushes the whole page (header + body) right by the scrollbar width on any page
   tall enough to scroll, while pages that don't scroll (messages, security) stay
   flush — an inconsistent left offset. We use the fluid (full-width,
   left-anchored) layout and don't need it, so every page sits flush-left.
   Loads after tabler.min.css, so equal-specificity :root wins on source order. */
@media (min-width: 992px) {
  :root { margin-left: 0; margin-right: 0; }
}

/* Hide the footer on the full-bleed map view */
body.view-map-active .app-footer { display: none; }

/* Full-bleed map: the Tabler shell (.page > .page-wrapper > .page-body >
   .container-xl > #view-map) is content-height by default, so an empty map
   collapses to 0px and renders nothing. Pin the shell to the viewport on the
   map view so #view-map's height:100% resolves to real pixels. */
body.view-map-active .page { height: 100vh; overflow: hidden; }
body.view-map-active .page-wrapper {
  display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0;
}
body.view-map-active .page-body { flex: 1 1 auto; min-height: 0; margin-block: 0; padding: 0; }
body.view-map-active .page-body > .container-xl {
  height: 100%; max-width: none; padding: 0;
}

/* Messages view: page header + footer removed to give the chat more room (the
   chat box scrolls internally, so the page itself shouldn't). Reclaim the
   freed vertical space; page padding/margins are otherwise respected. */
body.view-messages-active .app-footer { display: none; }
body.view-messages-active .msg-layout { height: calc(100dvh - 160px); }
@media (max-width: 767.98px) {
  /* Phone offset = header row 1 (~57px) + page padding + the channel
     dropdown; the old 180px also budgeted for the second (nav) header row,
     which phones never show — that surplus was the dead gap under the card. */
  body.view-messages-active .msg-layout { height: calc(100dvh - 150px); }
}

/* ---- Nav section sub-anchors -------------------------------------
   Nav items with in-page sections render as a dropdown; the parent link
   still navigates (no data-bs-toggle). Reveal the menu on hover/focus on
   desktop. On mobile the parent just navigates (menu stays hidden).
   These menus open via CSS (not Popper), so they have no [data-bs-popper]
   top/left — anchor them explicitly below the nav item so they drop down
   rather than overlapping the parent link. */
@media (min-width: 768px) {
  #navbar-nav .nav-item.dropdown { position: relative; }
  #navbar-nav .nav-item.dropdown:hover > .dropdown-menu,
  #navbar-nav .nav-item.dropdown:focus-within > .dropdown-menu {
    display: block;
    position: absolute;
    top: 100%; left: 0; right: auto;
    margin-top: 0;
  }
}
/* Below md the jump-menu never shows (no hover on touch; the parent link just
   navigates), so hide the dropdown caret — it promises a menu that can't open.
   Utility classes can't reach a ::after, hence the media query. */
@media (max-width: 767.98px) {
  #navbar-nav .nav-link.dropdown-toggle::after { display: none; }
}
/* Active nav link: highlight with the theme accent. Tabler's default active
   state is just white/bold, which barely reads against the other links — tint
   the text + icon and add a bottom accent bar (inset shadow avoids layout shift). */
#navbar-nav .nav-link.active,
#navbar-nav .nav-link.active .nav-link-icon,
#offcanvas-nav .nav-link.active,
#offcanvas-nav .nav-link.active .nav-link-icon {
  color: var(--tblr-primary);
}
#navbar-nav .nav-link.active {
  box-shadow: inset 0 -2px 0 var(--tblr-primary);
}
/* Drawer (vertical list): accent bar on the left edge instead of underneath */
#offcanvas-nav .nav-link.active {
  box-shadow: inset 2px 0 0 var(--tblr-primary);
}

/* Sticky header (two rows ~116px) must not cover a scrolled-to section */
.view .card { scroll-margin-top: 116px; }

/* Node-page identity grid: 2-up on phone. Tabler's datagrid auto-fit
   (min 15rem/item) collapses to one column below ~480px = a very long
   single-column scroll (operator request). Wide rows — Position (coords +
   map buttons), the Telemetry badge row (.dg-wide), and the public-key rows
   (inline grid-column:1/-1) — keep the full row. */
@media (max-width: 767.98px) {
  #np-id-grid { grid-template-columns: 1fr 1fr; }
  #np-id-grid > .dg-wide { grid-column: 1 / -1; }
}
