/* =====================================================================
   ALTIVEX Dashboard — stylesheet
   =====================================================================
   Dipisahkan dari `index.html` (Task UI #10) supaya markup tidak
   bercampur dengan styling, dan pemeriksaan visual review jadi lebih
   mudah. Utility class baru di bagian bawah file menggantikan inline
   `style="..."` lama (Task UI #1) sehingga theme switch / A/B layout
   dapat dilakukan tanpa menyentuh JS atau HTML.

   Konvensi:
   - `.neo-*`         : komponen utama bergaya neobrutalism.
   - `.alert-card`    : kartu pendaki keluar buffer (warna merah +
                        animasi pulse). Diset oleh `_renderHikerCards`
                        di `dashboard.js`.
   - `.standby-card`  : kartu alat belum terdaftar.
   - `.badge-*`       : varian warna untuk `.neo-badge`.
   - `.toast--*`      : warna border-left untuk `showToast`.
   - `.map-alert-banner` : banner peringatan in-app (Task UI #6).
   ===================================================================== */

:root {
    /* =================================================================
       Modern Warm palette — palette refresh v2.
       -----------------------------------------------------------------
       Token semantik baru (--bg, --surface, --ink, --line, --primary,
       --success, --danger, --info, --accent, --muted) jadi single
       source of truth. Token lama (--black, --white, --yellow, --green,
       --red, --blue, --gray) tetap ada sebagai alias supaya caller
       existing (CSS rule lama + inline `style="..."` di JS) tidak
       perlu di-refactor sekaligus.
       ================================================================= */
    --bg:      #FFF6E4;     /* cream background */
    --surface: #FFFFFF;     /* card / modal surface */
    --ink:     #1A1A1A;     /* default text color */
    --muted:   #6B5E47;     /* helper text & meta */
    --line:    #1A1A1A;     /* border lines */

    --primary: #F5B700;     /* mustard, ganti neon kuning sebelumnya */
    --success: #2EC27E;     /* forest hijau */
    --danger:  #F2545B;     /* terracotta merah */
    --info:    #3D5AFE;     /* cobalt biru */
    --accent:  #B5179E;     /* magenta untuk highlight (reserved) */

    /* Backward-compat aliases. */
    --black:  var(--line);
    --white:  var(--surface);
    --yellow: var(--primary);
    --green:  var(--success);
    --red:    var(--danger);
    --blue:   var(--info);
    --gray:   #E0E0E0;

    --shadow:    5px 5px 0px 0px var(--line);
    --shadow-sm: 3px 3px 0px 0px var(--line);
}

/* =====================================================================
   Dark mode — diaktifkan via class `body.dark-mode`.
   ---------------------------------------------------------------------
   Operator dinas malam: toggle 🌙 di header. Default first-visit
   mengikuti `prefers-color-scheme: dark`; setelah klik manual, pilihan
   tersimpan di `localStorage["ALTIVEX_THEME"]` (dashboard.js).
   Aturan kontras yang dijaga:
     - `--ink` di-flip ke cream supaya teks default tetap legible.
     - `--line` ikut cream supaya border tebal khas neobrutalism tetap
       terlihat di atas background gelap.
     - Shadow di-tinted ke `--primary` (mustard amber) — kartu jadi
       glow halus, bentuk blok tetap utuh.
     - Komponen yang punya bright fill bawaan (button + badge) tetap
       memakai teks dekat-hitam supaya kontras tidak luntur (lihat
       `.neo-btn`, `.neo-badge` di bawah).
   ===================================================================== */
body.dark-mode {
    --bg:      #1B1810;
    --surface: #2A2515;
    --ink:     #FFF6E4;
    --muted:   #C9BFA6;
    --line:    #FFF6E4;
    --primary: #FFCB30;
    --success: #4FE39A;
    --danger:  #FF7A85;
    --info:    #6E8DFF;
    --accent:  #E94CCB;
    --gray:    #3A332A;

    /* Backward-compat aliases — di-redefine eksplisit supaya CSS yang
       masih pakai `var(--white)` / `var(--black)` mendapat nilai dark
       (CSS variable resolve di lazy-time, tapi beberapa bug
       inheritance lebih aman kalau di-set ulang di scope yang sama). */
    --black:  var(--line);
    --white:  var(--surface);
    --yellow: var(--primary);
    --green:  var(--success);
    --red:    var(--danger);
    --blue:   var(--info);

    --shadow:    5px 5px 0px 0px var(--primary);
    --shadow-sm: 3px 3px 0px 0px var(--primary);
}

* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

body {
    font-family: "Manrope", system-ui, -apple-system, sans-serif;
    background-color: var(--bg);
    color: var(--ink);
    overflow-x: hidden;
    /* Body weight default lebih ringan supaya display Bricolage di
       judul terasa kontras + memberi rhythm visual.  */
    font-weight: 500;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* Display headings & block-marquee text — pakai Bricolage Grotesque.
   Variable font dengan opsz axis: optical size 12..96 menyesuaikan
   ukuran sehingga huruf besar tetap punya stress + huruf kecil tetap
   readable. */
h1, h2, h3, .logo,
.modal-title,
.toolbar__title,
.section-title,
.section-title--mt,
.alert-card__name,
.standby-card__name,
.map-alert-banner__text,
.neo-badge,
.neo-btn,
.tab-link {
    font-family: "Bricolage Grotesque", "Manrope", system-ui, sans-serif;
    font-weight: 800;
    font-stretch: 100%;
}

/* ---------- DARK MODE — explicit color overrides ----------
   Beberapa elemen di neobrutalism punya background terang bawaan
   (kartu putih, tab-link putih, modal cream, table container, toast,
   notification panel). Saat dark-mode aktif, `--surface` / `--white`
   menjadi gelap, jadi color teks-nya WAJIB ikut flip ke `--ink` cream
   supaya tidak hilang dilatar gelap. Set semuanya eksplisit di sini
   agar tidak bergantung pada inheritance yang fragile. */
body.dark-mode .neo-card,
body.dark-mode .neo-table-container,
body.dark-mode .neo-table th,
body.dark-mode .neo-table td,
body.dark-mode .tab-link,
body.dark-mode .toolbar__title,
body.dark-mode .toast,
body.dark-mode .notification-request,
body.dark-mode .modal-content,
body.dark-mode .modal-detail-stats,
body.dark-mode .stats-heading,
body.dark-mode .stats-list,
body.dark-mode .stats-info,
body.dark-mode .stats-item,
body.dark-mode .alert-card__name,
body.dark-mode .standby-card__name,
body.dark-mode .section-title,
body.dark-mode .section-title--mt,
body.dark-mode .form-label,
body.dark-mode .modal-title,
body.dark-mode .confirm-msg,
body.dark-mode .empty-message,
body.dark-mode .notif-prompt-text,
body.dark-mode .map-alert-banner__cta {
    color: var(--ink);
}

/* Tabel di dark-mode: header pakai surface darker + teks cream agar
   beda kontras vs cell biasa. */
body.dark-mode .neo-table th {
    background: var(--gray);
}

/* Badge `.badge-white` di dark-mode harus tetap kontras vs surface
   gelap — paksa background ke --bg (lebih gelap dari surface) dan
   teksnya cream. Begitu juga badge-status-off di tabel. */
body.dark-mode .badge-white {
    background: var(--surface);
    color: var(--ink);
    border-color: var(--line);
}
body.dark-mode .badge-status-off {
    background: var(--gray);
    color: var(--ink);
}

/* ---------- NEOBRUTALISM PRIMITIVES ---------- */
.neo-card {
    background: var(--white);
    border: 4px solid var(--black);
    box-shadow: var(--shadow);
    padding: 20px;
    margin-bottom: 20px;
}

.neo-btn {
    background: var(--yellow);
    /* Tombol berwarna terang harus tetap pakai teks dekat-hitam baik
       di light maupun dark mode supaya kontras > 7:1 (WCAG AAA). */
    color: #1A1A1A;
    border: 3px solid var(--black);
    box-shadow: var(--shadow-sm);
    padding: 10px 20px;
    font-weight: 700;
    text-transform: uppercase;
    cursor: pointer;
    transition: all 0.1s;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-family: inherit;
}

.neo-btn:active {
    box-shadow: none;
    transform: translate(3px, 3px);
}

.neo-btn-sm {
    padding: 5px 10px;
    font-size: 0.8rem;
    border-width: 2px;
}

.neo-btn-red   { background: var(--red);   color: white; }
.neo-btn-green { background: var(--green); color: #1A1A1A; }
.neo-btn-blue  { background: var(--blue);  color: white; }

.neo-input {
    width: 100%;
    padding: 12px;
    background: var(--surface);
    color: var(--ink);
    border: 3px solid var(--black);
    font-family: inherit;
    font-weight: 700;
    box-shadow: var(--shadow-sm);
    outline: none;
}

.neo-badge {
    /* Background varian-nya (badge-id, badge-status-on, dll.) ber-fill
       terang — paksa teks dekat-hitam supaya legible di light maupun
       dark mode. Untuk varian gelap (.badge-keluar, .badge-white) kita
       override eksplisit di rule masing-masing. */
    color: #1A1A1A;
    border: 2px solid var(--black);
    padding: 4px 10px;
    font-weight: 700;
    font-size: 0.75rem;
    text-transform: uppercase;
    display: inline-block;
}

/* Varian warna .neo-badge — menggantikan inline `style="background: ..."`. */
.badge-yellow      { background: var(--yellow); }
.badge-green       { background: var(--green); }
.badge-gray        { background: var(--gray); }
.badge-white       { background: var(--surface); color: var(--ink); }
.badge-status-on   { background: var(--green); }
.badge-status-off  { background: var(--gray); color: var(--ink); }
.badge-id          { background: var(--yellow); }
.badge-keluar      { background: var(--red); color: white; margin-bottom: 10px; }

/* ---------- HEADER ---------- */
header {
    background: var(--white);
    border-bottom: 4px solid var(--black);
    padding: 15px 30px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
    position: sticky;
    top: 0;
    z-index: 1000;
}

.logo--legacy-disabled {
    /* Class lama sudah di-superset di section ICON ALIGNMENT.
       Kept untuk reference. */
    display: none;
}

/* Group status badges di header. */
.header-status-group {
    display: flex;
    gap: 15px;
    align-items: center;
}

/* ---------- THEME TOGGLE ---------- */
/* Tombol 🌙/☀ di header. Compact, square-ish, tetap berbentuk
   neobrutalism (border 3px + shadow blok). Klik → flip class
   `dark-mode` di body, persisted ke localStorage oleh dashboard.js. */
.theme-toggle {
    width: 40px;
    height: 40px;
    background: var(--surface);
    color: var(--ink);
    border: 3px solid var(--line);
    box-shadow: var(--shadow-sm);
    cursor: pointer;
    font-family: inherit;
    font-size: 1rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: transform 0.1s;
    padding: 0;
}

.theme-toggle:active {
    box-shadow: none;
    transform: translate(3px, 3px);
}

/* Mobile: tombol toggle ikut jadi prioritas terakhir saat header
   wrap, tapi tetap reachable. */
@media (max-width: 600px) {
    .theme-toggle { width: 36px; height: 36px; }
}

/* ---------- TABS ---------- */
.tabs-nav {
    display: flex;
    gap: 20px;
    padding: 20px 30px 0 30px;
}

.tab-link {
    background: var(--white);
    border: 3px solid var(--black);
    border-bottom: none;
    padding: 10px 25px;
    font-weight: 700;
    cursor: pointer;
    box-shadow: 4px 0px 0px 0px var(--black);
    transform: translateY(3px);
    transition: all 0.2s;
}

.tab-link.active {
    background: var(--blue);
    color: var(--white);
    transform: translateY(0);
    padding-bottom: 13px;
}

/* ---------- MAIN LAYOUT ---------- */
.tab-content {
    display: none;
    padding: 30px;
}

.tab-content.active {
    display: block;
}

.dashboard-grid {
    display: grid;
    grid-template-columns: 1fr 350px;
    gap: 30px;
    height: calc(100vh - 200px);
}

#map {
    width: 100%;
    height: 100%;
    border: 4px solid var(--black);
    box-shadow: var(--shadow);
}

.sidebar {
    overflow-y: auto;
    padding-right: 10px;
}

.section-title {
    margin-bottom: 15px;
    text-transform: uppercase;
    font-weight: 900;
}

.section-title--mt {
    margin: 25px 0 15px 0;
    text-transform: uppercase;
    font-weight: 900;
}

/* Toolbar di tab "Kelola Pendaki". */
.toolbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.toolbar__title {
    text-transform: uppercase;
    font-weight: 900;
}

.toolbar__actions {
    display: flex;
    gap: 10px;
}

/* Filter bar (search + radio status). */
.filter-bar {
    display: flex;
    gap: 15px;
}

.filter-bar__radios {
    display: flex;
    gap: 10px;
    align-items: center;
    font-weight: 700;
}

/* ---------- IN-APP ALERT BANNER (Task UI #6) ---------- */
/* Banner sticky di tab "Peta Live" yang muncul saat ≥1 pendaki keluar
   buffer geofence. Klik banner → scroll ke kartu alert pertama di
   sidebar. Hidden via attribute `hidden` saat tidak ada pelanggaran. */
.map-alert-banner {
    background: var(--red);
    color: var(--white);
    border: 4px solid var(--black);
    box-shadow: var(--shadow);
    padding: 14px 22px;
    margin-bottom: 20px;
    display: flex;
    align-items: center;
    gap: 14px;
    font-weight: 800;
    cursor: pointer;
    animation: pulse 2s infinite;
}

.map-alert-banner[hidden] {
    display: none;
}

.map-alert-banner__icon {
    font-size: 1.4rem;
}

.map-alert-banner__text {
    flex: 1;
    text-transform: uppercase;
    letter-spacing: 0.3px;
}

.map-alert-banner__cta {
    background: var(--white);
    color: var(--black);
    border: 3px solid var(--black);
    padding: 6px 14px;
    font-weight: 800;
    text-transform: uppercase;
    cursor: pointer;
    font-family: inherit;
}

.map-alert-banner__cta:active {
    transform: translate(2px, 2px);
}

/* ---------- ALERT / STANDBY CARDS (di sidebar) ---------- */
.alert-card {
    border-left: 10px solid var(--red);
    padding: 15px;
    animation: pulse 2s infinite;
}

.alert-card__name {
    font-weight: 900;
    font-size: 1.1rem;
}

.alert-card__meta {
    font-size: 0.8rem;
    font-weight: 700;
    margin-bottom: 10px;
}

.alert-card__actions {
    display: flex;
    gap: 8px;
}

.standby-card {
    padding: 15px;
    /* Sedikit lebih lembut dari .neo-card supaya kartu standby tidak
       "berteriak" sekuat alert card. Pakai variabel agar dark-mode
       otomatis ikut shift ke shade gelap. */
    background: var(--bg);
}

.standby-card__name {
    font-weight: 800;
}

.standby-card__meta {
    font-size: 0.7rem;
    color: var(--muted);
    margin-bottom: 10px;
}

.all-safe-card {
    background: var(--green);
    text-align: center;
    font-weight: 900;
}

.empty-message {
    font-weight: 700;
    text-align: center;
}

/* ---------- TABLES ---------- */
.neo-table-container {
    overflow-x: auto;
    border: 4px solid var(--black);
    box-shadow: var(--shadow);
    background: var(--white);
}

.neo-table {
    width: 100%;
    border-collapse: collapse;
    text-align: left;
}

.neo-table th {
    background: var(--black);
    color: var(--white);
    padding: 15px;
    text-transform: uppercase;
    font-weight: 900;
}

.neo-table td {
    padding: 15px;
    border-bottom: 3px solid var(--black);
    font-weight: 700;
}

.history-actions {
    display: flex;
    gap: 5px;
}

/* ---------- MODALS ---------- */
.modal-overlay {
    position: fixed;
    top: 0; left: 0; width: 100%; height: 100%;
    background: rgba(0,0,0,0.8);
    display: none;
    align-items: center;
    justify-content: center;
    z-index: 2000;
}

.modal-content {
    width: 100%;
    max-width: 500px;
    background: var(--bg);
    border: 4px solid var(--black);
    box-shadow: 10px 10px 0px 0px var(--black);
    padding: 40px;
    position: relative;
}

.modal-content--lg { max-width: 800px; }
.modal-content--sm { max-width: 400px; text-align: center; }

.modal-title {
    text-transform: uppercase;
    font-weight: 900;
    margin-bottom: 25px;
}

.modal-title--detail  { margin-bottom: 20px; }
.modal-title--confirm { margin-bottom: 15px; }

.modal-detail-grid {
    grid-template-columns: 1fr 250px;
    height: 400px;
    gap: 20px;
}

.modal-detail-mini {
    border: 3px solid var(--black);
    height: 100%;
}

.modal-detail-stats {
    background: var(--white);
    border: 3px solid var(--black);
    padding: 15px;
}

.stats-heading {
    font-size: 0.9rem;
    margin-bottom: 15px;
}

.stats-list {
    font-weight: 700;
    font-size: 0.85rem;
}

.stats-item { margin-bottom: 10px; }

.stats-time {
    font-size: 0.75rem;
    color: var(--muted);
}

.stats-divider {
    margin: 15px 0;
    border: 1px dashed var(--black);
}

.stats-info { font-size: 0.8rem; }

.modal-detail-footer {
    margin-top: 25px;
    text-align: right;
}

.confirm-msg {
    font-weight: 700;
    margin-bottom: 25px;
}

.form-group { margin-bottom: 15px; }
.form-group--last { margin-bottom: 25px; }

.form-label {
    font-weight: 900;
    display: block;
    margin-bottom: 5px;
}

.modal-form-actions {
    display: flex;
    gap: 15px;
}

.btn-flex { flex: 1; }

/* `<select>` di neobrutalism: native control yang dirender browser
   tidak inherit warna dari `body.dark-mode` — `option` gambar lewat OS,
   bukan CSS. Kita tetap paksa background select-nya cream/dark sesuai
   token, dan styling `option` lewat selektor `select option` (Chrome /
   Firefox honor; Safari iOS terbatas tapi setidaknya kontras tidak
   sepenuhnya hilang). */
.input-select-white,
select.neo-input {
    background: var(--surface);
    color: var(--ink);
    appearance: none;
    -webkit-appearance: none;
    background-image:
        linear-gradient(45deg, transparent 50%, var(--ink) 50%),
        linear-gradient(135deg, var(--ink) 50%, transparent 50%);
    background-position:
        calc(100% - 18px) 50%,
        calc(100% - 12px) 50%;
    background-size: 6px 6px, 6px 6px;
    background-repeat: no-repeat;
    padding-right: 32px;
}

select.neo-input option,
.input-select-white option {
    background: var(--surface);
    color: var(--ink);
    font-weight: 700;
}

/* Dark mode: paksa option-nya gelap supaya tidak ke-flip oleh OS
   default. */
body.dark-mode select.neo-input,
body.dark-mode .input-select-white {
    background-color: var(--surface);
    color: var(--ink);
    /* color-scheme memberi sinyal ke browser supaya native dropdown
       (Chromium) ikut tema gelap. Tanpa ini, dropdown tetap putih. */
    color-scheme: dark;
}

body.dark-mode select.neo-input option,
body.dark-mode .input-select-white option {
    background-color: var(--surface);
    color: var(--ink);
}

/* ---------- TOASTS ---------- */
#toast-container {
    position: fixed;
    top: 30px;
    right: 30px;
    z-index: 3000;
    display: flex;
    flex-direction: column;
    gap: 15px;
}

