/*!
 * SIPER SAFE — siper.css
 *
 * Lapisan gaya di atas Velzon. Berisi hal-hal yang tidak disediakan template:
 * workspace bertab, widget, tabel data server-side, bilah aksi form,
 * empty state, dan toast.
 *
 * Warna sengaja mengambil variabel Velzon (--vz-*) supaya mode terang dan
 * gelap ikut menyesuaikan tanpa aturan tambahan.
 */

/* ==================================================================
 * 1. Token
 * ================================================================ */

/*
 * Cadangan variabel font.
 *
 * Halaman mandiri — masuk, galat 400/403/404, verifikasi QR — sengaja TIDAK
 * memuat `app.min.css`: 500 KB hanya untuk satu kartu teks, dan halaman
 * verifikasi dibuka dari HP di lapangan. Tetapi rantai font Velzon berakhir di
 * `app.min.css`:
 *
 *     bootstrap.min.css  body { font-family: var(--vz-body-font-family) }
 *                        --vz-body-font-family : var(--vz-font-sans-serif)
 *                        --vz-font-sans-serif  : var(--vz-font-family-secondary)
 *     app.min.css        [data-theme=default]:root { --vz-font-family-secondary: "Poppins" }
 *
 * Tanpa mata rantai terakhir seluruh halaman itu jatuh ke serif bawaan
 * peramban — terlihat seperti halaman yang salah, bukan halaman kami.
 *
 * Aman untuk aplikasi: spesifisitas `:root` (0,1,0) kalah dari
 * `[data-theme=default]:root` (0,2,0) milik Velzon, jadi di dalam aplikasi
 * nilai ini tidak pernah dipakai.
 */
:root {
    --vz-font-family-primary: "hkgrotesk", "Poppins", sans-serif;
    --vz-font-family-secondary: "Poppins", sans-serif;
}