.toast {
    background: var(--white);
    border: 3px solid var(--black);
    box-shadow: var(--shadow-sm);
    padding: 15px 25px;
    font-weight: 700;
    display: flex;
    align-items: center;
    gap: 10px;
    animation: slideIn 0.3s forwards;
    border-left: 10px solid var(--yellow);
}

.toast--success { border-left-color: var(--green); }
.toast--error   { border-left-color: var(--red); }
.toast--info    { border-left-color: var(--yellow); }

@keyframes slideIn {
    from { transform: translateX(100%); }
    to   { transform: translateX(0); }
}

/* ---------- NOTIFICATION REQUEST PANEL ---------- */
/* Panel `#notif-request` di-display:none secara default; di-show via
   JS (`window.load`) saat permission masih "default" dan operator
   belum men-dismiss. Layout default = flex saat di-show. */
.notification-request {
    display: none;
    position: fixed;
    bottom: 30px;
    left: 30px;
    background: var(--white);
    border: 3px solid var(--black);
    box-shadow: var(--shadow);
    padding: 15px 20px;
    flex-direction: column;
    gap: 12px;
    max-width: 320px;
    z-index: 2500;
}

.notif-prompt-text {
    font-weight: 700;
    font-size: 0.9rem;
}

.notif-prompt-actions {
    display: flex;
    gap: 10px;
}

/* ---------- STATUS DOTS ---------- */
.dot {
    width: 12px;
    height: 12px;
    border: 2px solid var(--black);
    border-radius: 50%;
    display: inline-block;
}

.dot-green { background: var(--green); }
.dot-red   { background: var(--red); }

/* ---------- ANIMATIONS ---------- */
@keyframes pulse {
    0%   { transform: scale(1);    box-shadow: var(--shadow); }
    50%  { transform: scale(1.02); box-shadow: 8px 8px 0px 0px var(--red); }
    100% { transform: scale(1);    box-shadow: var(--shadow); }
}

/* ---------- ICON ALIGNMENT ---------- */
/* SVG icon dari icons.js. Default: align baseline dengan text di
   sekelilingnya, ikut color via currentColor (sudah di-set di SVG).
   `flex-shrink: 0` supaya tidak ke-squish saat container sempit. */
.icon {
    display: inline-block;
    vertical-align: -0.15em;
    flex-shrink: 0;
    color: currentColor;
}

/* Logo header — icon mountain + wordmark "ALTIVEX". */
.logo {
    font-weight: 900;
    font-size: 1.6rem;
    text-transform: uppercase;
    letter-spacing: -1px;
    display: flex;
    align-items: center;
    gap: 12px;
}
.logo__icon {
    display: inline-flex;
    align-items: center;
    color: var(--ink);
}
.logo__icon .icon {
    /* Logo mountain di-render dengan stroke lebih tebal manual via
       CSS supaya menonjol di brand position. */
    stroke-width: 3;
}