:root {
    --siper-topbar-h: 70px;
    --siper-tabbar-h: 42px;
    --siper-footer-h: 34px;

    --siper-radius: 6px;
    --siper-gap: 1rem;

    --siper-surface: var(--vz-secondary-bg, #fff);
    --siper-border: var(--vz-border-color, #e9ebec);
    --siper-muted: var(--vz-secondary-color, #878a99);

    --siper-tab-bg: var(--vz-light, #f3f6f9);
    --siper-tab-active-bg: var(--vz-secondary-bg, #fff);

    --siper-head-bg: var(--vz-light, #f3f6f9);
    --siper-head-fg: var(--vz-heading-color, #495057);
}

/* ==================================================================
 * 2. Kerangka: topbar → tabbar → workspace → footer
 * ================================================================ */

html, body.siper-body { height: 100%; }

body.siper-body {
    overflow: hidden;              /* hanya pane yang boleh menggulir */
    background-color: var(--vz-body-bg);
}

body.siper-body #layout-wrapper { height: 100vh; }

body.siper-body .main-content {
    height: 100vh;
    min-width: 0;
    padding-top: var(--siper-topbar-h);
    display: flex;
    flex-direction: column;
}

/* Tinggi topbar dipatok eksplisit supaya padding-top .main-content persis
   sepadan — kalau meleset 1px, isi halaman tertutup bayangan topbar. */
.siper-topbar { height: var(--siper-topbar-h); }
.siper-topbar .navbar-header { height: 100%; }

/* ------------------------------------------------------------------
 * Merek — logo & lambang
 *
 * Turunan logo dibangun `php spark siper:brand-assets` ke
 * assets/images/siper/. Dua bentuk, dan pemilihannya soal KONTRAS,
 * bukan selera:
 *
 *   logo penuh    → latar terang saja (topbar putih, kartu masuk, kertas).
 *                   Huruf "i"/"r"-nya biru tua #034A9F; di atas sidebar
 *                   #405189 rasionya 1,12:1 — hilang sama sekali.
 *   lambang+nama  → latar gelap (sidebar, tema gelap). Petirnya kontras
 *                   4,5:1 lewat sisi kuning, namanya diketik bukan digambar.
 * ---------------------------------------------------------------- */

.siper-brand {
    display: inline-flex;
    align-items: center;
    flex: 0 0 auto;
    text-decoration: none;
    margin-right: 1rem;
}

/* Pemisah tipis antara merek dan kotak cari. Tanpa jarak ini keduanya
   terbaca sebagai satu kesatuan, dan logo berwarna langsung menempel di
   tepi kiri input — ramai. Garisnya hanya muncul begitu kotak cari
   memang tampil (Bootstrap md ke atas). */
@media (min-width: 768px) {
    .siper-brand {
        margin-right: 1.15rem;
        padding-right: 1.15rem;
        border-right: 1px solid var(--vz-border-color, #e9ebec);
    }
}

/* Tingginya datang dari atribut `height` yang ditulis helper `brand_logo()`,
   BUKAN dari sini: satu logo dipakai pada tujuh ukuran berbeda (topbar 40,
   halaman masuk 54, verifikasi 64, …) dan mengunci tinggi di CSS membuat
   argumen helper-nya diam-diam tidak berpengaruh. Yang dipatok di sini hanya
   yang tidak boleh berubah: lebar mengikuti tinggi, dan Bootstrap tidak boleh
   menggepengkannya lewat `img { max-width: 100% }`. */
.siper-brand__logo {
    display: block;
    width: auto;
    max-width: none;
}

/* Layar sempit: ruangnya dibagi dengan tombol laci dan menu pengguna.
   Di sini tinggi memang ditimpa — ini keputusan tata letak, bukan pemanggil. */
@media (max-width: 575.98px) {
    .siper-brand { margin-right: .5rem; }
    .siper-topbar .siper-brand__logo { height: 32px; }
}

/* Tema gelap: topbar jadi #292e32 dan huruf biru logo ikut tenggelam.
   Pelat putih tipis mengembalikan konteks terangnya tanpa mengubah warna
   mereknya — cara baku menempatkan logo berwarna di latar gelap.

   Pelatnya dipasang pada PEMBUNGKUS, bukan pada <img>: Bootstrap menyetel
   `box-sizing: border-box`, sehingga padding pada gambar ber-`height` justru
   MENGECILKAN gambarnya, bukan memberinya ruang bebas. */
[data-bs-theme="dark"] .siper-brand {
    background: #fff;
    border-radius: var(--siper-radius);
    padding: 4px 10px;
    border-right: 0;
}

@media (min-width: 768px) {
    [data-bs-theme="dark"] .siper-brand { padding-right: 10px; }
}

/* Pelat berdiri sendiri — dipakai halaman masuk, yang panel kirinya gelap. */
.siper-brand-plate {
    display: inline-flex;
    align-items: center;
    background: #fff;
    border-radius: calc(var(--siper-radius) + 2px);
    padding: 10px 16px;
    box-shadow: 0 2px 10px rgba(15, 34, 58, .18);
}

/* ------------------------------------------------------------------
 * Latar halaman autentikasi
 *
 * Fotonya pembangkit milik unit sendiri, bukan foto kantor generik bawaan
 * Velzon. Satu berkas dipakai di DUA tempat dengan perlakuan berbeda:
 *
 *   .auth-bg-cover  latar halaman — digelapkan kuat; tugasnya memberi
 *                   konteks, bukan menarik perhatian dari kartu masuk.
 *   .auth-one-bg    panel kiri kartu — ditumpuk gradien merek, jadi
 *                   terbaca sebagai bidang berwarna yang "punya isi".
 *
 * Keduanya memakai berkas yang SAMA sehingga hanya satu unduhan — halaman
 * masuk adalah halaman pertama yang dimuat, sering dari jaringan unit yang
 * lambat. Velzon menunjuk `../images/auth-one-bg.jpg`; berkas itu ikut
 * ditimpa `siper:sync-assets`, karena itu milik kita ditaruh di
 * `images/siper/` dan ditunjuk dari sini.
 * ---------------------------------------------------------------- */

.auth-page-wrapper.auth-bg-cover {
    background: #0d1b2e url("../images/siper/auth-bg.jpg") center / cover no-repeat;
}

/* Lapisan gelap agar kartu putih menonjol dan teks kaki tetap terbaca.
   Velzon memakai `.bg-overlay` untuk pola titik-titik; di sini ia menjadi
   peredup — polanya tidak lagi terlihat di atas foto dan hanya menambah
   satu unduhan.

   Gradien, bukan warna rata: bagian bawah foto berisi bangunan biru terang,
   dan tepat di situlah baris hak cipta berada. Dengan peredup rata 0,68 teks
   putih-50% di atasnya tidak terbaca — paling parah di layar ponsel, yang
   memotong fotonya persis pada bagian paling terang itu. */
.auth-page-wrapper.auth-bg-cover > .bg-overlay {
    background-image: linear-gradient(
        to bottom,
        rgba(13, 27, 46, .58) 0%,
        rgba(13, 27, 46, .62) 45%,
        rgba(13, 27, 46, .88) 100%
    );
    background-color: transparent;
    opacity: 1;
}

/* Baris hak cipta duduk di atas foto, bukan di atas bidang polos — putih 50%
   terlalu tipis untuk itu. Dinaikkan khusus di halaman ini. */
.auth-bg-cover .footer { color: rgba(255, 255, 255, .78); }

/* Panel kiri kartu: foto yang sama, ditumpuk gradien merek Velzon.
   Opasitasnya diturunkan dari .9 ke .82 supaya siluet pembangkitnya masih
   terbaca tanpa mengurangi kontras teks putih di atasnya. */
.auth-one-bg {
    background-image: url("../images/siper/auth-bg.jpg");
}

.auth-one-bg .bg-overlay { opacity: .82; }

/* ------------------------------------------------------------------
 * Merek aplikasi — logo SIPER SAFE saja (v0.57.0)
 *
 * Pengganti kunci merek ganda di topbar, halaman masuk, verifikasi QR,
 * pratinjau email, dan halaman galat (`brand_siper()`): permintaan pemilik
 * project 2 Okt 2026 — "Logo PLN Nusantara Power dihapus saja. Cukup logo
 * Siper Safe". Latar gelap memakai `.siper-brand-plate` seperti sebelumnya.
 * ---------------------------------------------------------------- */

.siper-merek {
    display: inline-flex;
    align-items: center;
    text-decoration: none;
}

/* Layar sempit: logonya dikecilkan supaya muat pada kartu selebar layar —
   keputusan TATA LETAK, bukan pemanggil (lihat .siper-brand__logo). Topbar
   lebih kecil lagi: ruangnya dibagi dengan tombol laci & menu pengguna, dan
   selektornya lebih spesifik supaya tidak tertimpa aturan umum di atasnya. */
@media (max-width: 575.98px) {
    .siper-merek .siper-brand__logo { height: 44px; }
    .siper-topbar .siper-merek .siper-brand__logo { height: 34px; }
}

/* ------------------------------------------------------------------
 * Kunci merek ganda — PLN di kiri, SIPER SAFE di kanan
 * (tidak dipakai layar mana pun sejak v0.57.0 — lihat `.siper-merek`)
 *
 * Selalu di atas bidang TERANG: lambang PLN berwarna penuh, dan logo
 * SIPER SAFE memang hanya terbaca di latar terang. Untuk latar gelap
 * kunci ini dibungkus `.siper-brand-plate`.
 * ---------------------------------------------------------------- */

.siper-cobrand {
    display: inline-flex;
    align-items: center;
    gap: .7rem;
    text-decoration: none;
}

/* Garis pemisah — menandai dua merek yang berdampingan, bukan satu logo
   panjang. Tingginya mengikuti isi, bukan dipatok, supaya tetap sepadan
   pada ukuran logo mana pun. */
.siper-cobrand__sep {
    align-self: stretch;
    width: 1px;
    margin: .15rem 0;
    background: var(--vz-border-color, #e9ebec);
    flex: 0 0 auto;
}

.siper-brand-plate .siper-cobrand__sep { background: #dfe2e6; }

/* Layar sempit.
   Tinggi sengaja ditimpa di sini — ini keputusan TATA LETAK, bukan pemanggil
   (lihat catatan pada .siper-brand__logo). */

/* Topbar di bawah `md`. Ambangnya sama dengan kotak cari, yang memang sudah
   disembunyikan Velzon lewat `d-none d-md-block` — jadi di bawah 768px logo
   korporat ikut mengalah supaya tombol laci, logo aplikasi, dan menu pengguna
   punya ruang. Yang harus bertahan adalah logo yang memberi tahu pengguna ia
   sedang di aplikasi mana. */
@media (max-width: 767.98px) {
    .siper-topbar .siper-cobrand .siper-brand__pln,
    .siper-topbar .siper-cobrand__sep { display: none; }
    .siper-topbar .siper-cobrand .siper-brand__logo { height: 32px; }
}

/* Halaman masuk, verifikasi, galat: keduanya tetap tampil — di sana merek
   justru satu-satunya isi di puncak halaman — hanya dikecilkan supaya muat
   pada kartu selebar layar. */
@media (max-width: 575.98px) {
    .siper-cobrand { gap: .5rem; }
    .siper-cobrand .siper-brand__pln  { height: 30px; }
    .siper-cobrand .siper-brand__logo { height: 36px; }
}

/* Lambang + nama, untuk latar gelap. */
.siper-brand__mark {
    display: inline-block;
    vertical-align: middle;
    height: 32px;
    width: 32px;
    flex: 0 0 auto;
}

/* inline-flex, BUKAN flex: saat Velzon memaksa `.logo span.logo-lg` jadi
   `inline-block` (mode rail), sebuah anak `display:flex` menjadi blok dan
   melompat ke baris sendiri — lambang di atas, nama di bawah. */
.siper-brand__text {
    display: inline-flex;
    flex-direction: column;
    justify-content: center;
    vertical-align: middle;
    margin-left: .6rem;
    line-height: 1.15;
    min-width: 0;
}

.siper-brand__name {
    font-weight: 700;
    font-size: .92rem;
    letter-spacing: .3px;
    color: #fff;
    white-space: nowrap;
}

.siper-brand__unit {
    font-size: .68rem;
    color: var(--vz-vertical-menu-item-color, #abb9e8);
    white-space: nowrap;
}

/* Logo korporat PLN. `display:block` + `max-width:none` sama alasannya dengan
   logo aplikasi: tingginya dikunci, lebarnya mengikuti, dan Bootstrap tidak
   boleh menggepengkannya lewat `img{max-width:100%}`. */
.siper-brand__pln,
.siper-brand__pln-mark {
    display: block;
    width: auto;
    max-width: none;
}

/* Rail 70px: hanya lambangnya, sedikit lebih kecil supaya ada ruang bebas. */
[data-sidebar-size="sm-hover"] .app-menu .logo-sm .siper-brand__mark,
[data-sidebar-size="sm"] .app-menu .logo-sm .siper-brand__mark {
    height: 30px;
    width: 30px;
}

/* Sisa dari sebelum ada berkas logo: kotak "SS". Masih dipakai sebagai
   cadangan bila berkas gambarnya belum dibangun. */
.siper-logo-mark {
    display: inline-grid;
    place-items: center;
    width: 34px; height: 34px;
    border-radius: var(--siper-radius);
    background: var(--vz-primary, #405189);
    color: #fff;
    font-weight: 700; font-size: .95rem; letter-spacing: .5px;
}

.siper-logo-text {
    margin-left: .55rem;
    font-weight: 700;
    letter-spacing: .3px;
    color: var(--vz-heading-color);
    line-height: 1;
}

.app-menu .siper-logo-text { color: #fff; }

/* Kotak logo sidebar dipatok setinggi topbar. Tanpa ini tingginya hanya
   setinggi kotak "SS" (34px) dan lambangnya duduk jauh di atas isi topbar —
   paling terlihat pada rail 70px, saat lambang itu satu-satunya yang tersisa. */
.app-menu .navbar-brand-box {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    height: var(--siper-topbar-h);
    padding: 0 .75rem;
}

/* Begitu sidebar terbuka penuh, tombol pengunci pindah ke tepi kanan —
   `float-end` bawaan Velzon tidak berlaku di dalam wadah flex. */
[data-sidebar-size="sm-hover"] .navbar-menu:hover .navbar-brand-box,
[data-sidebar-size="sm-hover-active"] .navbar-brand-box {
    justify-content: space-between;
    padding: 0 1rem;
}

/* Velzon menampilkan/menyembunyikan .logo-sm & .logo-lg lewat data-sidebar-size,
   tetapi hanya untuk elemen inline. Keduanya dibuat sejajar tengah di sini. */
.navbar-brand-box .logo {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 0;
    height: 100%;
}

/* line-height:1 penting — tanpa itu kotak "SS" dan teksnya duduk pada garis
   dasar yang berbeda dan terlihat seperti bertumpuk, bukan sebaris. */
.navbar-brand-box .logo-lg,
.navbar-brand-box .logo-sm {
    display: inline-flex;
    align-items: center;
    line-height: 1;
}

/* Pada mode rail, aturan Velzon `…[data-sidebar-size=sm-hover] .logo span.logo-sm`
   lebih spesifik daripada milik kita dan memaksa `display:inline-block`, yang
   mematikan penyejajaran flex di atas. `vertical-align` bekerja pada display
   apa pun, jadi dipakai sebagai pengaman — bukan lomba spesifisitas yang
   pasti kalah lagi begitu Velzon disegarkan dari docs/master/. */
.navbar-brand-box .siper-logo-mark,
.navbar-brand-box .siper-logo-text,
.navbar-brand-box .siper-brand__mark,
.navbar-brand-box .siper-brand__text { vertical-align: middle; }

.navbar-brand-box .logo-sm { display: none; }
[data-sidebar-size="sm"] .navbar-brand-box .logo-lg { display: none; }
[data-sidebar-size="sm"] .navbar-brand-box .logo-sm { display: inline-flex; }

.siper-user-btn {
    display: flex; align-items: center; gap: .5rem;
    border: 0; background: transparent; padding: .25rem .5rem;
}

.siper-avatar {
    display: inline-grid; place-items: center;
    width: 34px; height: 34px; border-radius: 50%;
    background: var(--vz-primary, #405189); color: #fff;
    font-size: .78rem; font-weight: 600;
}

/* ==================================================================
 * 3. Bilah tab
 * ================================================================ */

.siper-tabbar {
    flex: 0 0 var(--siper-tabbar-h);
    display: flex;
    align-items: stretch;
    gap: 2px;
    padding: 0 .5rem;
    background: var(--siper-head-bg);
    border-bottom: 1px solid var(--siper-border);
    overflow: hidden;
}

.siper-tabbar__home,
.siper-tabbar__btn {
    flex: 0 0 auto;
    border: 0;
    background: transparent;
    color: var(--siper-muted);
    padding: 0 .7rem;
    font-size: 1.05rem;
    line-height: 1;
    cursor: pointer;
    transition: color .12s ease, background-color .12s ease;
}

.siper-tabbar__home:hover,
.siper-tabbar__btn:hover { color: var(--vz-primary); background: rgba(0,0,0,.04); }

.siper-tabbar__overflow { display: flex; align-items: stretch; margin-left: auto; }

.siper-tabs {
    display: flex;
    align-items: stretch;
    gap: 2px;
    margin: 0;
    padding: 0;
    list-style: none;
    overflow-x: auto;
    scrollbar-width: none;
}

.siper-tabs::-webkit-scrollbar { display: none; }

.siper-tab {
    display: flex;
    align-items: center;
    max-width: 230px;
    border: 1px solid transparent;
    border-bottom: 0;
    border-radius: var(--siper-radius) var(--siper-radius) 0 0;
    background: transparent;
    margin-top: 5px;
    transition: background-color .12s ease;
}

.siper-tab:hover { background: rgba(0,0,0,.045); }

.siper-tab.is-active {
    background: var(--siper-tab-active-bg);
    border-color: var(--siper-border);
    box-shadow: 0 -2px 0 var(--vz-primary, #405189) inset;
}

.siper-tab__btn {
    display: flex; align-items: center; gap: .4rem;
    border: 0; background: transparent;
    padding: .35rem .5rem .35rem .7rem;
    font-size: .8125rem;
    color: var(--siper-muted);
    max-width: 100%;
    cursor: pointer;
}

.siper-tab.is-active .siper-tab__btn { color: var(--vz-heading-color); font-weight: 600; }

.siper-tab__label {
    max-width: 150px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.siper-tab__close {
    border: 0; background: transparent;
    color: var(--siper-muted);
    padding: 0 .5rem 0 .15rem;
    font-size: .95rem; line-height: 1;
    opacity: .55; cursor: pointer;
    transition: opacity .12s ease, color .12s ease;
}

.siper-tab__close:hover { opacity: 1; color: var(--vz-danger, #f06548); }

/* ==================================================================
 * 4. Workspace & pane
 * ================================================================ */

.siper-workspace {
    position: relative;
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
}

.siper-panes { position: absolute; inset: 0; }

.siper-pane {
    position: absolute;
    inset: 0;
    overflow: auto;
    overscroll-behavior: contain;
}

.siper-pane[hidden] { display: none; }

.fragment {
    display: flex;
    flex-direction: column;
    min-height: 100%;
}

/*
 * Tinggi toolbar diumumkan sebagai variabel supaya elemen lengket LAIN bisa
 * menumpuk di bawahnya, bukan bersembunyi di belakangnya. `.siper-pane` yang
 * menggulir (bukan halaman), jadi acuan `top` keduanya sama.
 *
 * Nilainya = padding atas + bawah (.6rem × 2) + tinggi baris isi (± 1.9rem).
 * Diikat ke satu variabel karena dua tempat yang menghitungnya sendiri-sendiri
 * pasti menyimpang begitu paddingnya diubah.
 */
:root { --siper-toolbar-h: 3.05rem; }

.fragment__toolbar {
    position: sticky;
    top: 0;
    z-index: 5;
    display: flex;
    align-items: center;
    gap: .5rem;
    flex-wrap: wrap;
    padding: .6rem 1rem;
    background: var(--siper-surface);
    border-bottom: 1px solid var(--siper-border);
}

.fragment__body { flex: 1 1 auto; padding: 1rem; }

.fragment__actionbar {
    position: sticky;
    bottom: 0;
    z-index: 6;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: .5rem;
    padding: .6rem 1rem;
    background: var(--siper-surface);
    border-top: 1px solid var(--siper-border);
    box-shadow: 0 -2px 8px rgba(0,0,0,.05);
}

.fragment__actionbar.is-dirty::before {
    content: "Ada perubahan belum tersimpan";
    margin-right: auto;
    font-size: .78rem;
    color: var(--vz-warning, #f7b84b);
    font-weight: 600;
}

.fragment__actionbar kbd {
    font-size: .68rem;
    padding: .1rem .3rem;
    border-radius: 3px;
    margin-left: .35rem;
    /* currentColor supaya terbaca di tombol terang maupun gelap */
    background: color-mix(in srgb, currentColor 16%, transparent);
    color: inherit;
    border: 1px solid color-mix(in srgb, currentColor 28%, transparent);
}

/* ==================================================================
 * 5. Indikator memuat
 * ================================================================ */

.siper-loading {
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 3px;
    overflow: hidden;
    z-index: 20;
    pointer-events: none;
}

.siper-loading__bar {
    width: 40%;
    height: 100%;
    background: var(--vz-primary, #405189);
    animation: siper-slide 1s ease-in-out infinite;
}

@keyframes siper-slide {
    0%   { transform: translateX(-100%); }
    100% { transform: translateX(300%); }
}

/* ------------------------------------------------------------------
 * Pil "Memproses…" — tanda bahwa ada permintaan TULIS yang berjalan.
 *
 * Diletakkan di TENGAH ATAS, bukan di sudut bersama toast: yang ini harus
 * tidak bisa tidak terlihat. Petugas yang tidak melihat tanda apa pun
 * menyimpulkan aplikasinya menggantung lalu memuat ulang halaman — dan
 * memuat ulang memutus permintaan yang sedang berjalan.
 *
 * z-index di bawah SweetAlert2 (1060) supaya tidak menutupi dialog
 * konfirmasi, tetapi di atas kartu dan tabel.
 * ------------------------------------------------------------------ */

.siper-kerja {
    position: fixed;
    top: 1rem;
    left: 50%;
    transform: translateX(-50%);
    z-index: 1055;
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .4rem .9rem;
    border-radius: 999px;
    font-size: .8125rem;
    font-weight: 500;
    color: #fff;
    background: rgba(33, 37, 41, .92);
    box-shadow: 0 .35rem 1rem rgba(0, 0, 0, .25);
    pointer-events: none;
    animation: siper-kerja-masuk .18s ease-out;
}

.siper-kerja .spinner-border {
    width: .9rem;
    height: .9rem;
    border-width: .15em;
}

@keyframes siper-kerja-masuk {
    from { opacity: 0; transform: translate(-50%, -.4rem); }
    to   { opacity: 1; transform: translate(-50%, 0); }
}

/* Kursor ikut memberi tahu — murah, dan terbaca bahkan saat pandangan
   petugas sedang tertuju ke tombol yang baru ia tekan. */
body.siper-sedang-sibuk { cursor: progress; }
body.siper-sedang-sibuk .btn { cursor: progress; }

@media (prefers-reduced-motion: reduce) {
    .siper-kerja { animation: none; }
}

/* ==================================================================
 * 6. Widget
 * ================================================================ */

/* Widget = kartu Velzon + kepala yang bisa dilipat/dimuat ulang.
   Ukuran, warna, sudut, dan bayangannya SENGAJA diambil dari token
   --vz-card-* supaya widget dan <div class="card"> biasa tidak pernah
   terlihat berbeda dalam satu halaman. */
.widget {
    display: flex;
    flex-direction: column;
    background-color: var(--vz-card-bg, var(--vz-secondary-bg));
    border: none;
    border-radius: var(--vz-card-border-radius, .25rem);
    box-shadow: 0 1px 2px rgba(56, 65, 74, .15);
    margin-bottom: 1.5rem;
    overflow: hidden;
}

.widget__header {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .75rem 1rem;
    background-color: var(--vz-card-cap-bg, transparent);
    border-bottom: 1px solid var(--vz-border-color);
    min-height: 52px;
}

.widget__title {
    display: flex; align-items: center; gap: .5rem;
    margin: 0;
    font-size: 15px;
    font-weight: 600;
    color: var(--vz-heading-color);
    text-transform: none;
}

.widget__title i { font-size: 1rem; opacity: .9; }

.widget__tools { display: flex; align-items: center; gap: 3px; margin-left: auto; }

/* Tombol di kepala widget mengikuti `btn-ghost-*` Velzon: transparan sampai
   disentuh. Tombol berwarna penuh di kepala kartu bersaing dengan tombol aksi
   utama halaman, padahal fungsinya cuma lipat/muat ulang. */
.widget__tool {
    display: inline-grid;
    place-items: center;
    width: 28px; height: 28px;
    border: 0;
    border-radius: 4px;
    background: transparent;
    color: var(--vz-secondary-color);
    font-size: .9rem;
    cursor: pointer;
    transition: background-color .15s ease, color .15s ease;
}

.widget__tool:hover { background: var(--vz-light); color: var(--vz-heading-color); }

.widget__tool--primary:hover   { background: var(--vz-primary-bg-subtle);   color: var(--vz-primary); }
.widget__tool--success:hover   { background: var(--vz-success-bg-subtle);   color: var(--vz-success); }
.widget__tool--info:hover      { background: var(--vz-info-bg-subtle);      color: var(--vz-info); }
.widget__tool--warning:hover   { background: var(--vz-warning-bg-subtle);   color: var(--vz-warning); }
.widget__tool--danger:hover    { background: var(--vz-danger-bg-subtle);    color: var(--vz-danger); }
.widget__tool--secondary:hover { background: var(--vz-secondary-bg-subtle); color: var(--vz-secondary); }

.widget__body { padding: 1rem; }
.widget__body.p-0 { padding: 0; }

.widget.is-collapsed .widget__body { display: none; }

.widget.is-busy { position: relative; }

.widget.is-busy::after {
    content: "";
    position: absolute; inset: 0;
    background: var(--siper-surface);
    opacity: .55;
}

/* Nada warna kepala widget.
   Memakai pasangan `bg-*-subtle` / `text-*` seperti Velzon, bukan blok warna
   pekat. Kepala berwarna penuh menarik perhatian ke pembungkusnya, bukan ke
   isinya — dan di dashboard dengan enam kartu hasilnya ramai. */
.widget--primary .widget__header { background: var(--vz-primary-bg-subtle); }
.widget--info    .widget__header { background: var(--vz-info-bg-subtle); }
.widget--success .widget__header { background: var(--vz-success-bg-subtle); }
.widget--warning .widget__header { background: var(--vz-warning-bg-subtle); }
.widget--danger  .widget__header { background: var(--vz-danger-bg-subtle); }

.widget--primary .widget__title { color: var(--vz-primary-text-emphasis); }
.widget--info    .widget__title { color: var(--vz-info-text-emphasis); }
.widget--success .widget__title { color: var(--vz-success-text-emphasis); }
.widget--warning .widget__title { color: var(--vz-warning-text-emphasis); }
.widget--danger  .widget__title { color: var(--vz-danger-text-emphasis); }

/* ==================================================================
 * 7. Tabel data (DataGrid)
 * ==================================================================
 *
 * Tabelnya memakai kelas Velzon apa adanya — `table align-middle
 * table-nowrap table-hover` + `thead.table-light` + paginasi
 * `pagination-separated`. Yang ditulis di sini HANYA yang tidak dimiliki
 * Velzon: kepala kolom lengket, penanda urut, dan tata letak toolbar/kaki.
 *
 * Jangan menyetel ulang font-size, padding sel, atau warna baris di sini.
 * Itu tugas app.min.css; menimpanya membuat tabel kita menyimpang dari
 * tabel Velzon lain di aplikasi yang sama.
 */

.datagrid { position: relative; }
.datagrid.is-busy { opacity: .6; pointer-events: none; }

.datagrid__toolbar {
    display: flex;
    align-items: center;
    gap: .5rem;
    flex-wrap: wrap;
    padding: 1rem;
    border-bottom: 1px solid var(--vz-border-color);
}

.datagrid__scroll { overflow-x: auto; }

/* Kepala kolom lengket — tambahan kita, tidak ada di Velzon.
   Latarnya wajib legap; kalau tembus, baris yang tergulir terlihat menembus. */
.datagrid thead th {
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--vz-light);
}

/* Panah urut milik Velzon (.table .sort::before/::after). Yang ditambahkan di
   sini hanya penunjuk kolom mana yang sedang dipakai — Velzon tidak punya
   status "sedang diurutkan" karena tabelnya statis. */
.datagrid th.sort { cursor: pointer; user-select: none; padding-right: 1.6rem; }
.datagrid th.sort:hover { color: var(--vz-primary); }
.datagrid th.is-sorted { color: var(--vz-primary); }
.datagrid th.is-sorted::before,
.datagrid th.is-sorted::after { opacity: .25; }
.datagrid th.is-sorted.dir-asc::before,
.datagrid th.is-sorted.dir-desc::after { opacity: 1; color: var(--vz-primary); }

.datagrid__footer {
    /* Menempel di dasar pane supaya navigasi halaman selalu terlihat
       walaupun tabelnya panjang — perilaku yang sama dengan kepala kolom. */
    position: sticky;
    bottom: 0;
    z-index: 3;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    flex-wrap: wrap;
    padding: .75rem 1rem;
    border-top: 1px solid var(--vz-border-color);
    background: var(--vz-secondary-bg);
    font-size: .8125rem;
}

.datagrid__info { margin-right: auto; }


/* ==================================================================
 * 8. Empty state
 * ================================================================ */

.empty-state {
    display: grid;
    place-items: center;
    gap: .35rem;
    padding: 2.5rem 1rem;
    text-align: center;
    color: var(--siper-muted);
}

.empty-state i { font-size: 2.6rem; opacity: .35; }
.empty-state__title { margin: 0; font-weight: 600; font-size: .9rem; }
.empty-state__hint { margin: 0; font-size: .78rem; opacity: .8; }
.empty-state--error i { color: var(--vz-danger, #f06548); opacity: .6; }

/* ==================================================================
 * 9. Toast
 * ================================================================ */

.siper-toasts {
    position: fixed;
    right: 1rem;
    bottom: calc(var(--siper-footer-h) + 1rem);
    z-index: 2000;
    display: flex;
    flex-direction: column;
    gap: .5rem;
    max-width: min(380px, calc(100vw - 2rem));
}

.siper-toast {
    display: flex;
    align-items: flex-start;
    gap: .55rem;
    padding: .65rem .75rem;
    border-radius: var(--siper-radius);
    border-left: 4px solid var(--vz-info, #299cdb);
    background: var(--siper-surface);
    box-shadow: 0 6px 20px rgba(0,0,0,.14);
    font-size: .8125rem;
    color: var(--vz-body-color);
    transform: translateY(10px);
    opacity: 0;
    transition: transform .18s ease, opacity .18s ease;
}

.siper-toast.is-shown { transform: none; opacity: 1; }
.siper-toast i { font-size: 1.05rem; line-height: 1.35; }
.siper-toast__msg { flex: 1 1 auto; }

.siper-toast__close {
    border: 0; background: transparent;
    color: var(--siper-muted);
    font-size: 1.1rem; line-height: 1;
    cursor: pointer; opacity: .6;
}

.siper-toast__close:hover { opacity: 1; }

.siper-toast.is-success { border-left-color: var(--vz-success, #0ab39c); }
.siper-toast.is-success i { color: var(--vz-success, #0ab39c); }
.siper-toast.is-error   { border-left-color: var(--vz-danger, #f06548); }
.siper-toast.is-error i { color: var(--vz-danger, #f06548); }
.siper-toast.is-warning { border-left-color: var(--vz-warning, #f7b84b); }
.siper-toast.is-warning i { color: var(--vz-warning, #f7b84b); }
.siper-toast.is-info i  { color: var(--vz-info, #299cdb); }

/* ==================================================================
 * 10. Footer
 * ================================================================ */

.siper-footer {
    flex: 0 0 var(--siper-footer-h);
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0 1rem;
    background: var(--siper-surface);
    border-top: 1px solid var(--siper-border);
    font-size: .72rem;
    color: var(--siper-muted);
}

.siper-footer__center { margin: 0 auto; }
.siper-footer__right { margin-left: auto; font-variant-numeric: tabular-nums; }
.siper-footer__center + .siper-footer__right { margin-left: 0; }

/* ==================================================================
 * 11. Form: kerapatan & bantuan visual
 * ================================================================ */

.fragment .form-label {
    font-size: .78rem;
    font-weight: 600;
    margin-bottom: .25rem;
    color: var(--vz-heading-color);
}

.fragment .form-label .req { color: var(--vz-danger, #f06548); margin-left: .15rem; }

.fragment .form-control,
.fragment .form-select { font-size: .8125rem; }

.fragment .invalid-feedback { display: block; font-size: .72rem; min-height: 1em; }

/* Ringkasan kelompok isian */
/* .form-section adalah alias kartu Velzon.
   Dipakai enam view. Didefinisikan lewat token kartu Velzon (--vz-card-*)
   supaya tampilannya tidak pernah menyimpang dari <div class="card"> asli:
   satu tema baru dari template langsung ikut, tanpa menyunting berkas ini. */
.form-section {
    background-color: var(--vz-card-bg, var(--vz-secondary-bg));
    border: none;
    border-radius: var(--vz-card-border-radius, .25rem);
    box-shadow: 0 1px 2px rgba(56, 65, 74, .15);
    margin-bottom: 1.5rem;
}

.form-section__head {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: 1rem;
    border-bottom: 1px solid var(--vz-border-color);
    font-size: 16px;
    font-weight: 600;
    color: var(--vz-heading-color);
}

/*
 * Kepala seksi yang LENGKET.
 *
 * Dipakai daftar periksa Safety Permit: 38 butir pada Working at Height berarti
 * penghitung "18 / 38 terjawab" sudah lama hilang dari layar saat petugas
 * mengisi butir ke-20 — dan justru di situlah ia paling dibutuhkan, karena
 * pengajuan ditutup selama masih ada butir kosong.
 *
 * Yang menggulir adalah `.siper-pane` (`overflow: auto`), bukan halaman — jadi
 * acuannya tepi atas pane. Tetapi `.fragment__toolbar` sudah lengket di `top: 0`
 * dengan `z-index: 5`; menaruh kepala seksi di `top: 0` juga membuatnya
 * bersembunyi DI BELAKANG toolbar, terlihat seperti sticky-nya tidak bekerja.
 * Karena itu ia menumpuk tepat di bawahnya.
 */
.form-section__head--sticky {
    position: sticky;
    top: var(--siper-toolbar-h);
    z-index: 3;
    background: var(--vz-secondary-bg);
}

.form-section__body { padding: 1rem; }

/* Aturan tombol-sedang-bekerja yang lama DIBUANG (5 Sep 2026). Ia menggambar
   spinner berwarna putih di atas teks yang ditransparankan — tidak terlihat
   sama sekali pada tombol berlatar terang, yaitu sebagian besar tombol simpan
   sekunder di aplikasi ini. Penggantinya `Siper.sibuk()` di core.js, yang
   memakai `.spinner-border` bawaan Bootstrap: warnanya mengikuti `currentColor`
   sehingga terbaca di tombol gelap maupun terang. */

/* ==================================================================
 * 12. Layar kecil
 * ================================================================ */

@media (max-width: 991.98px) {
    .siper-tab__label { max-width: 90px; }
    .fragment__body { padding: .75rem; }
    .siper-footer__center { display: none; }
}

@media (max-width: 575.98px) {
    :root { --siper-tabbar-h: 38px; }

    .siper-tab__label { display: none; }
    .siper-tab { max-width: 64px; }

    .fragment__actionbar { flex-wrap: wrap; }
    .fragment__actionbar.is-dirty::before { flex: 1 0 100%; margin-bottom: .35rem; }
    .fragment__actionbar kbd { display: none; }   /* tidak ada papan ketik fisik */

    /* Footer harus tetap satu baris; teks panjang dipotong, jam diprioritaskan. */
    .siper-footer { gap: .5rem; padding: 0 .6rem; font-size: .66rem; }
    .siper-footer__left {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    .siper-footer__right { white-space: nowrap; flex: 0 0 auto; }
}

/* ==================================================================
 * 13. Cetak — hanya isi fragment aktif yang dicetak
 * ================================================================ */

@media print {
    .siper-topbar, .siper-tabbar, .siper-footer,
    .app-menu, .fragment__actionbar, .fragment__toolbar,
    .widget__tools, .siper-toasts, .siper-loading { display: none !important; }

    body.siper-body, body.siper-body .main-content { height: auto; overflow: visible; padding-top: 0; }
    .siper-workspace, .siper-panes, .siper-pane { position: static; overflow: visible; }
    .main-content { margin-left: 0 !important; }
    .widget { border: 0; }
}

/* ==================================================================
 * 14. Halaman autentikasi
 * ==================================================================
 *
 * Tata letaknya sekarang memakai kelas Velzon apa adanya — `auth-page-wrapper`,
 * `auth-bg-cover`, `auth-one-bg`, `bg-overlay`, `auth-pass-inputgroup`. Blok
 * `.siper-auth__*` yang dulu ada di sini SENGAJA DIHAPUS: menulis ulang tata
 * letak auth berarti melawan CSS template alih-alih memakainya, dan itu yang
 * membuat tipografinya menyimpang dari halaman aplikasi.
 *
 * Yang tersisa hanya dua hal yang memang tidak dimiliki Velzon.
 */

/* Honeypot: harus tak terlihat manusia TAPI tetap ada di DOM untuk bot.
   `display:none` dilewati sebagian bot — dorong ke luar layar. */
.siper-honeypot {
    position: absolute !important;
    left: -9999px !important;
    width: 1px; height: 1px;
    overflow: hidden;
}

/* Panel kiri halaman auth.
   `auth-one-bg.jpg` adalah foto demo bawaan Velzon (suasana kantor) — bukan
   gambar unit. Lapisan warna korporat sengaja dibuat pekat supaya fotonya
   tinggal jadi tekstur dan teks putihnya tetap terbaca. Ganti berkas
   `public/assets/images/auth-one-bg.jpg` dengan foto UP Pacitan bila sudah ada,
   lalu opacity di bawah boleh diturunkan. */
.auth-one-bg .bg-overlay {
    background: linear-gradient(160deg, #2a3765 0%, #405189 58%, #0ab39c 170%);
    opacity: .94;
}

.siper-logo-mark--lg { width: 44px; height: 44px; font-size: 1.05rem; }

/* ==================================================================
 * 15. Sub-tab pada halaman detail satu entitas
 * ================================================================ */

.siper-subtabs {
    border-bottom: 1px solid var(--siper-border);
    padding: 0 .25rem;
    margin-bottom: 1rem;
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
}

.siper-subtabs::-webkit-scrollbar { display: none; }

.siper-subtabs .nav-link {
    border: 0;
    border-bottom: 2px solid transparent;
    border-radius: 0;
    padding: .5rem .85rem;
    font-size: .8125rem;
    color: var(--siper-muted);
    white-space: nowrap;
}

.siper-subtabs .nav-link:hover { color: var(--vz-primary); border-bottom-color: var(--siper-border); }

.siper-subtabs .nav-link.active {
    color: var(--vz-primary);
    font-weight: 600;
    background: transparent;
    border-bottom-color: var(--vz-primary);
}

.siper-subtab-body { min-height: 220px; }

/* Matriks izin — header kolom DAN kolom pertama menempel */
.matriks-wrap { max-height: calc(100vh - 260px); overflow: auto; }

.matriks { border-collapse: separate; border-spacing: 0; font-size: .78rem; width: 100%; }

.matriks thead th {
    position: sticky; top: 0; z-index: 3;
    background: var(--siper-head-bg);
    border-bottom: 1px solid var(--siper-border);
    padding: .5rem .4rem;
    text-align: center;
    vertical-align: bottom;
}

.matriks tbody th,
.matriks thead th:first-child {
    position: sticky; left: 0; z-index: 2;
    background: var(--siper-surface);
    border-right: 1px solid var(--siper-border);
    text-align: left;
    font-weight: 400;
    padding: .35rem .6rem;
    min-width: 300px;
}

.matriks thead th:first-child { z-index: 4; background: var(--siper-head-bg); }

.matriks tbody td {
    text-align: center;
    padding: .35rem .4rem;
    border-bottom: 1px solid var(--siper-border);
}

.matriks tbody tr:hover td,
.matriks tbody tr:hover th { background: var(--vz-light); }

.matriks tr.matriks__modul th,
.matriks tr.matriks__modul td {
    background: var(--vz-primary-subtle, #eef1f7);
    font-weight: 600;
    color: var(--vz-primary);
    position: sticky; left: 0;
}

.matriks__ya    { color: var(--vz-success, #0ab39c); font-weight: 700; }
.matriks__tidak { color: var(--siper-muted); opacity: .35; }

/* =================================================================
 * Autocomplete (Siper.Autocomplete)
 *
 * Dropdown saran istilah untuk input teks-bebas. Warnanya seluruhnya dari
 * token Velzon (--vz-*) supaya ikut berubah di mode gelap tanpa aturan kedua.
 * ============================================================== */

.siper-ac {
    position: fixed;
    z-index: 1080;                    /* di atas modal-backdrop Bootstrap (1050) */
    max-height: 260px;
    overflow-y: auto;
    background: var(--vz-dropdown-bg, var(--vz-secondary-bg));
    border: 1px solid var(--vz-border-color);
    border-radius: var(--vz-border-radius);
    box-shadow: var(--vz-box-shadow-lg);
    padding: .25rem 0;
    font-size: .8125rem;
}

.siper-ac__item {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .35rem .75rem;
    cursor: pointer;
    color: var(--vz-body-color);
}

.siper-ac__item:hover,
.siper-ac__item.is-sorot {
    background: var(--vz-tertiary-bg);
}

.siper-ac__teks {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.siper-ac__teks mark {
    padding: 0;
    background: transparent;
    color: var(--vz-primary);
    font-weight: 600;
}

/* Keterangan pendek di samping nama: jabatan, atau masa berlaku sertifikat.
   Dibuat lebih redup dan lebih kecil supaya tetap terbaca sebagai keterangan,
   bukan sebagai bagian dari namanya. */
.siper-ac__hint {
    margin-left: .4rem;
    font-size: .6875rem;
    color: var(--vz-secondary-color);
}

/* Seberapa sering istilah ini dipakai — yang membuat urutan sarannya masuk akal. */
.siper-ac__pakai {
    flex: 0 0 auto;
    font-size: .6875rem;
    color: var(--vz-secondary-color);
    background: var(--vz-tertiary-bg);
    border-radius: 10rem;
    padding: 0 .4rem;
}

/* Saran yang ADA di master tetapi tidak bisa dipakai (perusahaan nonaktif —
   BR-36). Tetap tampil supaya "lupa kalau sudah ada" terjawab; redupnya
   menyatakan bahwa ia tidak akan dipilihkan. */
.siper-ac__item.is-nonaktif .siper-ac__teks {
    color: var(--vz-secondary-color);
    text-decoration: line-through;
    text-decoration-color: var(--vz-border-color);
}

/* =================================================================
 * Pencarian global — panel saran kotak topbar (v0.59.0, butir 4.6)
 *
 * `assets/js/siper/pencarian.js`. Ditempel ke <body> + `position: fixed`
 * (topbar & kartu Velzon memotong `overflow`). Teks keterangan TIDAK memakai
 * `--vz-secondary-color` (3,43 : 1 di atas putih, AP 349) melainkan warna
 * badan yang diredupkan — tetap ≥ 4,5 : 1 di kedua tema; sorotan kata memakai
 * `--vz-link-color`, bukan `--vz-primary` yang tak berganti di mode gelap.
 * ============================================================== */
.siper-cari {
    position: fixed;
    z-index: 1080;
    overflow-y: auto;
    background: var(--vz-dropdown-bg, var(--vz-secondary-bg));
    color: var(--vz-body-color);
    border: 1px solid var(--vz-border-color);
    border-radius: var(--vz-border-radius);
    box-shadow: var(--vz-box-shadow-lg);
    padding: .25rem 0;
    font-size: .8125rem;
}

.siper-cari[hidden] { display: none; }

.siper-cari__kelompok {
    display: flex;
    align-items: center;
    gap: .4rem;
    padding: .5rem .85rem .25rem;
    font-size: .6875rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--vz-body-color);
    color: color-mix(in srgb, var(--vz-body-color) 78%, transparent);
}

.siper-cari__kelompok i { font-size: .875rem; color: var(--vz-link-color); }

.siper-cari__lebih {
    margin-left: auto;
    font-weight: 500;
    text-transform: none;
    letter-spacing: 0;
}

.siper-cari__item,
.siper-cari__semua {
    padding: .4rem .85rem;
    cursor: pointer;
}

.siper-cari__item:hover,
.siper-cari__item.is-sorot,
.siper-cari__semua:hover,
.siper-cari__semua.is-sorot {
    background: var(--vz-tertiary-bg);
}

.siper-cari__baris1 {
    display: flex;
    align-items: center;
    gap: .5rem;
    min-width: 0;
}

.siper-cari__nomor {
    font-family: var(--vz-font-monospace, monospace);
    font-weight: 600;
    white-space: nowrap;
}

.siper-cari__nomor--draf { font-family: inherit; font-style: italic; }

/* Judul DUA baris: nama pekerjaan sering panjang dan kata yang cocok kerap di
   ujungnya ("… Cable Cabin Ship Unloader") — satu baris memotongnya tepat di
   bagian yang menjelaskan kenapa barisnya muncul. */
.siper-cari__judul {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
}

.siper-cari__info {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.siper-cari__info {
    font-size: .75rem;
    color: var(--vz-body-color);
    color: color-mix(in srgb, var(--vz-body-color) 78%, transparent);
}

.siper-cari mark {
    padding: 0;
    background: transparent;
    color: var(--vz-link-color);
    font-weight: 700;
}

.siper-cari__semua {
    display: flex;
    align-items: center;
    gap: .4rem;
    margin-top: .25rem;
    border-top: 1px solid var(--vz-border-color);
    color: var(--vz-link-color);
    font-weight: 500;
}

.siper-cari__semua kbd {
    margin-left: auto;
    font-size: .6875rem;
    background: var(--vz-tertiary-bg);
    color: var(--vz-body-color);
    border: 1px solid var(--vz-border-color);
}

.siper-cari__kosong {
    padding: .9rem .85rem .6rem;
    text-align: center;
}

.siper-cari__kosong > i { display: block; font-size: 1.25rem; color: var(--vz-link-color); }

.siper-cari__petunjuk {
    margin-top: .25rem;
    font-size: .75rem;
    color: var(--vz-body-color);
    color: color-mix(in srgb, var(--vz-body-color) 78%, transparent);
}

/* Kotak cari di dalam tab Hasil Pencarian — lebar wajar di toolbar. */
.siper-cari-ulang .form-control { width: min(360px, 52vw); }

/* =================================================================
 * Pilihan + tombol "Tambah" yang menempel (Siper.TambahCepat — BR-36)
 *
 * Ruas Perusahaan / Vendor formulir Daftar Pekerjaan: kotak Choices di kiri,
 * tombol Tambah menempel di kanan seperti input-group Bootstrap. Bootstrap
 * tidak mengenal `.choices` sebagai anggota `.input-group`, jadi susunannya
 * ditulis di sini — dan radius sudut kanan kotak Choices wajib dibatalkan
 * dengan `!important`, karena Velzon memasangnya `!important`.
 *
 * `margin-bottom: 0` pada `.choices`: bawaan Velzon 24 px. Di dalam baris flex
 * margin itu ikut menentukan tinggi baris, dan tombolnya akan meregang 24 px
 * lebih tinggi daripada kotaknya.
 * ============================================================== */

.siper-tambah-cepat {
    display: flex;
    align-items: stretch;
}

.siper-tambah-cepat > .choices {
    flex: 1 1 auto;
    min-width: 0;                 /* tanpa ini nama perusahaan panjang mendorong tombolnya keluar */
    margin-bottom: 0;
}

.siper-tambah-cepat > .choices:not(:last-child) .choices__inner {
    border-top-right-radius: 0 !important;
    border-bottom-right-radius: 0 !important;
}

/* `btn-primary`, bukan `btn-soft-primary`: diukur di peramban 26 Sep 2026, soft-primary
   hanya 1,85 : 1 di mode gelap; primary 7,62 : 1 di KEDUA tema (tombol *Pilih* pada
   daftar mirip memakai alasan yang sama, *Tetap Tambahkan* memakai soft-dark 12,5 : 1). */
.siper-tambah-cepat__btn {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    margin-left: -1px;            /* satu garis tepi, bukan dua */
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
    white-space: nowrap;
}

/* Modal tambah-cepat: sedikit lebih lebar daripada bawaan 500 px supaya nama
   perusahaan yang panjang di daftar "mirip" tidak langsung terpotong. */
.siper-modal--sedang {
    --vz-modal-width: 560px;
}

.siper-tambah-cepat-form .form-label {
    font-size: .78rem;
    font-weight: 600;
    margin-bottom: .25rem;
    color: var(--vz-heading-color);
}

.siper-tambah-cepat-form .form-label .req { color: var(--vz-danger, #f06548); margin-left: .15rem; }

/* Daftar "mirip" — teks berwarna badan + garis kiri bernada, BUKAN
   `alert-warning`: varian *text-emphasis* tema ini terlalu pucat di atas latar
   kuning muda (2,25 : 1, Aturan Permanen 252). */
.siper-tambah-cepat-form__mirip {
    border-left: 3px solid var(--vz-warning);
    background: var(--vz-warning-bg-subtle);
    color: var(--vz-body-color);
    border-radius: var(--vz-border-radius);
    padding: .65rem .75rem;
}

.siper-tambah-cepat-form__mirip[hidden] { display: none; }

.siper-tambah-cepat-form__judul {
    font-size: .8125rem;
    font-weight: 600;
    margin-bottom: .5rem;
}

.siper-tambah-cepat-form__daftar {
    display: flex;
    flex-direction: column;
    gap: .35rem;
}

.siper-tambah-cepat-form__baris {
    display: flex;
    align-items: center;
    gap: .5rem;
    background: var(--vz-secondary-bg);
    border: 1px solid var(--vz-border-color);
    border-radius: var(--vz-border-radius);
    padding: .4rem .5rem;
}

.siper-tambah-cepat-form__nama {
    flex: 1 1 auto;
    min-width: 0;                 /* Aturan Permanen 201 — ruas yang boleh menyusut butuh batas bawah */
}

.siper-tambah-cepat-form__tetap {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
    margin-top: .6rem;
}

/* Penyaring yang dipindahkan ke baris kontrol DataTables. `[hidden]` dilepas
   bersama wadah sementaranya; aturan ini hanya merapikan jaraknya. */
.siper-dt-slot > .d-flex,
.siper-dt-slot > .row {
    justify-content: flex-end;
}

@media (max-width: 767.98px) {
    .siper-dt-slot > .d-flex { justify-content: flex-start; }
}

/* Kotak cari yang berbagi baris dengan penyaring.

   Bootstrap `col-sm-auto` menyusutkan kolomnya seukuran isi, dan lebar bawaan
   `<input>` di Chrome ± 118 px — cukup untuk "Cari…" tetapi tidak untuk melihat
   apa yang sedang diketik. Register pengguna dicari dengan nama lengkap dan
   nomor SPK; keduanya lebih panjang dari itu. */
.dataTables_filter input {
    min-width: 220px;
}

@media (max-width: 575.98px) {
    .dataTables_filter input { min-width: 0; width: 100%; }
}

/* Latar sel KOLOM BEKU (FixedColumns 4.3, §3.5) — v0.52.0.

   `fixedColumns.bootstrap5.min.css` memberi sel beku `background-color: white`
   di mode terang dan `var(--bs-body-bg)` di mode gelap. Velzon mengkompilasi
   Bootstrap dengan awalan `--vz-`, jadi `--bs-body-bg` TIDAK ADA: deklarasinya
   tidak sah saat dihitung dan latarnya jatuh ke `transparent`. Akibatnya di
   mode GELAP setiap sel beku tembus pandang — kolom yang bergulir di bawahnya
   ikut terbaca menimpa No/Nama/Status/Aksi di SEMUA register bermode gulir
   (terukur sesi 94: `rgba(0, 0, 0, 0)` pada td & th beku register Daftar
   Pekerjaan dan JSA). Di mode terang kepala beku putih sementara kepala lain
   `#f3f6f9`.

   Sel badan memakai latar kartu (`--vz-secondary-bg`, sama dengan `.card`
   Velzon); sel kepala memakai `--vz-table-bg` milik `thead.table-light`-nya
   sendiri, sehingga warnanya selalu sama dengan kepala yang tidak beku.
   `html[data-bs-theme]` menyamai kekhususan aturan gelap pustakanya; berkas
   ini dimuat sesudahnya, jadi aturan ini yang menang di kedua tema. Efek
   `table-hover` tetap terlihat: Bootstrap melukisnya lewat `box-shadow` inset
   di atas latar ini. */
html[data-bs-theme] table.dataTable tbody tr > .dtfc-fixed-left,
html[data-bs-theme] table.dataTable tbody tr > .dtfc-fixed-right {
    background-color: var(--vz-secondary-bg);
}

html[data-bs-theme] table.dataTable thead tr > .dtfc-fixed-left,
html[data-bs-theme] table.dataTable thead tr > .dtfc-fixed-right {
    background-color: var(--vz-table-bg);
}

/* =================================================================
 * Panel "intip" — assets/js/siper/peek.js
 *
 * Komponen yang TIDAK dimiliki Velzon (Aturan Permanen 27): sebuah popover
 * yang bisa dibuka dengan sentuhan tetikus maupun papan ketik, berisi daftar
 * yang tiap barisnya membuka dokumennya. Popover Bootstrap tidak dipakai —
 * ia tidak mengenal mode "disemat", isinya tidak bisa diganti tanpa
 * membangun ulang instansnya, dan ia tidak ikut berpindah induk saat papan
 * dijadikan layar penuh.
 * ============================================================== */

.siper-peek {
    position: fixed;
    z-index: 1080;                   /* di atas modal-backdrop Bootstrap (1050) */
    /* 34rem: cukup untuk nomor + nama pekerjaan + waktu + lencana tanpa salah
       satunya tergencet. Diukur pada kartu Dashboard, yang barisnya paling
       padat (nomor JSA panjang + nama pekerjaan + tanggal + nama perusahaan).
       Tetap dijepit lebar layar supaya di ponsel ia tidak menjulur. */
    width: min(34rem, calc(100vw - 1rem));
    max-height: min(24rem, calc(100vh - 2rem));
    display: flex;
    flex-direction: column;
    background: var(--vz-dropdown-bg, var(--vz-secondary-bg));
    border: 1px solid var(--vz-border-color);
    border-radius: var(--vz-border-radius);
    box-shadow: var(--vz-box-shadow-lg);
    overflow: hidden;
}

/* WAJIB. `display: flex` di atas adalah gaya PENULIS, dan gaya penulis selalu
   mengalahkan aturan bawaan peramban `[hidden] { display: none }` — berapa pun
   spesifisitasnya. Tanpa baris ini `panel.hidden = true` tidak menyembunyikan
   apa pun: panelnya tetap terlihat di sudut layar, sementara SELURUH pemeriksaan
   yang membaca atribut `hidden` menjawab "sudah tertutup". */
.siper-peek[hidden] { display: none; }

.siper-peek__head {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .5rem .75rem;
    border-bottom: 1px solid var(--vz-border-color);
    background: var(--vz-tertiary-bg);
    font-size: .8125rem;
    font-weight: 600;
    color: var(--vz-body-color);
}

.siper-peek__body {
    overflow-y: auto;
    padding: .25rem 0;
}

/* Panel yang disemat diberi cincin tipis: ia bertahan sampai ditutup, dan
   bedanya dengan panel intip yang hilang sendiri harus terlihat. */
.siper-peek.is-disemat {
    box-shadow: var(--vz-box-shadow-lg), 0 0 0 2px rgba(var(--vz-primary-rgb), .35);
}

.siper-peek__baris {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .5rem .75rem;
    font-size: .8125rem;
    color: var(--vz-body-color);
    text-decoration: none;
    border-bottom: 1px solid var(--vz-border-color-translucent, rgba(0, 0, 0, .05));
}

.siper-peek__baris:last-child { border-bottom: 0; }

.siper-peek__baris:hover,
.siper-peek__baris:focus-visible {
    background: var(--vz-tertiary-bg);
    color: var(--vz-body-color);
    outline: none;
}

.siper-peek__nomor {
    flex: 0 0 auto;
    font-weight: 600;
    white-space: nowrap;
}

/* Nama pekerjaan boleh menyusut — TETAPI TIDAK SAMPAI HABIS.
   Tanpa `min-width`, ruas ini kalah dari rentang tanggal dan lencana nama
   perusahaan yang panjang, dan yang tersisa di layar hanya "[C…". Terlihat
   pada kartu Dashboard: nama pekerjaan adalah penanda paling penting sesudah
   nomornya, dan justru itu yang lenyap. */
.siper-peek__kerja {
    flex: 1 1 auto;
    min-width: 8rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--vz-secondary-color);
}

.siper-peek__waktu {
    flex: 0 0 auto;
    font-size: .75rem;
    color: var(--vz-secondary-color);
    white-space: nowrap;
}

/* Lencana (jenis izin / pelaksana) ikut menyusut bila namanya panjang —
   `flex-shrink-0` di sinilah yang dulu menggencet nama pekerjaan.

   TETAPI ia pun punya batas bawah. Tanpa `min-width`, ruas yang boleh
   menyusut akan menyusut SAMPAI HABIS begitu tetangganya menahan diri:
   nama pekerjaan dilindungi `min-width: 8rem`, sehingga lencananya yang
   tergerus — terbaca "Hot …", "Confined …", "Near & Un…". Pelajaran yang
   sama, ruas yang berbeda. */
.siper-peek__baris .badge {
    flex: 0 1 auto;
    min-width: 6rem;
    max-width: 10rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    text-align: center;
}

.siper-peek__kosong,
.siper-peek__potong {
    padding: .5rem .75rem;
    font-size: .75rem;
    color: var(--vz-secondary-color);
}

.siper-peek__potong { border-top: 1px solid var(--vz-border-color); }

/* Tautan penutup panel: "Buka register …".
   Dibedakan dari baris biasa — ia tidak menunjuk satu dokumen melainkan
   membawa keluar dari panel, dan menyamakannya dengan baris permit membuat
   orang mengiranya salah satu dokumennya. */
.siper-peek__lanjut {
    display: block;
    padding: .5rem .75rem;
    border-top: 1px solid var(--vz-border-color);
    background: var(--vz-tertiary-bg);
    font-size: .75rem;
    font-weight: 500;
    color: var(--vz-link-color, var(--vz-primary));
    text-decoration: none;
}

.siper-peek__lanjut:hover,
.siper-peek__lanjut:focus-visible {
    background: var(--vz-secondary-bg);
    text-decoration: underline;
    outline: none;
}

/* Pemicu: kursor dan sorotan yang menyatakan "ini bisa dibuka". Tanpa penanda
   ini, kartu angka terlihat sama saja dengan kartu yang memang mati. */
.siper-peek-pemicu { cursor: pointer; }

.siper-peek-pemicu:focus-visible {
    outline: 2px solid var(--vz-primary);
    outline-offset: 2px;
}

/* =================================================================
 * Progres Safety Permit per jenis — Dashboard (v0.51.0)
 *
 * Tiga warna untuk tiga keadaan (OPEN · INPROGRES · CLOSE) dipakai BERSAMA
 * kartu per jenis, grafik batang, dan pie — satu warna, satu arti, di ketiga
 * tempat. Rona biru–oranye–hijau mengikuti gambar referensi pemilik project
 * (`resource/grafik-*-dashboard.png`); langkahnya DIVALIDASI dengan pemeriksa
 * palet (skill dataviz, `validate_palette.js --pairs all`) terhadap permukaan
 * kartu yang diukur di peramban:
 *
 *   terang (#ffffff) — ΔE buta warna 12,0 · normal 22,6 · kontras ≥ 3 : 1
 *   gelap  (#212529) — ΔE buta warna 11,5 · normal 24,3 · kontras ≥ 3 : 1
 *
 * Mode gelap BUKAN warna yang sama: hijau tua #196b24 hanya ± 2 : 1 di atas
 * kartu gelap, dan hijau yang lebih terang sekecerahan oranye runtuh jadi
 * satu warna bagi pembaca buta warna merah-hijau. Pasangan gelapnya dipisah
 * lewat kecerahan. Grafik membacanya lewat `Siper.Grafik.warna()`, jadi
 * mengubah warna cukup di sini.
 * ============================================================== */

:root {
    --siper-progres-open: #1d6db8;
    --siper-progres-inprogres: #e97132;
    --siper-progres-close: #196b24;
}

:root[data-bs-theme="dark"] {
    --siper-progres-open: #2673d1;
    --siper-progres-inprogres: #bd4d00;
    --siper-progres-close: #4ca871;
}

/* Kunci warna kecil di depan label. Teks label & angkanya sendiri memakai
   warna TEKS, bukan warna data — oranye/hijau sebagai teks tidak terbaca
   (dataviz: text wears text tokens). */
.siper-progres-kunci {
    display: inline-block;
    flex: 0 0 auto;
    width: .625rem;
    height: .625rem;
    margin-right: .375rem;
    border-radius: 2px;
}

.siper-progres-kunci--open      { background: var(--siper-progres-open); }
.siper-progres-kunci--inprogres { background: var(--siper-progres-inprogres); }
.siper-progres-kunci--close     { background: var(--siper-progres-close); }

/* Kartu per jenis: tiga angka berdampingan bila kartunya cukup lebar, dan
   MENUMPUK jadi daftar bila sempit. Lima kartu sebaris di layar 1200 px dengan
   sidebar berlabel hanya ± 170 px lebarnya — tiga kolom di situ memotong label
   "INPROGRES". Container query mengukur KARTUNYA, bukan layarnya. */
.siper-progres-kartu .card-body { container-type: inline-size; }

.siper-progres-angka {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: .5rem;
}

.siper-progres-angka__label {
    display: flex;
    align-items: center;
    font-size: .6875rem;
    font-weight: 500;
    letter-spacing: .02em;
    text-transform: uppercase;
    white-space: nowrap;
    color: var(--vz-secondary-color);
}

.siper-progres-angka__nilai {
    display: block;
    margin-top: .25rem;
    font-size: 1.375rem;
    font-weight: 600;
    line-height: 1.2;
    color: var(--vz-heading-color, var(--vz-body-color));
}

@container (max-width: 14.5rem) {
    .siper-progres-angka { grid-template-columns: 1fr; gap: .125rem; }

    .siper-progres-angka__sel {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: .5rem;
    }

    .siper-progres-angka__nilai {
        margin-top: 0;
        font-size: 1rem;
        font-variant-numeric: tabular-nums;   /* angka sekolom — rata kanan sejajar */
    }
}

/* Rincian pie yang disemat (klik irisan) — tabel jenis × keadaan. Kolom
   keadaan yang dipilih diberi latar tipis, bukan warna teks: nilainya tetap
   berwarna teks supaya terbaca di kedua tema. */
.siper-progres-rinci {
    margin-top: .75rem;
    border: 1px solid var(--vz-border-color);
    border-radius: var(--vz-border-radius);
    overflow: hidden;
}

.siper-progres-rinci[hidden] { display: none; }

.siper-progres-rinci__kepala {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .5rem .75rem;
    background: var(--vz-tertiary-bg);
    border-bottom: 1px solid var(--vz-border-color);
    font-size: .8125rem;
    font-weight: 600;
}

/* Penanda kolom aktif — satu-satunya yang boleh ditambahkan pada tabel
   (Aturan Permanen 27); ukuran & padding selnya tetap milik Velzon. */
.siper-progres-rinci td.is-pilih,
.siper-progres-rinci th.is-pilih { background: var(--vz-tertiary-bg); font-weight: 600; }

/* Label TENGAH donat. `app.min.css` Velzon memaksa `.apexcharts-pie text`
   putih — untuk donat, "Total" di tengah lubang jadi putih di atas kartu putih.
   Velzon sendiri menimpanya per-grafik (`#portfolio_donut_charts`). Jaring
   pengaman di samping penyalin warna `Siper.Grafik` (grafik.js). */
[data-grafik-progres] .apexcharts-pie .apexcharts-datalabel-label { fill: var(--vz-secondary-color); }
[data-grafik-progres] .apexcharts-pie .apexcharts-datalabel-value { fill: var(--vz-body-color); }

/* Tooltip pie berbentuk tabel mini — lebih lebar daripada tooltip bawaan. */
.siper-grafik-tip { padding: .5rem .625rem; min-width: 15rem; font-size: .75rem; }
.siper-grafik-tip__kepala { display: flex; align-items: center; margin-bottom: .375rem; font-weight: 600; }
.siper-grafik-tip table { width: 100%; border-collapse: collapse; }
.siper-grafik-tip th,
.siper-grafik-tip td { padding: .125rem .25rem; text-align: right; white-space: nowrap; }
.siper-grafik-tip th:first-child,
.siper-grafik-tip td:first-child { text-align: left; }
.siper-grafik-tip thead th { font-weight: 500; color: var(--vz-secondary-color); }
.siper-grafik-tip .is-pilih { font-weight: 700; background: var(--vz-tertiary-bg); }

/* =================================================================
 * Kalender permit — Papan Permit Aktif
 * ============================================================== */

/* Papan dalam LAYAR PENUH (`root.requestFullscreen()` pada `section.fragment`).
   Peramban mematok elemen layar penuh setinggi layar, tetapi `overflow`-nya
   tetap `visible` dan yang biasanya menggulir — `.siper-pane` — tidak ikut
   dirender. Terukur (v0.54.0): isi papan 1.689 px di layar 1.000 px, dan
   kalender di bawahnya TIDAK BISA dicapai sama sekali — tanpa galat. Latarnya
   juga transparan, jadi `::backdrop` hitam tampil di sela kartu mode terang.
   Elemennya sendiri yang menggulir; toolbar lengketnya ikut lengket di sini. */
.fragment:fullscreen {
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--vz-body-bg);
}

.siper-kalender td { vertical-align: top; }

.siper-kalender__hari {
    height: 96px;
    transition: background-color .12s ease-in-out;
}

.siper-kalender__hari.has-permit { cursor: pointer; }

.siper-kalender__hari.has-permit:hover,
.siper-kalender__hari.has-permit[aria-expanded="true"] {
    background: var(--vz-tertiary-bg);
}

.siper-kalender__hari.has-permit:focus-visible {
    outline: 2px solid var(--vz-primary);
    outline-offset: -2px;
}

.siper-kalender__hari.is-hari-ini {
    background: rgba(var(--vz-primary-rgb), .12);
    box-shadow: inset 0 0 0 2px rgba(var(--vz-primary-rgb), .45);
}

.siper-kalender__kosong { background: var(--vz-light-bg-subtle, var(--vz-tertiary-bg)); }

.siper-kalender__no {
    font-size: .75rem;
    font-weight: 600;
    margin-bottom: .25rem;
}

/* Satu permit di dalam sel: penanda progres + lencana nomornya (v0.54.0).
   Penandanya DI LUAR lencana, di atas latar sel — warna progres divalidasi
   terhadap permukaan kartu, bukan terhadap latar `bg-*-subtle` jenis izin. */
.siper-kalender__permit {
    display: flex;
    align-items: center;
    gap: .25rem;
    min-width: 0;
    margin-bottom: .2rem;
}

.siper-kalender__permit .siper-progres-kunci { margin-right: 0; }

/* Cincin tipis berwarna TEKS di sekeliling kotak progres pada kalender & panel
   tanggalnya. Warna data divalidasi terhadap permukaan KARTU, tetapi sel
   kalender tidak selalu berlatar kartu: sel HARI INI berlatar biru muda dan sel
   yang disentuh berlatar `--vz-tertiary-bg`. Terukur di peramban (v0.54.0):
   oranye INPROGRES di sel hari ini hanya 2,54 : 1 (terang) / 2,89 : 1 (gelap),
   biru OPEN di sel yang disentuh 2,93 : 1 (gelap) — di bawah 3 : 1 untuk
   penanda non-teks (WCAG 1.4.11). Cincin 60 % warna teks memberi ≥ 3,48 : 1
   terhadap ketiga latar di kedua tema, jadi BENTUK kotaknya selalu terbaca;
   warnanya tinggal membedakan keadaannya. Kotak di kartu Dashboard tidak
   disentuh — di sana latarnya memang kartu. */
.siper-kalender__permit .siper-progres-kunci,
.siper-kal-legenda .siper-progres-kunci,
.siper-kal-ringkas .siper-progres-kunci,
.siper-kal-baris__progres .siper-progres-kunci {
    box-shadow: 0 0 0 1px rgba(var(--vz-body-color-rgb), .6);
}

/* Lencana nomor: mengisi sisa lebar sel dan terpotong rapi. `min-width: 0`
   WAJIB — anak flex bawaannya tidak mau menyusut di bawah lebar teksnya, dan
   nomor yang panjang lalu menjulurkan selnya lebih lebar dari kolom harinya. */
.siper-kalender__badge {
    display: block;
    flex: 1 1 auto;
    min-width: 0;
    font-weight: 400;
    text-align: left;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Menggantung: IKON alarm, bukan warna keempat. Merah dan oranye (INPROGRES)
   nyaris tak terbedakan bagi pembaca buta warna merah-hijau; bentuknya
   terbedakan. Warnanya `--vz-danger-text-emphasis`, BUKAN `--vz-danger`:
   terukur, `--vz-danger` hanya 2,63 : 1 di sel hari ini (terang), sedangkan
   varian emphasis ≥ 3,52 : 1 (terang) / ≥ 5,49 : 1 (gelap) di sel biasa,
   sel hari ini, dan sel yang disentuh. */
.siper-kalender__gantung {
    flex: 0 0 auto;
    font-size: .8125rem;
    line-height: 1;
    color: var(--vz-danger-text-emphasis);
}

.siper-kalender__lagi {
    font-size: .6875rem;
    color: var(--vz-secondary-color);
}

/* Keterangan warna di bawah kalender. Teksnya warna TEKS (body), bukan warna
   data — oranye/hijau sebagai teks tidak terbaca (dataviz). Bukan pula
   `--vz-secondary-color`: token itu 3,43 : 1 di mode terang (AP 349), dan
   teks baru wajib ≥ 4,5 : 1 di kedua tema. */
.siper-kal-legenda {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .25rem .875rem;
    font-size: .6875rem;
    color: var(--vz-body-color);
}

.siper-kal-legenda__sel {
    display: inline-flex;
    align-items: center;
    white-space: nowrap;
    color: var(--vz-body-color);
}

.siper-kal-legenda__sel .siper-kalender__gantung { margin-right: .375rem; }

/* ---- Panel tanggal (Siper.Peek) ---- */

/* Ringkasan jumlah per progres di puncak panel tanggal. */
.siper-kal-ringkas {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .25rem .75rem;
    padding: .5rem .75rem;
    border-bottom: 1px solid var(--vz-border-color);
    font-size: .75rem;
    color: var(--vz-body-color);
}

.siper-kal-ringkas__judul {
    font-weight: 600;                /* warna TEKS, bukan sekunder — lihat .siper-kal-legenda */
}

.siper-kal-ringkas__sel {
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    white-space: nowrap;
}

.siper-kal-ringkas__sel .siper-progres-kunci { margin-right: 0; }

/* Baris panel DUA TINGKAT: nomor · pekerjaan · progres, lalu jenis · waktu.
   `.siper-peek__baris` menata anaknya sebaris; di sini anaknya dua baris
   flex yang masing-masing mewarisi aturan ruas fleksibel panel
   (`min-width` pada nama pekerjaan & lencana — docs/09 §7c). */
.siper-peek__baris.siper-kal-baris {
    flex-direction: column;
    align-items: stretch;
    gap: .25rem;
}

.siper-kal-baris__atas,
.siper-kal-baris__bawah {
    display: flex;
    align-items: center;
    gap: .5rem;
    min-width: 0;
}

/* Tingkat bawah boleh MEMBUNGKUS: jenis izin + *Ditunda* + kalimat waktu tidak
   selalu muat sebaris di panel yang dijepit lebar layar ponsel, dan kalimat
   waktu ber-`nowrap` yang tak bisa turun menjulurkan barisnya keluar panel. */
.siper-kal-baris__bawah {
    flex-wrap: wrap;
    row-gap: .25rem;
    font-size: .75rem;
}

/* Lencana progres di ujung kanan tingkat atas. */
.siper-kal-baris__progres { margin-left: auto; }

.siper-kal-baris__progres .siper-kalender__gantung { margin-right: .25rem; font-size: .75rem; }

/* Ponsel: panelnya dijepit ± 344 px, sementara nomor + nama pekerjaan (min
   8rem) + lencana progres (min 6rem) butuh ± 380 px — terukur meluber di
   360 px. Nama pekerjaan turun ke barisnya sendiri SELEBAR panel; nomor dan
   lencana progres tetap berdampingan di atasnya. */
@media (max-width: 575.98px) {
    .siper-kal-baris__atas { flex-wrap: wrap; row-gap: .125rem; }

    .siper-kal-baris__atas .siper-peek__kerja {
        order: 3;
        flex: 1 1 100%;
        min-width: 0;
    }
}

/* =================================================================
 * Matriks centang — kolom `P`–`AG` sheet `List`
 *
 * Berkas manual yang digantikan aplikasi ini memberi TIAP butir kelengkapan
 * kolomnya sendiri: sebelas untuk dokumen `a`–`k` (`R`–`AB`), lima untuk jenis
 * izin `l`–`p` (`AC`–`AG`), semuanya berlebar seragam 13 karakter dengan
 * **kepala tegak** (`textRotation = 90`, tinggi baris kepala 101 pt). Petugas
 * membacanya sebagai satu matriks sekali pandang, dan itulah bentuk yang
 * diminta pemilik project.
 *
 * Kepala mendatar pada kolom selebar 36 px akan memaksa lebarnya sepuluh kali
 * lipat — tabel 40 kolomnya berhenti muat, dan justru perbandingan kolom demi
 * kolom dengan Excel yang jadi tujuannya hilang.
 *
 * Ini BUKAN penyetelan ulang tabel (Aturan Permanen 27): keduanya komponen yang
 * hanya menyala pada kolom yang meminta kelasnya, bukan aturan yang mengenai
 * `.table` secara umum.
 * ============================================================== */

/* Kepala kolom tegak, dibaca dari bawah ke atas — sama dengan rotasi 90° Excel. */
.siper-th-tegak {
    /* `vertical-rl` + putar 180° = teks mengalir dari BAWAH ke atas. Tanpa
       putarannya ia mengalir dari atas ke bawah, dan kepala kolomnya terbaca
       terbalik dibanding berkas aslinya. */
    writing-mode: vertical-rl;
    transform: rotate(180deg);

    /*
     * Tinggi tetap supaya seluruh kepala kolom sejajar, berapa pun panjang
     * judulnya — dan cukup untuk judul TERPANJANG di master, bukan untuk
     * rata-rata. Diukur di peramban: pada 150 px, "Asuransi Ketenagakerjaan"
     * dan "Near and Under Water Permit" terpotong tanpa tanda apa pun.
     *
     * 210 px masih di bawah tinggi baris kepala berkas aslinya kalau
     * dikonversi apa adanya (101 pt ≈ 135 px) — bedanya di sana teksnya
     * MEMBUNGKUS (`wrap_text`), di sini satu baris. Judul yang lebih panjang
     * lagi tetap terpotong, jadi penjaganya mengukur `scrollHeight`, bukan
     * mempercayai angka ini.
     */
    height: 180px;
    white-space: nowrap;
    text-align: left;      /* sesudah diputar: menempel ke BAWAH sel */
    font-weight: 600;
    font-size: 10px;
    line-height: 1.1;
}

/*
 * Panah urut DataTables ditambatkan ke TENGAH tinggi `<th>`
 * (`bottom: 50%` / `top: 50%`, `right: 10px`). Pada kepala setinggi 180 px itu
 * membuatnya melayang jauh di atas judulnya — terbaca seperti ikon yang lepas
 * dari tempatnya, bukan seperti kontrol pengurutan.
 *
 * Kelas ini menariknya kembali ke bawah, dan dipasang HANYA pada kolom yang
 * memintanya (`headClass`) — bukan pada `.table` secara umum (Aturan Permanen
 * 27). Selektornya sengaja sepadan spesifisitasnya dengan milik DataTables;
 * `siper.css` dimuat terakhir, jadi ia menang tanpa `!important`.
 */
table.dataTable thead > tr > th.siper-th-bawah::before {
    top: auto;
    bottom: 24px;
}

table.dataTable thead > tr > th.siper-th-bawah::after {
    top: auto;
    bottom: 14px;
}

/*
 * Pada kepala TEGAK panahnya dibuang sama sekali: `transform: rotate(180deg)`
 * ikut memutar pseudo-elemennya, sehingga panahnya muncul terbalik di sudut
 * yang salah. Kolomnya tetap bisa diurut dengan diklik — kursornya sudah
 * menjadi penunjuk, dan judul tegaknya sendiri yang jadi sasaran klik.
 */
table.dataTable thead > tr > th.siper-th-tegak::before,
table.dataTable thead > tr > th.siper-th-tegak::after {
    display: none;
}

/* Tanpa panah, ruang yang disediakan DataTables untuknya tidak diperlukan. */
table.dataTable thead > tr > th.siper-th-tegak.sorting,
table.dataTable thead > tr > th.siper-th-tegak.sorting_asc,
table.dataTable thead > tr > th.siper-th-tegak.sorting_desc {
    padding-right: 4px;
}

/* Tanda di dalam sel matriks. */
.siper-centang {
    display: inline-block;
    min-width: 1em;
    font-size: 15px;
    line-height: 1;
    cursor: help;
    user-select: none;
}

/* `√` — sudah ada. Padanan tanda yang ditulis tangan di berkas manual. */
.siper-centang.is-ada {
    color: var(--vz-success);
    font-weight: 700;
}

/*
 * `✗` — wajib, belum ada, dan **menahan pengajuan** (sejak Sesi 64).
 *
 * Satu-satunya hal yang ditambahkan di luar berkas manual: di sana keadaan ini
 * tidak bisa dibedakan dari sel kosong biasa, padahal ia yang menentukan
 * dokumennya bisa diajukan atau tidak.
 */
.siper-centang.is-kurang {
    color: var(--vz-danger);
    font-weight: 700;
}

/* Belum ada, tetapi tidak menahan apa pun — sel kosong, seperti di berkasnya. */
.siper-centang.is-kosong {
    color: transparent;
}

/*
 * `·` — tidak diperlukan sama sekali (jenis izin yang tidak dicentang di JSA,
 * atau butir yang dibuang dari pekerjaan ini).
 *
 * Dibedakan dari "belum ada" dengan sengaja: di berkas manual sel kosong
 * berarti KEDUANYA, dan itulah yang membuat orang mengira ada izin yang hilang
 * padahal tidak pernah dibutuhkan.
 */
.siper-centang.is-nihil {
    color: var(--vz-tertiary-color);
    opacity: .5;
}

/* ==================================================================
 * 16. Panduan Penggunaan (manual book)
 * ==================================================================
 *
 * Dua kolom: daftar isi lengket di kiri, badan buku di kanan. Yang menggulir
 * adalah `.siper-pane`, bukan halaman — jadi acuan `top` daftar isi adalah
 * tepi atas pane. `.fragment__toolbar` sudah lengket di `top: 0` (z-index 5),
 * karena itu daftar isi MENUMPUK di bawahnya lewat `--siper-toolbar-h`;
 * menaruhnya di `top: 0` membuatnya bersembunyi di belakang toolbar dan
 * terlihat seperti sticky-nya tidak bekerja.
 *
 * Bab yang tersaring pencarian disembunyikan lewat `el.hidden`. Aturan
 * `[hidden]{display:none}` bawaan peramban KALAH dari `display` yang ditulis
 * penulis (CLAUDE.md §7), dan `.pd-bab`/`.pd-toc__link` keduanya memang
 * ber-`display` sendiri — jadi penindihannya ditulis di sini, apa adanya.
 *
 * Latar kartu memakai `--vz-secondary-bg`, BUKAN `--vz-card-bg`. Velzon hanya
 * mendefinisikan `--vz-card-bg` DI DALAM `.card`; di luar kartu variabelnya
 * kosong dan cadangan `#fff` yang menang — di mode gelap itu menjadi blok
 * putih berteks terang yang tak terbaca (terukur 11 Sep 2026 pada kartu
 * sambutan, chip bab, dan pil alur status). `.card` Velzon sendiri:
 * `background-color: var(--vz-secondary-bg)`.
 *
 * TEKS berwarna utama memakai `--vz-link-color`, bukan `--vz-primary`.
 * `--vz-primary` tidak berganti di mode gelap: #405189 di atas kartu gelap
 * hanya 2,02 : 1 (terukur). `--vz-link-color` adalah varian yang disiapkan
 * Velzon untuk teks — 7,62 : 1 terang, 11,27 : 1 gelap. `--vz-primary` tetap
 * dipakai sebagai LATAR berteks putih (7,62 : 1 di kedua tema).
 *
 * Kotak bernada (lencana izin, penghitung hasil cari) memakai warna teks
 * BADAN di atas latar berwarna, dan nadanya dibawa garis kiri. Varian
 * `--vz-*-text-emphasis` tema ini terlalu pucat untuk teks di atas latar
 * muda: lencana "tidak terbuka untuk peran Anda" terukur 2,25 : 1 dan
 * penghitung hasil cari 3,5 : 1 di mode terang.
 */

.panduan {
    display: grid;
    grid-template-columns: minmax(0, 16rem) minmax(0, 1fr);
    gap: 1.5rem;
    align-items: start;
    padding: 1rem;
}

.panduan__isi { min-width: 0; }

/* ---- Daftar isi ---- */

.panduan__toc { position: sticky; top: calc(var(--siper-toolbar-h) + .5rem); }

.pd-toc {
    background: var(--vz-card-bg, var(--vz-secondary-bg));
    border-radius: var(--vz-card-border-radius, .25rem);
    box-shadow: 0 1px 2px rgba(56, 65, 74, .15);
    overflow: hidden;
}

.pd-toc__isi {
    max-height: calc(100vh - var(--siper-toolbar-h) - 9rem);
    overflow-y: auto;
    padding: .5rem;
}

.pd-toc__hasil {
    margin: .25rem .25rem .5rem;
    padding: .35rem .5rem;
    border-radius: .25rem;
    background: var(--vz-info-bg-subtle, #e7f3ff);
    border-left: 3px solid var(--vz-info);
    color: var(--vz-body-color);
    font-size: .72rem;
}

.pd-toc__hasil[hidden] { display: none !important; }

.pd-toc__grup + .pd-toc__grup { margin-top: .65rem; }
.pd-toc__grup[hidden] { display: none !important; }

.pd-toc__grup-judul {
    display: flex;
    align-items: center;
    gap: .4rem;
    padding: .3rem .5rem;
    font-size: .68rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--vz-secondary-color, #878a99);
}

.pd-toc__link {
    display: flex;
    align-items: flex-start;
    gap: .45rem;
    padding: .32rem .5rem;
    border-radius: .25rem;
    font-size: .78rem;
    line-height: 1.35;
    color: var(--vz-body-color);
    text-decoration: none;
}

.pd-toc__link[hidden] { display: none !important; }
.pd-toc__link:hover { background: var(--vz-tertiary-bg, #f3f6f9); color: var(--vz-link-color); }

.pd-toc__link.is-active {
    background: var(--vz-primary-bg-subtle, #eaecf4);
    color: var(--vz-link-color);
    font-weight: 600;
}

.pd-toc__no {
    flex: 0 0 1.35rem;
    height: 1.35rem;
    display: grid;
    place-items: center;
    border-radius: .25rem;
    background: var(--vz-tertiary-bg, #f3f6f9);
    font-size: .66rem;
    font-weight: 600;
    color: var(--vz-secondary-color, #878a99);
}

.pd-toc__link.is-active .pd-toc__no { background: var(--vz-primary); color: #fff; }
.pd-toc__teks { min-width: 0; }

.pd-toc__toggle {
    display: flex;
    align-items: center;
    gap: .5rem;
    width: 100%;
    padding: .7rem 1rem;
    border: 0;
    background: transparent;
    font-weight: 600;
    font-size: .85rem;
    color: var(--vz-heading-color);
}

/* ---- Kartu sambutan ---- */

.pd-sambut {
    display: flex;
    gap: 1rem;
    padding: 1.15rem;
    margin-bottom: 1.5rem;
    border-radius: var(--vz-card-border-radius, .25rem);
    background: linear-gradient(135deg, var(--vz-primary-bg-subtle, #eaecf4), var(--vz-secondary-bg) 65%);
    box-shadow: 0 1px 2px rgba(56, 65, 74, .15);
}

.pd-sambut__ikon {
    display: grid;
    place-items: center;
    width: 3rem;
    height: 3rem;
    border-radius: .85rem;
    background: var(--vz-primary);
    color: #fff;
    font-size: 1.5rem;
}

.pd-sambut__kanan { min-width: 0; }
.pd-sambut__judul { font-size: 1.05rem; font-weight: 600; margin-bottom: .35rem; }
.pd-sambut__peran { font-size: .84rem; margin-bottom: .35rem; }
.pd-sambut__tugas { font-size: .84rem; margin-bottom: .5rem; color: var(--vz-body-color); }

.pd-sambut__saran {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .4rem;
    margin-bottom: .65rem;
}

.pd-sambut__saran-label {
    font-size: .72rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--vz-secondary-color, #878a99);
}

.pd-chip {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    padding: .2rem .55rem;
    border-radius: 999px;
    background: var(--vz-secondary-bg);
    border: 1px solid var(--vz-border-color);
    font-size: .74rem;
    color: var(--vz-link-color);
    text-decoration: none;
}

.pd-chip:hover { background: var(--vz-primary); border-color: var(--vz-primary); color: #fff; }

.pd-sambut__catatan {
    margin: 0;
    padding-top: .6rem;
    border-top: 1px dashed var(--vz-border-color);
    font-size: .76rem;
    color: var(--vz-secondary-color, #878a99);
}

.pd-sambut__catatan i { margin-right: .3rem; }

/* ---- Judul bagian & bab ---- */

.pd-bagian { margin: 2.25rem 0 1rem; }
.pd-bagian[hidden] { display: none !important; }
.pd-bagian:first-of-type { margin-top: .5rem; }

.pd-bagian__judul {
    display: flex;
    align-items: center;
    gap: .5rem;
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--vz-link-color);
    margin-bottom: .2rem;
}

.pd-bagian__ket { font-size: .78rem; color: var(--vz-secondary-color, #878a99); margin: 0; }

.pd-bab {
    display: block;
    background: var(--vz-card-bg, var(--vz-secondary-bg));
    border-radius: var(--vz-card-border-radius, .25rem);
    box-shadow: 0 1px 2px rgba(56, 65, 74, .15);
    margin-bottom: 1rem;
    scroll-margin-top: calc(var(--siper-toolbar-h) + 1rem);
}

.pd-bab[hidden] { display: none !important; }

.pd-bab__head {
    display: flex;
    gap: .85rem;
    padding: 1rem 1.15rem;
    border-bottom: 1px solid var(--vz-border-color);
}

.pd-bab__no {
    flex: 0 0 2rem;
    height: 2rem;
    display: grid;
    place-items: center;
    border-radius: .5rem;
    background: var(--vz-primary-bg-subtle, #eaecf4);
    color: var(--vz-link-color);
    font-weight: 700;
    font-size: .85rem;
}

.pd-bab__judul-wrap { min-width: 0; }

.pd-bab__judul {
    display: flex;
    align-items: center;
    gap: .45rem;
    font-size: 1rem;
    font-weight: 600;
    margin-bottom: .15rem;
}

.pd-bab__ringkas { font-size: .78rem; color: var(--vz-secondary-color, #878a99); margin: 0; }

.pd-bab__izin {
    margin: .5rem 0 0;
    padding: .4rem .6rem;
    border-radius: .25rem;
    background: var(--vz-warning-bg-subtle, #fff6e0);
    border-left: 3px solid var(--vz-warning);
    color: var(--vz-body-color);
    font-size: .74rem;
}

.pd-bab__isi { padding: 1.15rem; font-size: .84rem; line-height: 1.65; }
.pd-bab__isi > :last-child { margin-bottom: 0; }

.pd-bab__kaki {
    padding: .5rem 1.15rem .85rem;
    border-top: 1px dashed var(--vz-border-color);
}

.pd-atas {
    font-size: .74rem;
    color: var(--vz-secondary-color, #878a99);
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: .3rem;
}

.pd-atas:hover { color: var(--vz-link-color); }

.pd-penutup {
    margin: 1.5rem 0 .5rem;
    font-size: .76rem;
    color: var(--vz-secondary-color, #878a99);
    text-align: center;
}

/* ---- Blok isi yang dipakai berulang di dalam bab ---- */

.pd-sec { margin-bottom: 1.4rem; }
.pd-sec:last-child { margin-bottom: 0; }

.pd-sec > h4 {
    font-size: .88rem;
    font-weight: 600;
    margin-bottom: .5rem;
    padding-bottom: .3rem;
    border-bottom: 1px solid var(--vz-border-color);
    display: flex;
    align-items: center;
    gap: .4rem;
}

.pd-bab__isi ol, .pd-bab__isi ul { padding-left: 1.15rem; margin-bottom: .85rem; }
.pd-bab__isi li { margin-bottom: .3rem; }
.pd-bab__isi p { margin-bottom: .7rem; }

/* Langkah bernomor — nomornya besar supaya bisa dibaca sambil melihat layar. */
.pd-steps { counter-reset: pd; list-style: none; padding-left: 0 !important; }

.pd-steps > li {
    position: relative;
    padding-left: 2rem;
    margin-bottom: .55rem;
    counter-increment: pd;
}

.pd-steps > li::before {
    content: counter(pd);
    position: absolute;
    left: 0;
    top: .05rem;
    width: 1.45rem;
    height: 1.45rem;
    display: grid;
    place-items: center;
    border-radius: 50%;
    background: var(--vz-primary);
    color: #fff;
    font-size: .7rem;
    font-weight: 700;
}

/* Kotak catatan. Empat nada, sama dengan nada toast aplikasi. */
.pd-note {
    display: flex;
    gap: .55rem;
    padding: .65rem .8rem;
    border-radius: .3rem;
    border-left: 3px solid var(--vz-info);
    background: var(--vz-info-bg-subtle, #e7f3ff);
    font-size: .8rem;
    margin-bottom: .9rem;
}

.pd-note > i { flex: 0 0 auto; font-size: .95rem; line-height: 1.5; }
.pd-note > div > :last-child { margin-bottom: 0 !important; }
.pd-note--warn { border-left-color: var(--vz-warning); background: var(--vz-warning-bg-subtle, #fff6e0); }
.pd-note--danger { border-left-color: var(--vz-danger); background: var(--vz-danger-bg-subtle, #fde8e8); }
.pd-note--ok { border-left-color: var(--vz-success); background: var(--vz-success-bg-subtle, #e6f6ee); }

/* Jalur menu: "Transaksi › JSA › Buat JSA".
 *
 * `display: inline` + `box-decoration-break: clone`, BUKAN `inline-flex` +
 * `nowrap`: jalur terpanjang ("Master Data › Referensi K3 › Kelengkapan
 * Dokumen") lebih lebar dari kartu bab di layar 400 px — terukur meluap 27 px
 * dan menyeret seluruh badan panduan bergeser mendatar. Sekarang ia patah
 * seperti teks biasa, dan bingkainya ikut tergambar di setiap barisnya. */
.pd-path {
    display: inline;
    padding: .1rem .45rem;
    border-radius: .25rem;
    background: var(--vz-tertiary-bg, #f3f6f9);
    border: 1px solid var(--vz-border-color);
    font-size: .74rem;
    font-weight: 500;
    line-height: 1.9;
    -webkit-box-decoration-break: clone;
    box-decoration-break: clone;
}

.pd-kbd {
    display: inline-block;
    padding: .05rem .35rem;
    border-radius: .2rem;
    border: 1px solid var(--vz-border-color);
    border-bottom-width: 2px;
    background: var(--vz-tertiary-bg, #f3f6f9);
    font-size: .72rem;
    font-family: var(--vz-font-family-monospace, monospace);
    color: var(--vz-body-color);
}

.pd-tabel { overflow-x: auto; margin-bottom: .9rem; }
.pd-tabel table { width: 100%; font-size: .78rem; border-collapse: collapse; }

.pd-tabel th, .pd-tabel td {
    padding: .42rem .6rem;
    border-bottom: 1px solid var(--vz-border-color);
    vertical-align: top;
    text-align: left;
}

.pd-tabel thead th {
    background: var(--vz-tertiary-bg, #f3f6f9);
    font-weight: 600;
    white-space: nowrap;
}

.pd-tabel tbody tr:last-child td { border-bottom: 0; }

/* Rantai langkah mendatar: DRAFT → DIAJUKAN → … */
.pd-alur {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .35rem;
    padding: .6rem .7rem;
    border-radius: .3rem;
    background: var(--vz-tertiary-bg, #f3f6f9);
    margin-bottom: .9rem;
}

.pd-alur span {
    padding: .18rem .5rem;
    border-radius: .25rem;
    background: var(--vz-secondary-bg);
    border: 1px solid var(--vz-border-color);
    font-size: .72rem;
    font-weight: 600;
}

.pd-alur i { color: var(--vz-secondary-color, #878a99); font-size: .8rem; }

/* ---- Ponsel & tablet ---- */

@media (max-width: 991.98px) {
    .panduan { grid-template-columns: minmax(0, 1fr); gap: .75rem; padding: .75rem; }
    .panduan__toc { position: static; }
    .pd-toc__isi { display: none; max-height: 55vh; }
    .pd-toc__isi.is-open { display: block; }
    .pd-sambut { flex-direction: column; gap: .75rem; }
}

/* ---- Cetak ----
 * Daftar isi dibuang: pada kertas ia menyisakan kolom kosong sepanjang buku,
 * dan penomorannya sudah ada di kepala tiap bab. */

@media print {
    .panduan { display: block; padding: 0; }
    .panduan__toc, .pd-bab__kaki, .pd-sambut__saran { display: none !important; }
    .pd-bab { box-shadow: none; border: 1px solid #ddd; break-inside: auto; page-break-inside: auto; }
    .pd-bab__head { break-after: avoid; page-break-after: avoid; }
    .pd-bagian { break-before: page; page-break-before: always; }
    .pd-bagian:first-of-type { break-before: auto; page-break-before: auto; }
    .pd-sec { break-inside: avoid; page-break-inside: avoid; }
}

/* =================================================================
 * Linimasa "Progres Pekerjaan" — components/progres_linimasa.php
 *
 * Fase 6.2.2. Komponen yang TIDAK dimiliki Velzon dalam bentuk ini
 * (Aturan Permanen 27): daftar bernomor vertikal dengan garis penghubung,
 * tiap butirnya membawa dokumen yang bisa dibuka sebagai tab.
 *
 * Garisnya digambar ::before pada ITEM, bukan sebagai border wadah — dengan
 * begitu butir terakhir bisa memutusnya tanpa menghitung jumlah butir, dan
 * jumlah tahap boleh bertambah (JSO 6.3, Live Audit 6.4, Safety Clearance
 * 6.5) tanpa satu baris CSS pun berubah.
 * ============================================================== */

.siper-alur {
    list-style: none;
    margin: 0;
    padding: 0;
}

.siper-alur__item {
    position: relative;
    display: flex;
    gap: .75rem;
    padding: 0 0 1rem 0;
}

.siper-alur__item:last-child { padding-bottom: 0; }

/* Garis penghubung. `calc` memakai tinggi bulatan (1.75rem) sebagai titik
   mulai supaya ia berangkat dari BAWAH ikon, bukan dari tengahnya. */
.siper-alur__item::before {
    content: "";
    position: absolute;
    left: .875rem;
    top: 1.75rem;
    bottom: 0;
    width: 1px;
    background: var(--vz-border-color);
}

.siper-alur__item:last-child::before { display: none; }

.siper-alur__bulat {
    position: relative;
    z-index: 1;
    flex: 0 0 auto;
    width: 1.75rem;
    height: 1.75rem;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: .875rem;
    /* Latar solid supaya garis di belakangnya tidak menembus bulatan. */
    box-shadow: 0 0 0 3px var(--vz-secondary-bg);
}

.siper-alur__isi { min-width: 0; flex: 1 1 auto; }

/* Baris dokumen: nomor + status + keterangan, dibungkus supaya tidak pecah
   di tengah saat kartunya sempit. */
.siper-alur__dok {
    display: inline-flex;
    align-items: center;
    gap: .375rem;
    padding: .25rem .5rem;
    border: 1px solid var(--vz-border-color);
    border-radius: var(--vz-border-radius);
    background: var(--vz-tertiary-bg);
    max-width: 100%;
}

/* Tahap yang sedang berjalan ditebalkan sedikit — ia yang dicari mata lebih
   dulu saat kartunya dibuka. */
.siper-alur__item.is-berjalan .siper-alur__isi { font-weight: 500; }

/* =====================================================================
 * Daftar periksa OBSERVASI — YA · TIDAK · N/A (Fase 6.3.6)
 *
 * Komponen `components/daftar_periksa_observasi`, dipakai JSO dan kelak Live
 * Audit. Dirancang untuk ponsel di area kerja (Q-21): satu kolom, tanpa tabel
 * menggulir ke samping, target sentuh ≥ 44 px (pedoman WCAG 2.5.5 / Apple HIG).
 *
 * Warna tombol TERPILIH ditentukan sendiri, bukan `btn-success`/`btn-danger`
 * Velzon: teks putih di atas `#0ab39c` hanya 2,64 : 1 dan di atas `#f06548`
 * 3,15 : 1 — di bawah ambang AA. Tiga warna di bawah diukur ≥ 4,5 : 1 dengan teks
 * putih, di mode terang maupun gelap (Aturan Permanen 252: diukur, bukan ditebak).
 * ================================================================== */
.obs {
    --obs-ya: #067a6a;      /* putih di atasnya 5,25 : 1 (rumus luminans WCAG) */
    --obs-tidak: #b3261e;   /* 6,54 : 1 */
    --obs-na: #495057;      /* 8,18 : 1 */
}

.obs__kepala { flex-wrap: wrap; row-gap: .375rem; }
.obs__skor { font-size: .75rem; }

.obs__petunjuk {
    padding: .625rem 1rem;
    border-bottom: 1px solid var(--vz-border-color);
    background: var(--vz-tertiary-bg);
}

.obs__daftar {
    list-style: none;
    margin: 0;
    padding: 0;
}

.obs__judul {
    padding: .75rem 1rem .375rem;
    font-weight: 600;
    font-size: .8125rem;
    color: var(--vz-heading-color);
    background: var(--vz-tertiary-bg);
    border-bottom: 1px solid var(--vz-border-color);
}

.obs__judul .obs__kode { margin-right: .375rem; }

.obs__butir {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem 1rem;
    padding: .625rem 1rem;
    border-bottom: 1px solid var(--vz-border-color);
    border-left: 3px solid transparent;
    transition: background-color .3s ease;
}

.obs__butir.is-tidak { border-left-color: var(--obs-tidak); }
.obs__butir.is-sorot { background: var(--vz-warning-bg-subtle); }

/* Teks butir boleh menyusut, tetapi tidak sampai habis — tanpa `min-width`
   ia kalah dari tombol di sebelahnya (Aturan Permanen 201). */
.obs__teks {
    flex: 1 1 18rem;
    min-width: 12rem;
    display: flex;
    gap: .5rem;
    font-size: .8125rem;
    line-height: 1.45;
}

.obs__kode {
    flex: 0 0 auto;
    min-width: 1.75rem;
    font-weight: 600;
    color: var(--vz-secondary-color);
}

.obs__pilihan {
    flex: 0 0 auto;
    display: flex;
    gap: .375rem;
}

.obs__btn {
    min-width: 4.25rem;
    min-height: 44px;
    padding: .5rem .75rem;
    font-size: .8125rem;
    font-weight: 600;
    border: 1px solid var(--vz-border-color);
    background: var(--vz-secondary-bg);
    color: var(--vz-body-color);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.obs__btn:hover { border-color: var(--vz-secondary-color); }

.btn-check:checked + .obs__btn--ya    { background: var(--obs-ya);    border-color: var(--obs-ya);    color: #fff; }
.btn-check:checked + .obs__btn--tidak { background: var(--obs-tidak); border-color: var(--obs-tidak); color: #fff; }
.btn-check:checked + .obs__btn--na    { background: var(--obs-na);    border-color: var(--obs-na);    color: #fff; }

.btn-check:focus-visible + .obs__btn {
    outline: 2px solid var(--vz-link-color);
    outline-offset: 2px;
}

.obs__catatan { flex: 1 1 100%; }
.obs__catatan[hidden] { display: none; }

.obs__jawaban { flex: 0 0 auto; }
.obs__catatan-baca { flex: 1 1 100%; padding-left: 2.25rem; }

/* Ponsel: teks di atas, tiga tombol MEMBAGI RATA lebar di bawahnya — jari
   tidak perlu membidik tombol selebar teks "N/A". */
@media (max-width: 575.98px) {
    .obs__pilihan { flex: 1 1 100%; }
    .obs__btn { flex: 1 1 0; }
    .obs__teks { min-width: 0; flex-basis: 100%; }
    .obs__kepala .obs__lompat { flex: 1 1 100%; }
}

/* Foto observasi — kisi kecil, gambar dipotong rapi, tombol buang di pojok. */
.jso-foto {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr));
    gap: .75rem;
}

.jso-foto__item {
    position: relative;
    border: 1px solid var(--vz-border-color);
    border-radius: var(--vz-border-radius);
    overflow: hidden;
    background: var(--vz-tertiary-bg);
    aspect-ratio: 4 / 3;
}

.jso-foto__item img { width: 100%; height: 100%; object-fit: cover; display: block; }

.jso-foto__buang {
    position: absolute;
    top: .25rem;
    right: .25rem;
    min-width: 36px;
    min-height: 36px;
}

/* =====================================================================
 * Live Audit (Fase 6.4) — butir khusus per jenis izin, Permit Pekerjaan,
 * penghentian pekerjaan, dan draf lokal.
 *
 * Warna teks di atas latar bernada memakai `--vz-body-color` / garis bernada,
 * bukan varian *emphasis* tema ini (terlalu pucat — Aturan Permanen 252).
 * ================================================================== */

/* Lencana "butir khusus" — jenis izin yang membuat butirnya aktif (BR-30). */
.obs__khusus {
    display: inline-block;
    margin-left: .25rem;
    padding: .0625rem .375rem;
    font-size: .6875rem;
    font-weight: 500;
    line-height: 1.4;
    white-space: nowrap;
    vertical-align: middle;
    color: var(--vz-body-color);
    background: var(--vz-info-bg-subtle);
    border: 1px solid var(--vz-info-border-subtle);
    border-radius: var(--vz-border-radius);
}

.obs__khusus--mati {
    color: var(--vz-secondary-color);
    background: var(--vz-tertiary-bg);
    border-color: var(--vz-border-color);
}

/* Butir terkunci: tetap terbaca (ia tercetak di lembar), tetapi jelas bukan
   sesuatu yang perlu disentuh — latar tersier, tanpa tombol. */
.obs__butir--terkunci { background: var(--vz-tertiary-bg); }
.obs__butir--terkunci .obs__teks { color: var(--vz-secondary-color); }
.obs__judul--terkunci { color: var(--vz-secondary-color); }

/* Delapan kotak "Permit Pekerjaan" (sel B39–R43) — dihitung dari JSA. */
.la-permit {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(10.5rem, 1fr));
    gap: .5rem;
}

.la-permit__kotak {
    display: flex;
    align-items: center;
    gap: .5rem;
    min-height: 2.5rem;
    padding: .375rem .625rem;
    font-size: .8125rem;
    color: var(--vz-secondary-color);
    border: 1px solid var(--vz-border-color);
    border-left-width: 3px;
    border-radius: var(--vz-border-radius);
    background: var(--vz-secondary-bg);
}

.la-permit__kotak.is-on {
    color: var(--vz-body-color);
    font-weight: 500;
    border-color: var(--vz-success-border-subtle);
    border-left-color: var(--vz-success);
    background: var(--vz-success-bg-subtle);
}

.la-permit__kotak i { font-size: 1.125rem; }

/* Spanduk penghentian pekerjaan (BR-31) — teks badan di atas latar bernada,
   garis kiri merah tebal: keadaan yang paling perlu terlihat di halaman.

   Namanya `siper-stop`, BUKAN `la-stop` (v0.47.0–v0.51.0): `icons.min.css`
   Velzon memuat Line Awesome, yang mendefinisikan `.la-stop:before
   { content: "\f04d" }`. Tanpa kelas `.la` yang memberi font ikonnya, titik
   kode itu dirender dalam Poppins sebagai kotak kosong "□" di pojok kiri atas
   SETIAP spanduk penghentian — detail Live Audit, Safety Permit, PTW, dan
   Daftar Pekerjaan. Kelas milik kita tidak boleh berawalan `la-`/`las-`/
   `lab-`/`ri-`/`bx-`/`mdi-` yang sama dengan kelas ikon: dijaga
   `AssetVelzonTest::testKelasSiperTidakBentrokDenganKelasIkon`. */
.siper-stop {
    border-left: 4px solid var(--vz-danger);
    background: var(--vz-danger-bg-subtle);
    color: var(--vz-body-color);
    border-radius: var(--vz-border-radius);
    padding: .75rem 1rem;
}

.siper-stop__judul { font-weight: 600; }

/* Draf lokal — isian yang belum tersimpan di server (docs/16 6.4.6).
   `!important` WAJIB: spanduknya berkelas `d-flex`, dan utilitas Bootstrap
   `.d-flex { display: flex !important }` mengalahkan `[hidden]` maupun aturan
   ini tanpa `!important` — spanduk kosong ber-tombol "Buang isian lokal" tampil
   di SETIAP formulir Live Audit walau tidak ada draf (v0.47.0–v0.51.0, terukur
   `getComputedStyle` = flex pada elemen ber-`hidden`; diperbaiki v0.52.0). */
.la-draf-lokal[hidden] { display: none !important; }

/* =====================================================================
 * Daftar periksa OBSERVASI — mode CENTANG (v0.52.0)
 *
 * Centang = YA, kosong = N/A — pola aplikasi PLN WPO Plus, atas keputusan
 * pemilik project 26 September 2026 (K-03 dibalik). SELURUH baris adalah
 * `<label>` kotaknya: target sentuh selebar baris dan setinggi ≥ 48 px, jadi
 * petugas bersarung tangan tidak perlu membidik kotak 24 px di ujung kanan.
 * Warna kotak tercentang `--obs-ya` (putih di atasnya 5,25 : 1) — bukan
 * `--vz-primary`, yang tidak berganti di mode gelap (Aturan Permanen 331).
 * ================================================================== */
.obs--centang .obs__butir--centang {
    display: block;
    padding: 0;
}

.obs__centang {
    display: flex;
    align-items: flex-start;
    gap: .625rem;
    width: 100%;
    min-height: 48px;
    margin: 0;
    padding: .6875rem 1rem;
    font-size: .8125rem;
    line-height: 1.45;
    cursor: pointer;
    user-select: none;
}

/* Teks butir boleh menyusut, tetapi tidak sampai habis (Aturan Permanen 201). */
.obs__centang .obs__isi { flex: 1 1 auto; min-width: 8rem; }

.obs__kotak.form-check-input {
    flex: 0 0 auto;
    width: 1.5rem;
    height: 1.5rem;
    margin: 0 0 0 auto;
    border-width: 2px;
    border-color: var(--vz-border-color-translucent, var(--vz-border-color));
    cursor: pointer;
}

.obs__kotak.form-check-input:checked {
    background-color: var(--obs-ya);
    border-color: var(--obs-ya);
}

.obs__kotak.form-check-input:focus { box-shadow: none; }
.obs__kotak.form-check-input:focus-visible {
    outline: 2px solid var(--vz-link-color);
    outline-offset: 2px;
}

.obs__butir--centang:hover { background: var(--vz-tertiary-bg); }

/* Tercentang: latar & garis kiri bernada — terbaca dari jauh tanpa membaca kotaknya. */
.obs__butir--centang.is-ya {
    background: var(--vz-success-bg-subtle);
    border-left-color: var(--obs-ya);
}

/* Butir yang belum pernah tersimpan jawabannya — lihat docblock komponen. */
.obs__baru {
    display: inline-block;
    margin-left: .25rem;
    padding: .0625rem .375rem;
    font-size: .6875rem;
    font-weight: 500;
    line-height: 1.4;
    white-space: nowrap;
    vertical-align: middle;
    color: var(--vz-body-color);
    background: var(--vz-warning-bg-subtle);
    border: 1px solid var(--vz-warning-border-subtle);
    border-radius: var(--vz-border-radius);
}

/* Isian LAMA ber-TIDAK (sebelum v0.52.0) — dipertahankan, bukan dibuang diam-diam. */
.obs__lama { padding: 0 1rem .75rem 3.375rem; }
.obs__lama[hidden],
.obs__butir.is-ya .obs__lama { display: none; }

.obs__lama-baris {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .25rem .75rem;
    margin-bottom: .375rem;
}

.obs__lama-lencana {
    font-size: .75rem;
    font-weight: 600;
    color: var(--vz-body-color);
    border-left: 3px solid var(--obs-tidak);
    padding-left: .5rem;
}

.obs__lama-na { font-size: .75rem; }

/* Legenda "Centang = YA · Kosong = N/A" di kepala daftar (kalimat referensi). */
.obs__legenda {
    display: inline-flex;
    flex-wrap: wrap;
    gap: .25rem .75rem;
    color: var(--vz-secondary-color);
}

.obs__legenda i { font-size: .9375rem; vertical-align: -2px; }
.obs__legenda-ya i { color: var(--obs-ya); }

.obs--centang .obs__progres { color: var(--vz-body-color); }

/* Bilah kemajuan di tepi bawah kepala lengket: berapa yang sudah dicentang. */
.obs--centang .obs__kepala { position: relative; }
.obs--centang .obs__kepala.form-section__head--sticky,
.obs--centang .obs__kepala.obs__kepala--lengket-lokal { position: sticky; }

.obs__meter {
    position: absolute;
    left: 0;
    right: 0;
    bottom: -1px;
    height: 3px;
    background: var(--vz-border-color);
    overflow: hidden;
}

.obs__meter > span {
    display: block;
    height: 100%;
    background: var(--obs-ya);
    transition: width .2s ease;
}

/* Kepala yang menempel di dalam MODAL: yang menggulir badan modalnya sendiri,
   bukan pane — jadi menempel di tepi atas badan modal, bukan di bawah toolbar. */
.obs__kepala--lengket-lokal {
    position: sticky;
    top: 0;
    z-index: 3;
    background: var(--vz-secondary-bg);
}

@media (max-width: 575.98px) {
    .obs__centang { padding: .6875rem .75rem; }
    .obs__lama { padding-left: .75rem; }
}

/* =====================================================================
 * Modal JSO & Live Audit dari Daftar Pekerjaan (v0.52.0) — `Siper.ObsModal`
 *
 * Susunan WPO Plus: daftar periksa di kiri, data pekerja / catatan / foto di
 * kanan. Layar penuh di bawah 992 px (`modal-fullscreen-lg-down`) — daftar 37
 * butir di dalam kotak kecil di tengah ponsel adalah dua gulungan bertumpuk.
 * ================================================================== */
.obs-modal-dialog .modal-content { background: var(--vz-body-bg); }

.obs-modal__kepala {
    align-items: flex-start;
    gap: .75rem;
    background: var(--vz-secondary-bg);
}

.obs-modal__kepala-isi { flex: 1 1 auto; min-width: 0; }

.obs-modal__kepala-baris {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .375rem .625rem;
}

.obs-modal__kepala-baris .modal-title { font-size: 1rem; font-weight: 600; margin: 0; }
.obs-modal__kepala-ikon { font-size: 1.25rem; color: var(--vz-link-color); }
.obs-modal__status { font-size: .75rem; font-weight: 600; }

.obs-modal__kepala-sub {
    margin-top: .125rem;
    font-size: .8125rem;
    color: var(--vz-secondary-color);
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.obs-modal-dialog .modal-body.obs-modal__badan { padding: 0; }
.obs-modal { padding: 1rem 1.25rem; }

.obs-modal__kaki {
    gap: .5rem;
    background: var(--vz-secondary-bg);
}

.obs-modal__kaki > * { margin: 0; }

.obs-modal__kaki-kiri {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
    margin-right: auto !important;
}

/* Ringkasan pekerjaan — disalin server, hanya-baca (BR-26). */
.obs-modal__pekerjaan {
    padding: .75rem 1rem;
    border: 1px solid var(--vz-border-color);
    border-left: 3px solid var(--vz-link-color);
    border-radius: var(--vz-border-radius);
    background: var(--vz-secondary-bg);
}

.obs-modal__pekerjaan-nama {
    display: flex;
    gap: .5rem;
    align-items: baseline;
    font-size: .875rem;
}

.obs-modal__fakta {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(10.5rem, 1fr));
    gap: .5rem 1.25rem;
    margin: .5rem 0 0;
}

.obs-modal__fakta dt {
    font-size: .6875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .02em;
    color: var(--vz-secondary-color);
}

.obs-modal__fakta dd { margin: 0; font-size: .8125rem; }

.obs-modal__permit { margin-top: .75rem; }

.obs-modal__riwayat {
    margin-top: .75rem;
    padding: .5rem .75rem;
    border-radius: var(--vz-border-radius);
    background: var(--vz-tertiary-bg);
    line-height: 1.7;
}

/* Kolom kanan — kartu kecil bertumpuk. */
.obs-modal__panel {
    margin-bottom: 1rem;
    padding: .875rem 1rem;
    border: 1px solid var(--vz-border-color);
    border-radius: var(--vz-border-radius);
    background: var(--vz-secondary-bg);
}

.obs-modal__panel-judul {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin: 0 0 .625rem;
    font-size: .875rem;
    font-weight: 600;
    color: var(--vz-heading-color);
}

.obs-modal__panel .form-label { font-size: .75rem; font-weight: 600; margin-bottom: .25rem; }

.obs-modal .obs { margin-bottom: 1rem; }

/* Data Pekerja: nama + skill + Tambah dalam SATU baris (Aturan Permanen 168). */
.obs-modal__pekerja-tambah {
    display: flex;
    gap: .375rem;
    margin-bottom: .625rem;
}

.obs-modal__pekerja-tambah input[data-obs-pekerja-nama] { flex: 1 1 55%; min-width: 0; }
.obs-modal__pekerja-tambah input[data-obs-pekerja-skill] { flex: 1 1 45%; min-width: 0; }
.obs-modal__pekerja-tambah .btn { flex: 0 0 auto; }

.obs-modal__pekerja-tabel {
    max-height: 15rem;
    overflow-y: auto;
    border: 1px solid var(--vz-border-color);
    border-radius: var(--vz-border-radius);
}

.obs-modal__pekerja-tabel .table { font-size: .8125rem; }
.obs-modal__pekerja-tabel thead th { position: sticky; top: 0; z-index: 1; }
.obs-modal__pekerja-kosong[hidden] { display: none; }

/* Foto — kisi lebih rapat daripada halaman detail (kolom kanan sempit). */
.obs-modal__foto { grid-template-columns: repeat(auto-fill, minmax(6.25rem, 1fr)); gap: .5rem; }

.obs-modal__antre { outline: 2px dashed var(--vz-warning); outline-offset: -2px; }
.obs-modal__antre img { width: 100%; height: 100%; object-fit: cover; display: block; }

.obs-modal__antre-tanda {
    position: absolute;
    left: .25rem;
    bottom: .25rem;
    padding: 0 .375rem;
    font-size: .625rem;
    font-weight: 600;
    color: var(--vz-body-color);
    background: var(--vz-warning-bg-subtle);
    border-radius: var(--vz-border-radius);
}

/* Mode hasil — angka ringkas di kanan nomor dokumen. */
.obs-modal__ringkas {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .75rem 1.5rem;
    padding: .875rem 1rem;
    border: 1px solid var(--vz-border-color);
    border-left: 3px solid var(--vz-success);
    border-radius: var(--vz-border-radius);
    background: var(--vz-secondary-bg);
}

.obs-modal__angka { display: flex; flex-wrap: wrap; gap: 1.25rem; }
.obs-modal__angka > div { display: flex; flex-direction: column; align-items: center; min-width: 3rem; }
.obs-modal__angka-nilai { font-size: 1.25rem; font-weight: 600; line-height: 1.15; }

.obs-modal__angka-label {
    font-size: .6875rem;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--vz-secondary-color);
}

/* Mode tertahan — kalimat keadaan di tengah. */
.obs-modal__tertahan { padding: 2.5rem 1rem 2rem; text-align: center; }
.obs-modal__tertahan-ikon { font-size: 2.5rem; line-height: 1; margin-bottom: .75rem; color: var(--vz-warning); }
.obs-modal__tertahan-teks { max-width: 40rem; }

@media (max-width: 575.98px) {
    .obs-modal { padding: .75rem; }
    .obs-modal__kaki .btn { flex: 1 1 auto; }
    .obs-modal__kaki-kiri { width: 100%; }
}

/* Modal tampil layar penuh di bawah `lg` (`modal-fullscreen-lg-down`) — di
   sanalah petugas mengisi sambil berdiri di area kerja, sering bersarung
   tangan. Tombol kaki setinggi target sentuh daftar periksanya (≥ 44 px);
   bawaan `btn-sm` hanya 27 px (terukur 360 px). */
@media (max-width: 991.98px) {
    .obs-modal__kaki .btn:not(.btn-link) {
        min-height: 2.75rem;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }
}

/* =====================================================================
 * Sel JSO & Live Audit — register Daftar Pekerjaan (v0.52.0)
 *
 * Dua kolom BEKU di kanan, bersama Aksi (§3.5) — setiap piksel di sini dibayar
 * kolom data yang terdorong keluar layar.
 *
 * Sel BERTUMPUK (lencana → keterangan → tombol), bukan berjejer: berjejer
 * satu sel 209–219 px dan di layar 1366 px tinggal 230 px untuk data;
 * bertumpuk ± 143 px (terukur, sesi 94). Tombolnya hanya untuk Bidang K3.
 * ================================================================== */
.dp-obs {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: .25rem;
    max-width: 8.75rem;
    white-space: normal;
}

.dp-obs__keadaan {
    display: flex;
    flex-wrap: wrap;
    gap: .25rem;
}

.dp-obs__ket {
    max-width: 100%;
    font-size: .6875rem;
    line-height: 1.3;
    color: var(--vz-secondary-color);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dp-obs__ket a { font-weight: 600; }

.dp-obs__btn {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    min-height: 1.875rem;
    padding: .1875rem .625rem;
    font-size: .75rem;
    font-weight: 600;
}

.dp-obs__btn i { font-size: 1rem; }
.dp-obs__btn[disabled] { pointer-events: none; }
.dp-obs__tunggu { display: inline-flex; cursor: help; }

/* Selama modal JSO / Live Audit terbuka, toast pindah ke TENGAH ATAS — di
   atas judul modal, yang tidak bisa diklik. Di posisi bawaannya (kanan bawah)
   ia menutupi tombol utama kaki modal ("Simpan & Finalkan") dan klik petugas
   mengenai toast, bukan tombolnya; di kanan atas ia menutupi tombol ×
   (keduanya terukur di peramban, v0.52.0). */
body.siper-obs-terbuka .siper-toasts {
    top: 1rem;
    bottom: auto;
    right: auto;
    left: 50%;
    transform: translateX(-50%);
}

/* =====================================================================
 * Spanduk keadaan (v0.55.0) — "apakah isi layar ini BERPENGARUH?"
 *
 * Teks warna BADAN di atas latar muda; nadanya dibawa garis kiri (pola
 * `.pd-bab__izin`). BUKAN `.alert-warning`/`.alert-info`: Velzon mewarnai
 * TEKS keduanya dengan `--vz-*-text-emphasis` — spanduk Nomor WA Pemantau
 * terukur 2,25 : 1 di mode terang (Aturan Permanen 349). Ikon ikut warna
 * teks: ia penanda, maknanya dibawa kalimatnya.
 * ================================================================== */
.siper-keadaan {
    display: flex;
    gap: .5rem;
    align-items: flex-start;
    margin-bottom: 1rem;
    padding: .6rem .85rem;
    border-radius: .25rem;
    border-left: 3px solid var(--vz-info);
    background: var(--vz-info-bg-subtle, #e7f3ff);
    color: var(--vz-body-color);
    font-size: .8125rem;
    line-height: 1.5;
}

.siper-keadaan--waspada {
    border-left-color: var(--vz-warning);
    background: var(--vz-warning-bg-subtle, #fff6e0);
}

.siper-keadaan__ikon { flex-shrink: 0; font-size: 1rem; line-height: 1.3; }
.siper-keadaan a { font-weight: 600; }

/* =====================================================================
 * Tabel entri Analisis Bahaya JSA (v0.60.0) — `Siper.AnalisisJsa`
 *
 * Bentuk lembar JSA di Excel (`resource/table-analisis-risiko-jsa.png`):
 * No · Tahapan Kerja · No · Potensi Bahaya · No · Dampak · No · Pengendalian
 * Bahaya · PIC. Satu baris = satu pengendalian.
 *
 * Sel LANJUTAN (dikosongkan = sama dengan baris di atasnya) digambar seperti
 * SEL GABUNGAN Excel: garis atasnya disembunyikan — `border-top-style:
 * hidden` MENANG atas garis apa pun pada model `border-collapse` (CSS 2.1
 * §17.6.2.1), termasuk garis baris Bootstrap — dan ruas isiannya tembus
 * pandang sampai disentuh / difokus.
 *
 * Tinggi sel mengikuti isinya tanpa JavaScript pengukur (pola "grow-wrap"):
 * `<textarea>` dan `::after` pembungkusnya menempati sel grid yang SAMA, dan
 * `::after` menyalin teksnya (`data-isi`) dengan metrik huruf yang identik.
 * Aman di pane tab yang tersembunyi dan ikut berubah saat lebar layar berubah.
 * ================================================================== */
.siper-analisis__petunjuk {
    display: flex;
    gap: .5rem;
    align-items: flex-start;
    padding: .75rem 1rem;
    border-bottom: 1px solid var(--vz-border-color);
    color: var(--vz-body-color);
    font-size: .78rem;
    line-height: 1.55;
}

.siper-analisis__petunjuk > i {
    flex-shrink: 0;
    font-size: 1rem;
    line-height: 1.25;
    color: var(--vz-warning);
}

.siper-analisis__pintasan { display: block; margin-top: .2rem; }

/* Ringkasan jumlah & catatan kaki — warna BADAN, bukan `.text-muted` (`--vz-secondary-color` terukur
   3,43 : 1 di mode terang; teks gaya baru wajib ≥ 4,5 : 1 — Aturan Permanen 349). */
.siper-analisis__ringkas { color: var(--vz-body-color); }
.siper-analisis__pintasan kbd { font-size: .68rem; padding: .05rem .3rem; }

/* `position: relative` WAJIB: label `.visually-hidden` (posisi absolut) di kepala
   kolom Aksi tidak punya leluhur berposisi, jadi lolos dari pemotongan wadah gulir
   dan membuat PANE ikut menggulir mendatar 586 px di ponsel 390 px (terukur;
   kerabat Aturan Permanen 332). Dengan ini wadah gulir menjadi blok penampungnya. */
.siper-analisis .siper-analisis__gulir { position: relative; }

.siper-analisis .siper-analisis__tabel {
    table-layout: fixed;
    width: 100%;
    min-width: 1080px;
    font-size: .8125rem;
}

.siper-analisis__w-no1 { width: 2.25rem; }
.siper-analisis__w-no2 { width: 2.75rem; }
.siper-analisis__w-no3 { width: 3.25rem; }
.siper-analisis__w-no4 { width: 3.75rem; }
.siper-analisis__w-kendali { width: 26%; }
.siper-analisis__w-pic { width: 12%; }
.siper-analisis__w-aksi { width: 4.5rem; }

.siper-analisis .siper-analisis__tabel > :not(caption) > * > * {
    padding: .25rem;
    border: 1px solid var(--vz-border-color);
    vertical-align: top;
}

.siper-analisis .siper-analisis__tabel > thead > tr > th {
    padding: .5rem .45rem;
    vertical-align: bottom;
    font-size: .75rem;
    font-weight: 600;
    white-space: normal;
}

.siper-analisis .siper-analisis__tabel .siper-analisis__no {
    padding: .5rem .2rem .25rem;
    text-align: center;
    white-space: nowrap;
    font-size: .75rem;
    font-variant-numeric: tabular-nums;
    color: var(--vz-body-color);
    background-color: var(--vz-tertiary-bg);
}

.siper-analisis .siper-analisis__tabel > thead > tr > th.siper-analisis__no { padding: .5rem .2rem; }

/* Pemisah tahapan — blok tahapan terbaca seperti di kertas. */
.siper-analisis .siper-analisis__tabel > tbody > tr.is-awal-tahapan > td { border-top-width: 2px; }

/* Sel gabungan: garis atasnya hilang, isiannya tembus pandang. */
.siper-analisis .siper-analisis__tabel > tbody > tr > td.is-lanjut { border-top-style: hidden; }

.siper-analisis .siper-analisis__tabel td.is-lanjut .form-control:not(:focus):not(.is-invalid) {
    background-color: transparent;
    border-color: transparent;
}

.siper-analisis .siper-analisis__tabel td.is-lanjut .form-control:not(:focus)::placeholder { color: transparent; }

.siper-analisis .siper-analisis__tabel td.is-lanjut:hover .form-control:not(:focus):not(:disabled) {
    border-style: dashed;
    border-color: var(--vz-border-color);
}

.siper-analisis .siper-analisis__tabel td.is-lanjut:hover .form-control:not(:focus)::placeholder {
    color: var(--vz-secondary-color);
}

/* PIC baris lanjutan = PIC tahapannya (sel gabungan) — bukan ruas abu-abu. */
.siper-analisis .siper-analisis__tabel td.is-lanjut .form-control:disabled { background-color: transparent; }

/* Baris yang sedang disunting. */
.siper-analisis .siper-analisis__tabel > tbody > tr:focus-within > td { background-color: var(--vz-primary-bg-subtle); }

/* Baris kosong di ujung — tempat mengetik baris berikutnya. */
.siper-analisis .siper-analisis__tabel > tbody > tr.is-ekor .form-control:not(:focus) { border-style: dashed; }
.siper-analisis .siper-analisis__tabel > tbody > tr.is-ekor [data-analisis-hapus] { visibility: hidden; }

/* Grow-wrap: textarea & salinannya di sel grid yang sama, metrik identik. */
.siper-analisis .siper-analisis__isi { display: grid; }

.siper-analisis .siper-analisis__isi > textarea,
.siper-analisis .siper-analisis__isi::after {
    grid-area: 1 / 1 / 2 / 2;
    min-height: 0;
    margin: 0;
    padding: .3125rem .45rem;
    border-width: var(--vz-border-width, 1px);
    border-style: solid;
    font-family: inherit;
    font-size: .8125rem;
    line-height: 1.45;
    letter-spacing: normal;
    white-space: pre-wrap;
    overflow-wrap: break-word;
    word-break: normal;
}

.siper-analisis .siper-analisis__isi::after {
    content: attr(data-isi) " ";
    visibility: hidden;
    border-color: transparent;
}

.siper-analisis .siper-analisis__isi > textarea {
    height: 100%;
    resize: none;
    overflow: hidden;
}

/* Galat di sel sempit: tanpa ikon Bootstrap (memakan ± 30 px dan menggeser
   lipatan baris salinannya) — garis merah + latar merah muda. */
.siper-analisis .siper-analisis__isi > textarea.is-invalid {
    padding-right: .45rem;
    background-image: none;
    background-color: var(--vz-danger-bg-subtle);
}

.siper-analisis .siper-analisis__aksi { text-align: center; white-space: nowrap; }

.siper-analisis .siper-analisis__tombol {
    padding: .2rem .3rem;
    line-height: 1;
    font-size: .95rem;
}

.siper-analisis__kaki {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem 1rem;
    padding: .75rem 1rem;
}

@keyframes siper-analisis-kedip {
    from { background-color: var(--vz-warning-bg-subtle); }
    to   { background-color: transparent; }
}

.siper-analisis .siper-analisis__tabel > tbody > tr.is-kedip > td { animation: siper-analisis-kedip 1.2s ease-out; }

@media (prefers-reduced-motion: reduce) {
    .siper-analisis .siper-analisis__tabel > tbody > tr.is-kedip > td { animation: none; }
}

/* Halaman detail JSA — tabel hanya-baca berbentuk lembar JSA (v0.60.0).
   Sel induk `rowspan` = sel gabungan Excel; kolom No menyusut ke isinya. */
.siper-analisis-baca { min-width: 720px; font-size: .8125rem; }

.siper-analisis-baca > :not(caption) > * > * { padding: .4rem .5rem; vertical-align: top; }

.siper-analisis-baca .siper-analisis-baca__no {
    width: 1%;
    white-space: nowrap;
    text-align: center;
    font-variant-numeric: tabular-nums;
    color: var(--vz-body-color);
    background-color: var(--vz-tertiary-bg);
}

.siper-analisis-baca > tbody > tr.siper-analisis-baca__awal > td { border-top-width: 2px; }

/* =====================================================================
 * Daftar periksa SAFETY PERMIT — YES · NO · N/A (v0.61.0)
 *
 * Revisi uji pengguna 5 Okt 2026: tombol NO ditambahkan pada kelima jenis
 * izin. Bahasa visualnya mengikuti tiga tombol observasi (`.obs__btn`, JSO &
 * Live Audit v0.46–0.51): tak terpilih = netral bergaris, TERPILIH = latar
 * penuh bernada dengan teks putih. Warna terpilih SAMA dengan token `.obs`
 * yang sudah terukur ≥ 4,5 : 1 — bukan `btn-outline-success`/`-secondary`
 * Velzon (putih di atas `#0ab39c` 2,64 : 1, Aturan Permanen 349).
 *
 * Tombolnya `label.btn` di belakang `input.btn-check`: warnanya diatur lewat
 * VARIABEL `--vz-btn-*` (pola varian `.btn-*` Bootstrap 5.3), sehingga aturan
 * hover/terpilih/fokus milik Bootstrap sendiri yang bekerja — tidak ada
 * kekhususan yang perlu dilawan.
 *
 * Layar sempit (< 768 px): baris tabel disusun ulang jadi grid — teks butir
 * di atas, tombol MEMBAGI RATA lebar baris di bawahnya, target sentuh ≥ 44 px.
 * Markup tabelnya tidak berubah (penghitung, buang butir, dan baris tambahan
 * dari endpoint tetap membaca `tr[data-cl-row]` yang sama).
 * ================================================================== */
.siper-periksa {
    --siper-jwb-yes: #067a6a;   /* = --obs-ya    — putih di atasnya 5,25 : 1 */
    --siper-jwb-no:  #b3261e;   /* = --obs-tidak — 6,54 : 1 */
    --siper-jwb-na:  #495057;   /* = --obs-na    — 8,18 : 1 */
}

/* Mode gelap: isi tombol TERPILIH sedikit lebih terang supaya terbedakan dari
   kartu gelap (≥ 3 : 1 — nada terang di atas hanya 1,89–2,94 : 1 di sana), tanpa
   menurunkan teks putihnya di bawah 4,5 : 1. Angka di komentar terukur. */
:root[data-bs-theme="dark"] .siper-periksa {
    --siper-jwb-yes: #07806f;   /* putih 4,85 : 1 · terhadap kartu gelap (#212529) 3,18 : 1 */
    --siper-jwb-no:  #d32f2f;   /* putih 4,98 : 1 · 3,10 : 1 */
    --siper-jwb-na:  #6c757d;   /* putih 4,69 : 1 · 3,29 : 1 */
}

.siper-periksa > tbody > tr > td.siper-periksa__no    { width: 44px; }
.siper-periksa > tbody > tr > td.siper-periksa__jawab { width: 252px; text-align: center; }
.siper-periksa > tbody > tr > td.siper-periksa__na    { width: 78px; }
.siper-periksa > tbody > tr > td.siper-periksa__aksi  { width: 40px; }

.siper-periksa__pilihan {
    display: inline-flex;
    flex-wrap: nowrap;
    gap: .375rem;
}

.siper-periksa__btn {
    --vz-btn-padding-x: .625rem;
    --vz-btn-padding-y: .25rem;
    --vz-btn-font-size: .75rem;
    --vz-btn-font-weight: 600;
    --vz-btn-line-height: 1.2;
    --vz-btn-color: var(--vz-body-color);
    --vz-btn-bg: var(--vz-secondary-bg);
    --vz-btn-border-color: var(--vz-border-color);
    --vz-btn-hover-color: var(--vz-body-color);
    --vz-btn-hover-bg: var(--vz-tertiary-bg);
    --vz-btn-hover-border-color: var(--vz-secondary-color);
    --vz-btn-active-color: #fff;

    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .25rem;
    min-width: 4.25rem;
    min-height: 32px;
    letter-spacing: .02em;
    box-shadow: none;
}

.siper-periksa__btn > i { font-size: .95rem; line-height: 1; }

.siper-periksa__btn--yes {
    --vz-btn-active-bg: var(--siper-jwb-yes);
    --vz-btn-active-border-color: var(--siper-jwb-yes);
    --vz-btn-focus-shadow-rgb: 6, 122, 106;
}

.siper-periksa__btn--no {
    --vz-btn-active-bg: var(--siper-jwb-no);
    --vz-btn-active-border-color: var(--siper-jwb-no);
    --vz-btn-focus-shadow-rgb: 179, 38, 30;
}

.siper-periksa__btn--na {
    --vz-btn-active-bg: var(--siper-jwb-na);
    --vz-btn-active-border-color: var(--siper-jwb-na);
    --vz-btn-focus-shadow-rgb: 73, 80, 87;
}

/* Fokus papan ketik terlihat jelas di kedua tema — cincin bayangan Bootstrap
   (alfa 0,5) nyaris hilang di atas kartu gelap. */
.btn-check:focus-visible + .siper-periksa__btn {
    outline: 2px solid var(--vz-link-color);
    outline-offset: 2px;
}

/* Arti tombol & rincian jawaban — warna BADAN, bukan `.text-muted` (3,43 : 1). */
.siper-periksa__legenda {
    display: flex;
    flex-wrap: wrap;
    gap: .25rem 1.25rem;
    padding: .5rem 1rem;
    border-bottom: 1px solid var(--vz-border-color);
    background: var(--vz-tertiary-bg);
    color: var(--vz-body-color);
    font-size: .75rem;
    line-height: 1.5;
}

/* Catatan Super Admin selama berkas `.sql` 20 belum diimpor. Bukan `alert-warning`:
   teks `--vz-warning-text-emphasis` di atas latar subtle hanya 2,25 : 1 — teks badan
   + garis kiri bernada (Aturan Permanen 252). */
.siper-periksa__catatan-admin {
    display: flex;
    gap: .5rem;
    align-items: flex-start;
    padding: .5rem 1rem;
    border-bottom: 1px solid var(--vz-border-color);
    border-left: 3px solid var(--vz-warning);
    background: var(--vz-warning-bg-subtle);
    color: var(--vz-body-color);
    font-size: .75rem;
    line-height: 1.5;
}

.siper-periksa__catatan-admin > i { flex-shrink: 0; font-size: 1rem; line-height: 1.2; }
/* `<code>` Velzon berwarna merah muda — di atas latar subtle oranye kontrasnya rendah; ikut warna teks. */
.siper-periksa__catatan-admin code { color: inherit; font-size: inherit; }

.siper-periksa__rincian {
    font-size: .75rem;
    font-weight: 400;
    color: var(--vz-body-color);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

@media (max-width: 767.98px) {
    table.siper-periksa,
    table.siper-periksa > tbody { display: block; width: 100%; }

    table.siper-periksa > tbody > tr[data-cl-row] {
        display: grid;
        grid-template-columns: 2.25rem minmax(0, 1fr) auto;
        border-bottom: 1px solid var(--vz-border-color);
    }

    table.siper-periksa > tbody > tr[data-cl-row] > td {
        display: block;
        width: auto;
        border-bottom-width: 0;
        padding: .375rem .5rem;
    }

    /* Satu kelas lebih khusus daripada aturan sel umum di atas — kalau tidak,
       `padding` umumnya menimpa padding per sel. */
    table.siper-periksa > tbody > tr[data-cl-row] > td.siper-periksa__no    { grid-column: 1; grid-row: 1 / span 2; padding-right: 0; }
    table.siper-periksa > tbody > tr[data-cl-row] > td.siper-periksa__teks  { grid-column: 2; grid-row: 1; padding-bottom: .125rem; }
    table.siper-periksa > tbody > tr[data-cl-row] > td.siper-periksa__aksi  { grid-column: 3; grid-row: 1; }
    table.siper-periksa > tbody > tr[data-cl-row] > td.siper-periksa__jawab { grid-column: 2 / 4; grid-row: 2; text-align: left; padding-bottom: .625rem; }
    table.siper-periksa > tbody > tr[data-cl-row] > td.siper-periksa__na    { grid-column: 3; grid-row: 2; align-self: center; }
    table.siper-periksa > tbody > tr[data-cl-row] > td.siper-periksa__na:empty { display: none; }

    /* Butir ukur: ruas angka di kolom teks, kotak N/A di sebelahnya. */
    table.siper-periksa > tbody > tr[data-cl-ukur="1"] > td.siper-periksa__jawab { grid-column: 2; }

    .siper-periksa__pilihan { display: flex; width: 100%; }
    .siper-periksa__btn { flex: 1 1 0; min-height: 44px; --vz-btn-font-size: .8125rem; }
}