/* Tombol login/logout/theme — icon di-vertical-center. */
.theme-toggle .icon,
.neo-btn .icon,
.tab-link__icon .icon,
.section-title .icon,
.section-title--mt .icon,
.standby-card__name .icon,
.alert-card__name .icon,
.all-safe-card .icon,
.toast .icon,
.skeleton-card .icon,
.notif-prompt-text .icon,
.map-alert-banner__icon .icon,
.login-brand__icon .icon,
.history-actions .neo-btn .icon {
    vertical-align: middle;
}

/* Section title (Alert Sidebar, Perangkat) — icon ber-margin sedikit. */
.section-title,
.section-title--mt {
    display: flex;
    align-items: center;
    gap: 10px;
}
.section-title .icon { color: var(--red); }
.section-title--mt .icon { color: var(--blue); }

/* Tab link icon — sedikit lebih kecil + margin kanan. */
.tab-link__icon {
    display: inline-flex;
    align-items: center;
    margin-right: 6px;
}

/* Banner icon — putih kontras vs merah, dengan stroke tebal. */
.map-alert-banner__icon .icon {
    color: white;
    stroke-width: 3;
}

/* Alert card name icon (warning) — putih di tengah card merah. */
.alert-card__name .icon {
    color: var(--red);
    margin-right: 6px;
}

/* Standby card icon (device) — pakai biru info untuk membedakan dari
   alert. */
.standby-card__name .icon {
    color: var(--blue);
    margin-right: 6px;
}

/* All-safe card icon — hijau. */
.all-safe-card .icon {
    color: var(--ink);
    margin-right: 8px;
    stroke-width: 3;
}

/* Toast icon — sesuai varian. */
.toast--success .icon { color: var(--green); }
.toast--error   .icon { color: var(--red); }
.toast--info    .icon { color: var(--blue); }

/* Skeleton card icon — animated rotating refresh. */
.skeleton-card .icon {
    color: var(--muted);
    animation: skeleton-spin 2s linear infinite;
}
@keyframes skeleton-spin {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}

/* Login brand icon — ukuran besar, color primary. */
.login-brand__icon {
    color: var(--primary);
    display: inline-flex;
    align-items: center;
}
.login-brand__icon .icon {
    width: 32px;
    height: 32px;
    stroke-width: 3;
}

/* Logout button icon — diberi rotasi 180deg supaya arah panah masuk. */
.logout-btn .icon {
    color: var(--ink);
}

/* History action buttons — icon agak lebih kecil. */
.history-actions .neo-btn .icon {
    margin-right: 2px;
}

/* ---------- WAYPOINT MARKER (Leaflet divIcon) ---------- */
.waypoint-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    background: var(--surface);
    border: 2.5px solid var(--line);
    border-radius: 50%;
    box-shadow: 2px 2px 0 0 var(--line);
    color: var(--ink);
}
.waypoint-icon .icon { stroke-width: 2.5; }

/* Path marker (start/end pendaki polyline) */
.path-marker {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    background: var(--surface);
    border: 2.5px solid var(--line);
    border-radius: 50%;
    box-shadow: 2px 2px 0 0 var(--line);
}
.path-marker--start .icon { color: var(--green); }
.path-marker--end   .icon { color: var(--red); }

/* Popup di waypoint — typography pakai font dashboard. */
.waypoint-popup {
    font-family: "Manrope", system-ui, sans-serif;
}
.waypoint-popup__title {
    font-family: "Bricolage Grotesque", sans-serif;
    font-size: 14px;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.waypoint-popup__route {
    color: white;
    padding: 2px 8px;
    font-size: 11px;
    font-weight: 700;
    border: 2px solid var(--line);
    display: inline-block;
    margin-top: 4px;
}

/* ---------- ICON ALIGNMENT (END) ---------- */

/* ---------- LOGIN PAGE (UI #4) ---------- */
/* Login modal di-show oleh dashboard.js saat token belum ada di
   localStorage atau request balik 401. Pakai modal-overlay yang sama
   tapi dengan class `modal-overlay--auth` untuk full-bleed background
   (operator tidak boleh klik dashboard sebelum login). */
.modal-overlay--auth {
    background: var(--bg);
    /* Selalu tampil sampai JS toggle off — pakai display: flex, override
       default `display: none` dari .modal-overlay. */
    display: flex;
}

.modal-content--auth {
    max-width: 420px;
    background: var(--surface);
    text-align: center;
}

.login-brand {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    font-weight: 900;
    font-size: 1.4rem;
    text-transform: uppercase;
    letter-spacing: -0.5px;
    margin-bottom: 18px;
    color: var(--ink);
}

.login-brand__icon {
    font-size: 1.6rem;
}

.login-heading {
    margin-bottom: 8px;
    font-size: 1.6rem;
}

.login-subtitle {
    font-weight: 500;
    color: var(--muted);
    margin-bottom: 24px;
    font-size: 0.9rem;
}

.login-form .form-group {
    text-align: left;
}

.login-error {
    background: var(--red);
    color: white;
    border: 3px solid var(--line);
    padding: 10px 14px;
    margin-bottom: 14px;
    font-weight: 800;
    font-size: 0.85rem;
}

.login-error[hidden] {
    display: none;
}

.logout-btn {
    font-size: 1.1rem;
}

.logout-btn[hidden] {
    display: none;
}

/* ---------- BATTERY PILL ---------- */
/* Indikator baterai yang muncul di alert-card / standby-card.
   Pakai class `.battery-pill--<level>` untuk warna sesuai threshold.
   `.battery-pill__label` adalah persen ("85%" / "—"). */
.battery-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border: 2px solid var(--line);
    background: var(--surface);
    font-family: "Bricolage Grotesque", sans-serif;
    font-weight: 800;
    font-size: 0.78rem;
    line-height: 1;
    box-shadow: 2px 2px 0 0 var(--line);
}

.battery-pill__label {
    letter-spacing: 0.3px;
}

.battery-pill--full,
.battery-pill--ok    { color: var(--green); }
.battery-pill--mid   { color: var(--primary); }
.battery-pill--low   { color: var(--red); }
.battery-pill--crit,
.battery-pill--off   {
    color: var(--red);
    animation: battery-pulse 1.4s ease-in-out infinite;
}
.battery-pill--unknown { color: var(--muted); }

@keyframes battery-pulse {
    0%, 100% { transform: scale(1);    box-shadow: 2px 2px 0 0 var(--line); }
    50%      { transform: scale(1.05); box-shadow: 4px 4px 0 0 var(--red); }
}

/* Row container untuk menempatkan badge "KELUAR KORIDOR" + battery
   pill di alert card. Standby card hanya berisi battery pill. */
.alert-card__row,
.standby-card__row {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 8px 0 10px 0;
    flex-wrap: wrap;
}

/* ---------- LOADING SKELETON ---------- */
/* Skeleton placeholder muncul saat sidebar/banner belum sempat
   re-populate setelah refresh — terutama di mobile yang koneksinya
   lambat. Operator lihat "loading..." daripada UI kosong + curiga
   data hilang. Skeleton dihapus oleh _renderHikerCards begitu
   render pertama jalan. */
.skeleton-card {
    background: var(--surface);
    border: 3px dashed var(--line);
    padding: 18px;
    margin-bottom: 12px;
    color: var(--muted);
    font-weight: 700;
    font-size: 0.85rem;
    display: flex;
    align-items: center;
    gap: 10px;
    animation: skeleton-pulse 1.4s ease-in-out infinite;
}

.skeleton-card::before {
    content: "⏳";
    font-size: 1.1rem;
}

@keyframes skeleton-pulse {
    0%, 100% { opacity: 0.55; }
    50%      { opacity: 1; }
}

/* ---------- RESPONSIVE ---------- */
@media (max-width: 1000px) {
    .dashboard-grid { grid-template-columns: 1fr; height: auto; }
    #map { height: 400px; }
}

@media (max-width: 600px) {
    header {
        flex-wrap: wrap;
        gap: 10px;
        padding: 12px 15px;
    }
    .logo { font-size: 1.2rem; gap: 8px; }
    .logo__icon .icon { width: 22px; height: 22px; }
    .tabs-nav { gap: 5px; padding: 10px 15px 0; }
    .tab-link { padding: 8px 12px; font-size: 0.8rem; }
    .tab-content { padding: 15px; }
    #map { height: 55vh; min-height: 300px; }
    .dashboard-grid { grid-template-columns: 1fr; }
    .sidebar { height: auto; max-height: 400px; }

    .hide-mobile { display: none; }

    /* ----- Toolbar Kelola Pendaki: stack vertikal di mobile ----- */
    .toolbar {
        flex-direction: column;
        align-items: stretch;
        gap: 12px;
    }
    .toolbar__title {
        font-size: 1rem;
        line-height: 1.2;
    }
    .toolbar__actions {
        flex-direction: row;
        gap: 8px;
    }
    .toolbar__actions .neo-btn {
        flex: 1;
        justify-content: center;
        white-space: nowrap;
        font-size: 0.75rem;
        padding: 10px 8px;
    }

    /* ----- Filter bar: search + radio group rapi ----- */
    .filter-bar {
        flex-direction: column;
        gap: 10px;
    }
    .filter-bar__radios {
        flex-wrap: wrap;
        gap: 12px;
        font-size: 0.85rem;
    }

    /* ----- Card-ify riwayat pendaki di mobile -----
       Native tabel jadi unreadable saat overflow horizontal di mobile.
       Solusi: ubah tiap <tr> jadi block "kartu" dengan label inline
       (data-label) di tiap cell. Header tabel disembunyikan; setiap
       cell pakai pseudo `::before` untuk render label dari atribut
       `data-label`. Markup HTML di renderHistoryTable() WAJIB tambah
       `data-label="..."` di setiap td. */
    .neo-table-container {
        border: none;
        box-shadow: none;
        background: transparent;
        overflow-x: visible;
    }
    .neo-table thead {
        display: none;
    }
    .neo-table,
    .neo-table tbody,
    .neo-table tr,
    .neo-table td {
        display: block;
        width: 100%;
    }
    .neo-table tr {
        background: var(--surface);
        border: 4px solid var(--line);
        box-shadow: var(--shadow);
        margin-bottom: 16px;
        padding: 14px 16px;
    }
    .neo-table td {
        border: none;
        padding: 6px 0;
        display: flex;
        justify-content: space-between;
        align-items: center;
        gap: 12px;
        font-size: 0.85rem;
    }
    .neo-table td::before {
        content: attr(data-label);
        font-weight: 900;
        text-transform: uppercase;
        font-size: 0.7rem;
        letter-spacing: 0.5px;
        color: var(--muted);
        flex-shrink: 0;
    }
    /* Cell aksi punya konten kompleks (tombol-tombol), di-render
       full-width, label di atas row buttons. */
    .neo-table td.cell-actions {
        flex-direction: column;
        align-items: stretch;
        gap: 8px;
        padding-top: 10px;
        border-top: 2px dashed var(--line);
        margin-top: 6px;
    }
    .neo-table td.cell-actions::before {
        text-align: left;
    }
    .neo-table td .history-actions {
        flex-wrap: wrap;
        gap: 6px;
    }
    .neo-table td .history-actions .neo-btn {
        flex: 1;
        min-width: 80px;
        justify-content: center;
    }

    .map-alert-banner {
        flex-wrap: wrap;
        padding: 12px 16px;
    }
    .map-alert-banner__cta {
        margin-left: 0;
        width: 100%;
    }

    .notification-request {
        left: 16px;
        right: 16px;
        bottom: 16px;
        max-width: none;
    }

    /* Modal di mobile: full-bleed dengan margin tipis. */
    .modal-content {
        padding: 24px 20px;
        max-width: calc(100vw - 24px);
        margin: 12px;
    }
    .modal-form-actions {
        flex-direction: column;
    }
}
