/* ==========================================================================
   Custom styles untuk SPARTAN Gunungkidul
   ========================================================================== */

/* --------------------------------------------------------------------------
   .text-marquee
   Teks panjang dipotong jadi ~10 karakter + "…". Saat di-hover, teks lengkapnya
   berjalan (marquee) sampai ujung, lalu balik lagi.

   Markup (wajib ada 1 elemen pembungkus di dalam, karena teks perlu digeser
   di dalam kotak yang memotongnya, jadi tidak bisa satu elemen saja):

     <span class="text-marquee"><span>{{ $teks }}</span></span>

   Atau pakai komponen Blade-nya:

     <x-truncate-marquee :text="$event['nama_organisasi']" />
     <x-truncate-marquee :text="$item->nama" :chars="20" />

   Atur lewat CSS variable, boleh inline per elemen:

     <span class="text-marquee" style="--marquee-chars: 20; --marquee-speed: 6s">

   Catatan: 1ch = lebar karakter "0" pada font yang dipakai. Di font
   proporsional seperti Figtree/Public Sans, 10ch kira-kira setara 10-14 huruf
   kecil atau 7-9 huruf kapital, jadi batasnya perkiraan lebar dan bukan hitungan
   karakter yang persis.
   -------------------------------------------------------------------------- */

.text-marquee {
    /* lebar jendela yang terlihat, dalam satuan karakter */
    --marquee-chars: 10;
    /* durasi sekali jalan dari awal ke akhir teks */
    --marquee-speed: 4s;
    /* jeda setelah kursor masuk, sebelum teks mulai jalan */
    --marquee-delay: 0.25s;

    display: inline-block;
    max-width: calc(var(--marquee-chars) * 1ch);
    overflow: hidden;
    /* inline-block ber-overflow memakai bottom margin edge sebagai baseline,
       jadi disejajarkan manual supaya tidak melayang dari teks di sekitarnya */
    vertical-align: bottom;
}

.text-marquee > * {
    display: block;
    max-width: 100%;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* Saat hover: buang "…", lebarkan anak ke lebar teks aslinya, lalu jalankan
   animasi. Pembungkus luarnya tetap memotong, jadi yang terlihat hanya jendela
   selebar --marquee-chars. */
.text-marquee:hover > *,
.text-marquee:focus-within > * {
    max-width: none;
    width: max-content;
    text-overflow: clip;
    animation: text-marquee-scroll var(--marquee-speed) var(--marquee-delay)
        linear infinite alternate;
}

@keyframes text-marquee-scroll {
    /* diam sebentar di awal supaya sempat terbaca */
    0%,
    12% {
        transform: translateX(0);
    }
    /* geser sejauh (lebar teks - lebar jendela), lalu diam sebentar di ujung.
       min() menjaga teks pendek tetap diam: kalau teksnya lebih sempit dari
       jendela, hasil hitungannya positif dan dipaksa jadi 0. */
    88%,
    100% {
        transform: translateX(
            min(0px, calc(var(--marquee-chars) * 1ch - 100%))
        );
    }
}

/* Varian lebar siap pakai */
.text-marquee-sm {
    --marquee-chars: 6;
}
.text-marquee-lg {
    --marquee-chars: 20;
}
.text-marquee-xl {
    --marquee-chars: 32;
}

/* Varian block: dipakai kalau elemen harus mengikuti lebar kolom/kartu induknya
   (misal di dalam <td> atau card), bukan selebar --marquee-chars. */
.text-marquee-block {
    display: block;
    width: 100%;
    max-width: 100%;
    container-type: inline-size;
}

.text-marquee-block:hover > *,
.text-marquee-block:focus-within > * {
    animation-name: text-marquee-scroll-fluid;
}

@keyframes text-marquee-scroll-fluid {
    0%,
    12% {
        transform: translateX(0);
    }
    88%,
    100% {
        /* 100cqw = lebar pembungkus, jadi jendelanya ikut lebar kolom */
        transform: translateX(min(0px, calc(100cqw - 100%)));
    }
}

/* Hormati pengguna yang mematikan animasi di OS-nya: teks tetap tampil penuh
   saat hover, hanya tidak berjalan. */
@media (prefers-reduced-motion: reduce) {
    .text-marquee:hover > *,
    .text-marquee:focus-within > * {
        animation: none;
    }
}

/* --------------------------------------------------------------------------
   Offcanvas "Detail Agenda"
   Panel baca-saja untuk detail peminjaman ruang yang dibuka dari kalender.
   Dibangun di atas Bootstrap 5 / Vuexy yang sudah dipakai project ini.
   -------------------------------------------------------------------------- */

.agenda-detail {
    width: 460px;
    /* Tanpa ini, lebar tetap 460px akan melebihi layar HP dan memicu
       scroll horizontal. */
    max-width: 100%;
}

.agenda-detail .offcanvas-header {
    align-items: flex-start;
    padding-bottom: 0.75rem;
    border-bottom: 1px solid rgba(67, 89, 113, 0.12);
}

.agenda-detail__eyebrow {
    display: block;
    font-size: 0.75rem;
    font-weight: 500;
    line-height: 1.2;
    color: #a1acb8;
    margin-bottom: 0.25rem;
}

/* Nama acara adalah judul panel: satu-satunya teks berukuran besar. */
.agenda-detail__title {
    font-size: 1.125rem;
    font-weight: 600;
    line-height: 1.35;
    color: #384551;
    margin: 0;
}

.agenda-detail .offcanvas-body {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    padding-top: 1.25rem;
}

/* Blok utama: kapan dan di mana. Dua fakta yang paling dicari pengunjung,
   jadi diberi latar dan ikon supaya terbaca lebih dulu dari sisanya. */
.agenda-detail__primary {
    display: grid;
    gap: 1rem;
    padding: 1rem;
    border-radius: 0.5rem;
    background: rgba(105, 108, 255, 0.06);
}

.agenda-detail__fact {
    display: grid;
    grid-template-columns: 1.75rem 1fr;
    align-items: start;
    gap: 0.75rem;
}

.agenda-detail__fact i {
    font-size: 1.25rem;
    line-height: 1.4;
    color: #696cff;
}

.agenda-detail__fact-label {
    display: block;
    font-size: 0.75rem;
    color: #8592a3;
    margin-bottom: 0.125rem;
}

.agenda-detail__fact-value {
    display: block;
    font-size: 0.9375rem;
    font-weight: 500;
    line-height: 1.45;
    color: #384551;
    overflow-wrap: anywhere;
}

.agenda-detail__fact-value small {
    display: block;
    font-size: 0.8125rem;
    font-weight: 400;
    color: #697a8d;
    margin-top: 0.125rem;
}

/* Blok sekunder: siapa yang meminjam. Label kecil, nilai biasa, tanpa kotak. */
.agenda-detail__meta {
    display: grid;
    gap: 1rem;
    margin: 0;
}

.agenda-detail__meta dt {
    font-size: 0.75rem;
    font-weight: 400;
    color: #8592a3;
    margin-bottom: 0.125rem;
}

.agenda-detail__meta dd {
    font-size: 0.9375rem;
    color: #384551;
    margin: 0;
    overflow-wrap: anywhere;
}

/* Nilai yang kosong tampil sebagai teks redup, bukan placeholder yang
   terlihat seperti kolom isian. */
.agenda-detail__empty {
    color: #a1acb8;
    font-style: italic;
}

.agenda-detail__footer {
    margin-top: auto;
    padding-top: 1.25rem;
    border-top: 1px solid rgba(67, 89, 113, 0.12);
}

@media (max-width: 575.98px) {
    .agenda-detail__footer .btn {
        width: 100%;
    }
}

/* Vuexy .btn-label-secondary memberi teks #a8aaae di atas #f1f1f2 = kontras
   2.06:1, jauh di bawah ambang WCAG AA 4.5:1. Tombol tutup diwarnai ulang
   memakai warna teks bawaan Vuexy (#566a7f) yang mencapai 5.6:1. */
.agenda-detail__footer .btn-tutup {
    background-color: transparent;
    border: 1px solid rgba(67, 89, 113, 0.25);
    color: #566a7f;
}

.agenda-detail__footer .btn-tutup:hover,
.agenda-detail__footer .btn-tutup:focus-visible {
    background-color: rgba(67, 89, 113, 0.06);
    border-color: rgba(67, 89, 113, 0.4);
    color: #384551;
}

/* Umpan balik sentuh: tombol turun 1px saat ditekan */
.agenda-detail__footer .btn-tutup:active {
    transform: translateY(1px);
}

/* --- Collapsible Schedule Card Landing Event Timeline --- */
.schedule-card {
    background-color: #ffffff;
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 24px;
    max-width: 800px;
    margin: 0 auto 1rem auto;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
}

/* Header Area (Always Visible) */
.schedule-card-header {
    display: flex;
    flex-direction: column;
    gap: 12px;
    cursor: pointer;
    background-color: transparent;
    border: none;
    padding: 0;
    text-decoration: none;
}

/* Row 1: Time, Add to Calendar, Chevron */
.schedule-header-row-1 {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.header-left-actions {
    display: flex;
    align-items: center;
    gap: 12px;
}

.schedule-time {
    font-size: 12px;
    font-weight: 500;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.add-calendar-link {
    font-size: 12px;
    font-weight: 600;
    color: var(--secondary);
    display: flex;
    align-items: center;
    gap: 4px;
    text-decoration: none;
}

.schedule-chevron {
    color: var(--text-secondary);
    font-size: 14px;
    font-weight: 300;
    transition: transform 0.3s ease;
}

/* Chevron Animation */
.schedule-card-header:not(.collapsed) .schedule-chevron {
    transform: rotate(180deg);
}

/* Row 2: Category Badge */
.schedule-badge {
    background-color: var(--badge-bg);
    color: var(--secondary);
    font-size: 12px;
    font-weight: 600;
    padding: 4px 12px;
    border-radius: 9999px;
    align-self: flex-start;
    display: inline-block;
}

/* Row 3: Session Title */
.schedule-title {
    font-size: 16px;
    font-weight: 700;
    color: var(--text-primary);
    margin: 0;
    line-height: 1.3;
}

/* Row 4: Speakers */
.schedule-speakers {
    font-size: 14px;
    color: var(--text-primary);
}

.speaker-link {
    color: var(--primary);
    text-decoration: none;
    font-weight: 400;
    transition: color 0.2s ease;
}

.speaker-link:hover {
    color: var(--text-primary);
}

/* Body Area (Hidden by default) */
.schedule-card-body {
    padding-top: 16px;
    margin-top: 16px;
    border-top: 1px dashed var(--border);
}

.schedule-description {
    font-size: 12px;
    color: var(--text-secondary);
    line-height: 1.6;
    margin-bottom: 16px;
}

.btn-register {
    background-color: var(--btn-bg);
    color: var(--btn-text);
    border: none;
    padding: 8px 16px;
    border-radius: 6px;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    transition: background-color 0.2s ease;
}

.btn-register:hover {
    background-color: #bbf7d0;
}

/* Prevent link clicks inside header from triggering the collapse */
.stop-propagation {
    position: relative;
    z-index: 2;
}

/* Custom CSS untuk mempercantik Card */
.schedule-card-modern {
    border-radius: 12px;
    overflow: hidden;
    border: 1px solid #f4f4f4;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.04);
    background-color: #ffffff;
    transition:
        transform 0.2s ease,
        box-shadow 0.2s ease;
}

.schedule-card-modern:hover {
    transform: translateY(-3px);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.08);
}

/* Styling Banner */
.schedule-banner {
    width: 100%;
    height: 160px; /* Sesuaikan tinggi banner */
    object-fit: cover;
    border-bottom: 1px solid #f0f0f0;
}

/* Typography */
.schedule-title {
    font-size: 1.2rem;
    font-weight: 700;
    color: #5a5a66;
    line-height: 1.4;
}

.schedule-meta-text {
    font-size: 0.9rem;
    color: #71717a;
}

.schedule-meta-text a {
    color: #71717a;
    text-decoration: none;
    transition: color 0.2s ease;
}

.schedule-meta-text a:hover {
    color: #8b2df4; /* Warna ungu saat di-hover */
}

/* Custom Button menyesuaikan referensi gambar */
.btn-purple {
    background-color: #8b2df4;
    border-color: #8b2df4;
    color: #ffffff;
    font-weight: 500;
    border-radius: 6px;
}

.btn-purple:hover {
    background-color: #7420d4;
    border-color: #7420d4;
    color: #ffffff;
}

/* --------------------------------------------------------------------------
   Agenda hari ini (.agenda-grid / .agenda-card) dan agenda akan datang
   (.agenda-next) di landing page.

   Memakai token warna Vuexy yang sudah ada (primary #7367f0, judul #5d596c,
   teks sekunder #6f6b7d, garis #dbdade) supaya tidak muncul palet kedua di
   halaman yang sama.

   Aturan sudut yang dipakai konsisten di dua blok ini:
     kartu      12px
     chip meta   6px

   Gerak sengaja ditahan di level hover/press saja karena ini halaman layanan
   publik: yang dikejar keterbacaan, bukan pertunjukan. Semua transisi mati di
   bawah prefers-reduced-motion (blok paling bawah file ini).
   -------------------------------------------------------------------------- */

/* ---------- Judul section ---------- */

.agenda-head__title {
    margin-bottom: 0.5rem;
    color: #5d596c;
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -0.01em;
}

.agenda-head__meta {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin: 0;
    padding: 0.3rem 0.75rem;
    border-radius: 6px;
    background-color: rgba(115, 103, 240, 0.1);
    color: #7367f0;
    font-size: 0.8125rem;
    font-weight: 600;
}

/* ---------- Kartu agenda hari ini ---------- */

/* Daftar kartu memakai grid native, bukan kolom Bootstrap. Jumlah kolomnya
   ditentukan lebar yang tersedia, jadi tidak ada breakpoint yang perlu ditebak
   dan tidak perlu div pembungkus per kartu. */
.agenda-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
    gap: 1rem;
}

.agenda-card,
.ruang-card,
.kontak-card,
.survey-card {
    /* kartu jadi acuan ukuran bagi isinya sendiri, dipakai di bagian bawah
       blok ini untuk merapatkan isi saat kartunya sempit */
    container-type: inline-size;
    border: 1px solid #ebe9f1;
    border-radius: 12px;
    background-color: #fff;
    overflow: hidden;
    transition:
        transform 0.2s ease,
        box-shadow 0.2s ease,
        border-color 0.2s ease;
}

/* Seluruh kartu satu target klik, jadi tidak ada tautan mati di dalamnya */
.agenda-card__link {
    display: flex;
    flex-direction: column;
    height: 100%;
    color: inherit;
    text-decoration: none;
}

.agenda-card__link:focus-visible {
    outline: 2px solid #7367f0;
    outline-offset: 2px;
}

/* Foto ruang dipasang sebagai background, bukan <img>, supaya saat filenya
   tidak ada yang muncul tint ini dan bukan ikon gambar rusak. Bandnya sengaja
   pendek: foto di sini gunanya mengenali ruang, bukan jadi tokoh utama, dan
   kartu yang pendek membuat lebih banyak agenda terlihat sekali pandang. */
.agenda-card__media {
    aspect-ratio: 5 / 2;
    background-color: #e9e7fb;
    background-position: center;
    background-size: cover;
    box-shadow: inset 0 0 0 1px rgba(115, 103, 240, 0.08);
    transition: transform 0.3s ease;
}

.agenda-card__body {
    display: flex;
    flex-grow: 1;
    flex-direction: column;
    padding: 1.125rem;
}

/* Urutan baca yang dituju: KAPAN -> ACARA APA -> DI MANA -> SIAPA */
.agenda-card__time {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin-bottom: 0.4rem;
    color: #7367f0;
    font-size: 0.875rem;
    font-weight: 700;
    /* angka jam sama lebar, jadi waktu antar kartu sejajar dan enak dipindai */
    font-variant-numeric: tabular-nums;
}

.agenda-card__title {
    margin-bottom: 0.75rem;
    color: #5d596c;
    font-size: 1.0625rem;
    font-weight: 700;
    line-height: 1.4;
    /* mencegah satu kata tertinggal sendirian di baris terakhir */
    text-wrap: pretty;
    /* dipotong 2 baris supaya tinggi kartu rata dalam satu baris grid */
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
}

/* Baris meta (ruang + peminjam). Sengaja dipakai bersama oleh kartu hari ini
   dan daftar akan datang supaya dua blok itu terbaca sebagai satu keluarga. */
.agenda-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin: 0;
}

.agenda-tag {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    max-width: 100%;
    padding: 0.2rem 0.55rem;
    border-radius: 6px;
    background-color: #f4f3f7;
    color: #6f6b7d;
    font-size: 0.75rem;
    font-weight: 500;
}

.agenda-tag span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Di sistem peminjaman ruang, "ruang mana" adalah info kunci. Chip-nya diberi
   bobot lebih supaya tidak seberat chip peminjam yang sifatnya pelengkap. */
.agenda-tag--ruang {
    background-color: rgba(115, 103, 240, 0.1);
    color: #7367f0;
    font-weight: 600;
}

/* Garis tipis memisahkan zona aksi dari isi, jadi lebih jelas kartunya bisa
   diklik. margin-top auto menahannya di dasar kartu supaya kartu bersebelahan
   tetap sejajar walau panjang judulnya beda. */
.agenda-card__cta {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin-top: auto;
    padding-top: 0.75rem;
    border-top: 1px solid #f1f0f4;
    color: #7367f0;
    font-size: 0.8125rem;
    font-weight: 600;
}

.agenda-card__cta i {
    transition: transform 0.2s ease;
}

/* Efek angkat hanya untuk perangkat yang benar-benar punya hover. Di layar
   sentuh efek begini menempel setelah disentuh dan malah membingungkan. */
@media (hover: hover) {
    .agenda-card:hover,
    .ruang-card:hover,
    .kontak-card:hover {
        transform: translateY(-2px);
        border-color: #d5d0fb;
        box-shadow: 0 8px 24px rgba(115, 103, 240, 0.12);
    }

    .agenda-card:hover .agenda-card__media {
        transform: scale(1.03);
    }

    .agenda-card:hover .agenda-card__cta i {
        transform: translateX(3px);
    }
}

/* Umpan balik saat ditekan, supaya kartu terasa seperti tombol sungguhan */
.agenda-card__link:active {
    transform: scale(0.99);
}

/* Kartu yang benar-benar sempit (ponsel kecil): rapatkan padding dan turunkan
   ukuran judul sedikit supaya isinya tidak terasa sesak. */
@container (max-width: 19rem) {
    .agenda-card__body {
        padding: 0.875rem;
    }

    .agenda-card__title {
        font-size: 1rem;
    }
}

/* ---------- Daftar agenda akan datang ---------- */

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

.agenda-next__item {
    position: relative;
    padding: 0.875rem 0 0.875rem 1.125rem;
}

/* Rel kiri per item memberi kesan runtutan waktu tanpa perlu titik status */
.agenda-next__item::before {
    content: "";
    position: absolute;
    top: 0.5rem;
    bottom: 0.5rem;
    left: 0;
    width: 3px;
    border-radius: 3px;
    background-color: #ebe9f1;
    transition: background-color 0.2s ease;
}

.agenda-next__item:hover::before {
    background-color: #7367f0;
}

.agenda-next__time {
    margin-bottom: 0.35rem;
    color: #28c76f;
    font-size: 0.75rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.agenda-next__title {
    margin-bottom: 0.35rem;
    font-size: 0.9375rem;
    font-weight: 700;
    line-height: 1.45;
    text-wrap: pretty;
}

.agenda-next__title a {
    color: #5d596c;
    text-decoration: none;
}

.agenda-next__title a:hover,
.agenda-next__title a:focus-visible {
    color: #7367f0;
}

.agenda-next__org {
    margin-bottom: 0.5rem;
    color: #6f6b7d;
    font-size: 0.8125rem;
}

/* ---------- Keadaan kosong ---------- */

.agenda-empty {
    padding: 2.5rem 1.25rem;
    border: 1px dashed #dbdade;
    border-radius: 12px;
    background-color: #fcfcfd;
    text-align: center;
}

.agenda-empty i {
    display: block;
    margin-bottom: 0.6rem;
    color: #b7b5be;
    font-size: 1.75rem;
}

.agenda-empty p {
    margin: 0;
    color: #6f6b7d;
    font-size: 0.875rem;
}

@media (prefers-reduced-motion: reduce) {
    .agenda-card,
    .ruang-card,
    .kontak-card,
    .agenda-card__media,
    .agenda-card__cta i,
    .agenda-next__item::before {
        transition: none;
    }

    .agenda-card:hover,
    .ruang-card:hover,
    .kontak-card:hover,
    .agenda-card:hover .agenda-card__media,
    .agenda-card:hover .agenda-card__cta i,
    .agenda-card__link:active {
        transform: none;
    }
}

/* --------------------------------------------------------------------------
   Timeline agenda (halaman /timelines)

   Sengaja dibangun di atas keluarga .agenda-* yang sama dengan landing page
   (kartu 12px, chip 6px, token #7367f0 / #5d596c / #6f6b7d / #dbdade) supaya
   dua halaman ini terbaca sebagai satu produk, bukan dua tema yang kebetulan
   bertetangga.

   Bentuk kartunya sama persis dengan yang di landing page (foto di atas, isi di
   bawah). Yang membedakan halaman ini cuma pembungkusnya: kartunya dikelompokkan
   per tanggal dan digantung pada rel waktu vertikal, karena di sini yang dicari
   "kapan" lebih dulu, baru "acara apa".

   Halaman ini menggantikan .timeline bawaan Vuexy yang dipakai versi lama:
   timeline zig-zag itu memaksa mata bolak-balik kiri-kanan dan tanggalnya
   diulang di tiap kartu walau banyak agenda jatuh di hari yang sama.
   -------------------------------------------------------------------------- */

/* ---------- Baris filter ruang ---------- */

.agenda-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.625rem;
    padding: 0.875rem 1rem;
    border: 1px solid #ebe9f1;
    border-radius: 12px;
    background-color: #fff;
}

.agenda-toolbar__label {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin: 0;
    color: #5d596c;
    font-size: 0.8125rem;
    font-weight: 600;
}

.agenda-toolbar__label i {
    color: #7367f0;
}

/* Melar mengisi sisa baris, tapi berhenti sebelum jadi selebar layar: daftar
   nama ruang itu pendek, select sepanjang 40rem cuma bikin jarak baca jauh. */
.agenda-toolbar__select {
    flex: 1 1 14rem;
    width: auto;
    min-width: 12rem;
    max-width: 22rem;
}

/* Didorong ke kanan supaya "buang filter" tidak tertukar dengan "pasang
   filter" yang ada di kiri. Hanya muncul kalau filternya memang aktif. */
.agenda-toolbar__reset {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    margin-left: auto;
    color: #6f6b7d;
    font-size: 0.8125rem;
    font-weight: 600;
    text-decoration: none;
}

.agenda-toolbar__reset:hover,
.agenda-toolbar__reset:focus-visible {
    color: #7367f0;
}

/* ---------- Rel waktu ---------- */

.agenda-timeline {
    /* jarak garis rel dari tepi kiri blok */
    --tl-rail-x: 0.5rem;
    /* jarak isi ke tepi kiri blok; selisihnya dengan --tl-rail-x jadi ruang
       gerak titik penanda tanggal */
    --tl-gap: 2rem;
    /* tinggi navbar yang menggantung di atas, dipakai judul tanggal yang
       menempel saat digulir */
    --tl-sticky-top: 5.5rem;

    position: relative;
    padding-left: var(--tl-gap);
}

.agenda-timeline::before {
    content: "";
    position: absolute;
    top: 0.75rem;
    bottom: 0.75rem;
    left: var(--tl-rail-x);
    width: 2px;
    margin-left: -1px;
    border-radius: 2px;
    /* nada menengah, bukan #ebe9f1 seperti garis lain di file ini: rel ini
       lewat di atas gradasi latar hero yang warnanya sudah lavender muda,
       jadi abu-abu paling terang ikut hilang di sana */
    background-color: #cfcbe0;
}

.agenda-timeline__group + .agenda-timeline__group {
    margin-top: 1.75rem;
}

/* Judul tanggal menempel di bawah navbar selama grupnya masih terlihat. Di
   daftar yang panjang ini yang menjaga konteks: kartu yang sedang dibaca
   selalu punya tanggalnya sendiri di layar, tanpa harus diulang per kartu. */
.agenda-timeline__date {
    position: sticky;
    top: var(--tl-sticky-top);
    z-index: 2;
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0 0 0.875rem;
    padding: 0.375rem 0.875rem;
    border: 1px solid #ebe9f1;
    border-radius: 999px;
    /* buram, bukan transparan: kartu di bawahnya lewat persis di belakang ini */
    background-color: #fff;
    box-shadow: 0 2px 8px rgba(93, 89, 108, 0.06);
    color: #5d596c;
    font-size: 0.875rem;
    font-weight: 700;
}

/* Titik penanda di garis rel. Ditempel ke judul tanggal (bukan ke grupnya)
   supaya ikut turun saat judulnya menempel — titiknya jadi penunjuk posisi
   baca, bukan sekadar hiasan di kepala grup. */
.agenda-timeline__date::before {
    content: "";
    position: absolute;
    top: 50%;
    left: calc(var(--tl-rail-x) - var(--tl-gap));
    width: 0.875rem;
    height: 0.875rem;
    margin-top: -0.4375rem;
    margin-left: -0.4375rem;
    border: 2px solid #fff;
    border-radius: 50%;
    background-color: #b7b5be;
}

.agenda-timeline__date--today {
    border-color: #d5d0fb;
    color: #7367f0;
}

.agenda-timeline__date--today::before {
    background-color: #7367f0;
    box-shadow: 0 0 0 4px rgba(115, 103, 240, 0.15);
}

.agenda-timeline__date-rel {
    padding: 0.1rem 0.45rem;
    border-radius: 6px;
    background-color: rgba(115, 103, 240, 0.1);
    color: #7367f0;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

.agenda-timeline__date-count {
    color: #a5a3ae;
    font-size: 0.75rem;
    font-weight: 500;
}

/* Jumlah kolom dipatok per breakpoint (bukan auto-fill seperti .agenda-grid di
   landing) supaya satu hari selalu tersaji dengan jumlah kartu per baris yang
   sama: 1 di ponsel, 2 mulai md, 3 mulai lg. Ambangnya ikut breakpoint
   Bootstrap yang dipakai template ini. */
.agenda-timeline__items {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
}

@media (min-width: 768px) {
    .agenda-timeline__items {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (min-width: 992px) {
    .agenda-timeline__items {
        grid-template-columns: repeat(3, 1fr);
    }
}

/* ---------- Penyesuaian kartu di timeline ---------- */

/* Baris waktu di sini bisa berisi pil "Berlangsung" yang tidak ada di landing,
   jadi khusus di halaman ini dibolehkan turun baris saat kartunya sempit. */
.agenda-timeline .agenda-card__time {
    flex-wrap: wrap;
}

/* Ruang tanpa foto: pita-nya tetap ada supaya tinggi kartu dalam satu baris
   grid tetap sama, tapi diisi ikon supaya terbaca "belum ada foto" dan bukan
   blok kosong yang terlihat seperti gambar gagal dimuat. */
.agenda-card__media--kosong {
    display: grid;
    place-items: center;
    color: #b3aef0;
    font-size: 1.75rem;
}

.agenda-card__org {
    margin-bottom: 0.6rem;
    color: #6f6b7d;
    font-size: 0.8125rem;
}

/* Agenda yang sedang berlangsung diberi tepi hijau — status "sekarang" adalah
   satu-satunya info di halaman ini yang basi kalau telat dibaca. */
.agenda-card--live {
    border-color: rgba(40, 199, 111, 0.4);
}

.agenda-card--live .agenda-card__time {
    color: #28c76f;
}

.agenda-status {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.1rem 0.5rem;
    border-radius: 6px;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

.agenda-status--live {
    background-color: rgba(40, 199, 111, 0.12);
    color: #28c76f;
}

.agenda-status--live::before {
    content: "";
    width: 0.4rem;
    height: 0.4rem;
    border-radius: 50%;
    background-color: currentColor;
    animation: agenda-status-pulse 1.6s ease-in-out infinite;
}

@keyframes agenda-status-pulse {
    0%,
    100% {
        opacity: 1;
        transform: scale(1);
    }
    50% {
        opacity: 0.35;
        transform: scale(0.7);
    }
}

/* Penanda acara yang melewati tengah malam, supaya tidak salah baca sebagai
   acara sehari — kartunya digantung di tanggal mulai. */
.agenda-tag--multiday {
    background-color: rgba(255, 159, 67, 0.12);
    color: #ff9f43;
    font-weight: 600;
}

/* ---------- Layar kecil ---------- */

@media (max-width: 575.98px) {
    .agenda-timeline {
        --tl-gap: 1.25rem;
        --tl-rail-x: 0.375rem;
        --tl-sticky-top: 4.75rem;
    }

    .agenda-timeline__date {
        font-size: 0.8125rem;
    }

    .agenda-toolbar__reset {
        margin-left: 0;
    }
}

@media (prefers-reduced-motion: reduce) {
    .agenda-status--live::before {
        animation: none;
    }
}

/* --------------------------------------------------------------------------
   Agenda bulanan (halaman /agenda-bulanan)

   Turunan dari timeline agenda: daftar rincinya memakai .agenda-timeline dan
   .agenda-card yang sama persis, jadi yang baru di sini cuma pembungkusnya —
   saklar tampilan, baris navigasi bulan, dan kalender tujuh kolomnya.

   Token warna, sudut kartu (12px), dan sudut chip (6px) mengikuti blok agenda
   di atas supaya tidak muncul palet kedua di produk yang sama.
   -------------------------------------------------------------------------- */

/* Saklar .agenda-tampilan sudah tidak ada: perannya diambil tab Tabel/Bulanan
   di halaman Pinjaman, dan halaman publik Agenda Bulanan sendiri dihapus. */

/* ---------- Baris navigasi & filter bulan ---------- */

/* Selubungnya sengaja sama dengan .agenda-toolbar di halaman timeline. */
.agenda-bulan-nav {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.625rem;
    padding: 0.875rem 1rem;
    border: 1px solid #ebe9f1;
    border-radius: 12px;
    background-color: #fff;
}

/* Panah dan dua select bulan/tahun dikunci jadi satu kelompok rapat: ketiganya
   mengubah hal yang sama (bulan mana yang dilihat), jadi tidak boleh terpisah
   oleh jarak yang sama besar dengan jarak ke filter ruang. */
.agenda-bulan-nav__periode {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.375rem;
}

/* Panah bulan adalah <a>, bukan <button>: hasilnya alamat penuh yang bisa
   dibagikan dan dibuka di tab baru, dan tetap jalan walau form belum disentuh.
   Tingginya dipatok setinggi .form-select bawaan Bootstrap supaya satu baris
   ini tidak terlihat bergerigi. */
.agenda-bulan-nav__panah {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    min-height: 38px;
    padding: 0 0.75rem;
    border: 1px solid #dbdade;
    border-radius: 8px;
    color: #5d596c;
    font-size: 0.8125rem;
    font-weight: 600;
    white-space: nowrap;
    text-decoration: none;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.agenda-bulan-nav__panah:hover,
.agenda-bulan-nav__panah:focus-visible {
    border-color: #7367f0;
    background-color: rgba(115, 103, 240, 0.08);
    color: #7367f0;
}

.agenda-bulan-nav__select {
    width: auto;
    min-width: 8.5rem;
}

.agenda-bulan-nav__select--tahun {
    min-width: 6rem;
}

.agenda-bulan-nav__ruang {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    gap: 0.5rem;
    /* Tidak dibuat melar: kalau grup ini mengambil sisa baris, tombol "Terapkan"
       terlempar ke tepi kanan dan berjarak jauh dari kotak yang diterapkannya. */
    flex: 0 1 auto;
    min-width: 0;
}

.agenda-bulan-nav__ruang .agenda-toolbar__label {
    white-space: nowrap;
}

.agenda-bulan-nav__ruang .agenda-toolbar__select {
    min-width: 0;
}

/* ---------- Kalender bulan ---------- */

/* Tujuh kolom baru masuk akal kalau tiap kolom masih cukup lebar untuk memuat
   nama acara. Di bawah 768px satu kolom tinggal sekitar 45px — yang tersisa
   cuma kotak-kotak warna tanpa keterangan. Di lebar itu kalendernya
   disembunyikan dan yang dibaca daftar rinci di bawahnya, isinya sama. */
.agenda-bulan {
    display: none;
    margin-bottom: 2rem;
    border: 1px solid #ebe9f1;
    border-radius: 12px;
    background-color: #fff;
    overflow: hidden;
}

@media (min-width: 768px) {
    .agenda-bulan {
        display: block;
    }
}

.agenda-bulan__kepala,
.agenda-bulan__pekan {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
}

.agenda-bulan__kepala {
    border-bottom: 1px solid #ebe9f1;
    background-color: #f8f7fa;
}

.agenda-bulan__nama-hari {
    padding: 0.5rem 0.625rem;
    color: #6f6b7d;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: uppercase;
}

/* Garis bawah putus-putus bawaan <abbr> menabrak garis grid dan terbaca seperti
   cacat render; keterangan hari panjangnya tetap ada lewat title. */
.agenda-bulan__nama-hari abbr {
    border: 0;
    text-decoration: none;
    cursor: help;
}

/* Tinggi minimum dipasang supaya baris pekan yang kosong tidak menciut jadi
   segaris — bentuk kalender hilang kalau tiap baris setinggi isinya sendiri. */
.agenda-bulan__kotak {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    min-height: 7.5rem;
    padding: 0.5rem;
    border-right: 1px solid #f1f0f5;
    border-bottom: 1px solid #f1f0f5;
}

.agenda-bulan__kotak:last-child {
    border-right: 0;
}

/* Baris terakhir sudah dibatasi border kotak pembungkusnya; tanpa ini garisnya
   jadi dua tumpuk. */
.agenda-bulan__pekan:last-child .agenda-bulan__kotak {
    border-bottom: 0;
}

.agenda-bulan__kotak--pekanan {
    background-color: #fcfcfd;
}

/* Tanggal dari bulan tetangga tetap digambar supaya tiap pekan utuh tujuh
   kolom, tapi dipudarkan: yang sedang dibaca bulan ini, bukan sisipannya. */
.agenda-bulan__kotak--luar {
    background-color: #fafafc;
}

.agenda-bulan__kotak--luar .agenda-bulan__angka,
.agenda-bulan__kotak--lampau .agenda-bulan__angka {
    color: #b7b5be;
}

/* Hari ini ditandai lewat inset shadow, bukan border: border akan menggeser
   lebar kolomnya sendiri dan membuat satu kolom meleset dari kolom lain. */
.agenda-bulan__kotak--hariini {
    background-color: rgba(115, 103, 240, 0.06);
    box-shadow: inset 0 0 0 2px #7367f0;
}

.agenda-bulan__tanggal {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.25rem;
}

.agenda-bulan__angka {
    min-width: 1.5rem;
    color: #5d596c;
    font-size: 0.8125rem;
    font-weight: 700;
    line-height: 1.5rem;
    text-align: center;
}

.agenda-bulan__kotak--hariini .agenda-bulan__angka {
    display: grid;
    place-items: center;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 50%;
    background-color: #7367f0;
    color: #fff;
}

/* Efek hover untuk kotak yang memiliki agenda */
.agenda-bulan__kotak--ada-agenda {
    cursor: pointer;
    transition: background-color 0.2s ease;
}

.agenda-bulan__kotak--ada-agenda:hover {
    background-color: rgba(115, 103, 240, 0.04);
}

.agenda-bulan__jumlah {
    padding: 0 0.35rem;
    border-radius: 6px;
    background-color: rgba(115, 103, 240, 0.1);
    color: #7367f0;
    font-size: 0.6875rem;
    font-weight: 700;
}

.agenda-bulan__daftar {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.agenda-bulan__pil {
    display: flex;
    align-items: baseline;
    gap: 0.3rem;
    padding: 0.2rem 0.35rem;
    border-left: 3px solid #7367f0;
    border-radius: 4px;
    background-color: rgba(115, 103, 240, 0.08);
    color: #5d596c;
    font-size: 0.75rem;
    line-height: 1.3;
    text-decoration: none;
    transition: background-color 0.15s ease;
}

.agenda-bulan__pil:hover,
.agenda-bulan__pil:focus-visible {
    background-color: rgba(115, 103, 240, 0.18);
    color: #5d596c;
}

.agenda-bulan__jam {
    flex-shrink: 0;
    color: #7367f0;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

/* Nama ruang dipotong satu baris. Tinggi kotak harus seragam sepanjang satu
   baris pekan: satu nama panjang tidak boleh menarik enam tanggal lain ikut
   memanjang. Isi utuhnya tetap terbaca lewat title dan daftar rinci. */
.agenda-bulan__ruang {
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

/* Sedang berlangsung memakai hijau yang sama dengan .agenda-card--live. */
.agenda-bulan__pil--live {
    border-left-color: #28c76f;
    background-color: rgba(40, 199, 111, 0.1);
}

.agenda-bulan__pil--live .agenda-bulan__jam {
    color: #28c76f;
}

/* Acara yang berangkat di tanggal sebelumnya: garisnya putus-putus dan jamnya
   diganti panah, karena "09:00" di kotak ini akan terbaca sebagai jam mulai
   yang salah. */
.agenda-bulan__pil--lanjutan {
    border-left-style: dashed;
}

.agenda-bulan__lainnya {
    display: inline-block;
    padding: 0.1rem 0.35rem;
    color: #6f6b7d;
    font-size: 0.6875rem;
    font-weight: 600;
    text-decoration: none;
}

.agenda-bulan__lainnya:hover,
.agenda-bulan__lainnya:focus-visible {
    color: #7367f0;
    text-decoration: underline;
}

/* ---------- Daftar rinci di bawah kalender ---------- */

.agenda-bulan-rinci__judul {
    margin-bottom: 1rem;
    color: #5d596c;
    font-size: 1.125rem;
    font-weight: 700;
}

/* Tautan "+n lainnya" melompat ke grup tanggal di daftar rinci. Navbar halaman
   ini menggantung di atas, jadi tanpa jarak ini judul tanggal yang dituju
   berhenti tepat di belakangnya. */
.agenda-timeline__group[id] {
    scroll-margin-top: 6rem;
}

/* ---------- Keadaan kosong ---------- */

/* Bulan kosong itu jalan buntu: tanpa tangga keluar satu-satunya jalan pengguna
   adalah tombol kembali peramban. */
.agenda-empty__aksi {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.5rem;
    margin-top: 1rem;
}

/* ---------- Layar kecil ---------- */

@media (max-width: 575.98px) {
    /* Nama bulan di panah dibuang, chevron-nya saja: dua nama bulan penuh plus
       dua select tidak muat sebaris, dan yang pecah jadi berantakan. */
    .agenda-bulan-nav__panah-teks {
        display: none;
    }

    .agenda-bulan-nav__select,
    .agenda-bulan-nav__select--tahun {
        min-width: 0;
        flex: 1 1 6rem;
    }

    .agenda-bulan-nav__ruang {
        flex: 1 1 100%;
        flex-wrap: wrap;
    }
}

@media (prefers-reduced-motion: reduce) {
    .agenda-bulan-nav__panah,
    .agenda-bulan__pil {
        transition: none;
    }
}


/* --------------------------------------------------------------------------
   Daftar ruangan (halaman /ruangkami)

   Badan kartunya dipakai bersama .agenda-card (lihat selector gabungan di blok
   agenda di atas), jadi kartu ruang dan kartu agenda dijamin punya sudut,
   garis, bayangan, dan efek hover yang sama — bukan disalin lalu berbeda
   diam-diam. Yang ditulis di sini cuma isi yang memang khas halaman ini:
   galeri foto dan baris tombol.

   Kolomnya mengikuti timeline agenda (1 / 2 / 3) supaya orang yang pindah
   antar halaman tidak perlu menyesuaikan cara memindai lagi.
   -------------------------------------------------------------------------- */

.ruang-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
}

@media (min-width: 768px) {
    .ruang-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (min-width: 992px) {
    .ruang-grid {
        grid-template-columns: repeat(3, 1fr);
    }
}

/* Kolom supaya baris tombol bisa didorong ke dasar kartu; height 100% membuat
   kartu sebaris sama tinggi walau panjang deskripsinya beda. */
.ruang-card {
    display: flex;
    flex-direction: column;
    height: 100%;
}

/* ---------- Galeri foto ---------- */

/* Menggantikan Swiper yang dipakai versi lama. Di sana setiap kartu memakai
   id="swiper-with-progress" yang sama, padahal ui-carousel.js meng-init lewat
   querySelector('#swiper-with-progress') — jadi hanya kartu pertama yang
   sliernya hidup, dan tombol panahnya (dicari dengan selector global
   .swiper-button-next) saling rebut antar kartu.

   Penggantinya scroll-snap biasa: tiap kartu berdiri sendiri, tidak ada id
   kembar, di layar sentuh sudah bisa digeser tanpa JS sama sekali. Tombol
   panahnya cuma tambahan untuk pengguna mouse dan baru muncul kalau JS-nya
   jalan (lihat .is-navigable).
   -------------------------------------------------------------------------- */

.ruang-card__gallery {
    position: relative;
    background-color: #e9e7fb;
}

.ruang-card__track {
    display: flex;
    aspect-ratio: 5 / 2;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    /* batang gulir disembunyikan karena geseran di sini pakai tombol/sentuh,
       bukan diseret; jejaknya tetap bisa digulir dengan roda dan keyboard */
    scrollbar-width: none;
}

.ruang-card__track::-webkit-scrollbar {
    display: none;
}

.ruang-card__slide {
    flex: 0 0 100%;
    scroll-snap-align: center;
    background-position: center;
    background-size: cover;
}

/* Ruang tanpa foto sama sekali: samakan tinggi pitanya dengan yang berfoto
   supaya kartu sebaris tetap rapi, lalu isi ikon agar terbaca "belum ada foto"
   dan bukan gambar yang gagal dimuat. */
.ruang-card__gallery--kosong {
    display: grid;
    place-items: center;
    aspect-ratio: 5 / 2;
    color: #b3aef0;
    font-size: 2rem;
}

.ruang-card__nav {
    /* disembunyikan sampai JS memasang .is-navigable; tanpa JS tombol ini
       tidak berfungsi, jadi lebih baik tidak ditawarkan sama sekali */
    display: none;
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    place-items: center;
    width: 2rem;
    height: 2rem;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background-color: rgba(255, 255, 255, 0.92);
    color: #5d596c;
    box-shadow: 0 2px 6px rgba(93, 89, 108, 0.2);
    cursor: pointer;
}

.ruang-card__gallery.is-navigable .ruang-card__nav {
    display: grid;
}

.ruang-card__nav:hover {
    background-color: #fff;
    color: #7367f0;
}

.ruang-card__nav:focus-visible {
    outline: 2px solid #7367f0;
    outline-offset: 2px;
}

.ruang-card__nav--prev {
    left: 0.5rem;
}

.ruang-card__nav--next {
    right: 0.5rem;
}

.ruang-card__count {
    position: absolute;
    left: 0.5rem;
    bottom: 0.5rem;
    padding: 0.1rem 0.45rem;
    border-radius: 6px;
    background-color: rgba(45, 41, 61, 0.65);
    color: #fff;
    font-size: 0.6875rem;
    font-weight: 600;
}

/* ---------- Isi kartu ---------- */

.ruang-card__body {
    display: flex;
    flex-grow: 1;
    flex-direction: column;
    padding: 1.125rem;
}

.ruang-card__title {
    margin-bottom: 0.4rem;
    color: #5d596c;
    font-size: 1.0625rem;
    font-weight: 700;
    line-height: 1.4;
    text-wrap: pretty;
}

.ruang-card__address {
    display: flex;
    align-items: flex-start;
    gap: 0.4rem;
    margin-bottom: 0.75rem;
    color: #6f6b7d;
    font-size: 0.8125rem;
    line-height: 1.5;
}

.ruang-card__address i {
    /* ikon disejajarkan ke baris pertama, bukan ke tengah blok, supaya alamat
       dua baris tidak membuat pin-nya melayang di tengah */
    margin-top: 0.15rem;
    color: #a5a3ae;
}

/* Deskripsi sengaja tidak dipotong: tidak ada halaman detail ruang di aplikasi
   ini, jadi kartu inilah satu-satunya tempat keterangan ruang bisa dibaca.
   Kartu dalam satu baris grid tetap rata karena tingginya saling menyamakan. */
.ruang-card__desc {
    margin-bottom: 1rem;
    color: #6f6b7d;
    font-size: 0.875rem;
    line-height: 1.6;
}

.ruang-card__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    /* menempel di dasar kartu supaya tombol antar kartu sebaris tetap sejajar */
    margin-top: auto;
    padding-top: 1rem;
    border-top: 1px solid #f1f0f4;
}

@media (prefers-reduced-motion: reduce) {
    .ruang-card__nav {
        transition: none;
    }
}

/* --------------------------------------------------------------------------
   Tentang Kami (halaman /tentangkami)

   Versi lama memuat isi tiap tab lewat AJAX dan melaporkan kegagalan dengan
   popup SweetAlert. Sekarang isinya dirender server (tab dipilih lewat ?tab=),
   jadi tidak ada layar kosong menunggu balasan, tidak ada popup yang harus
   ditutup dulu, dan tiap tab punya URL sendiri yang bisa disalin/di-bookmark.
   Keadaan "kategori belum ada" dan "belum ada isi" ditampilkan sebagai isi
   halaman biasa (lihat .agenda-empty), bukan sebagai peringatan.
   -------------------------------------------------------------------------- */

/* ---------- Baris tab ---------- */

.tentang-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0 0 1.25rem;
    padding: 0;
    list-style: none;
}

/* Tab-nya tautan sungguhan, bukan tombol JS: bisa dibuka di tab baru, tombol
   kembali di browser jalan, dan tetap berfungsi kalau JS gagal dimuat. */
.tentang-tab {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.5rem 0.875rem;
    border: 1px solid #ebe9f1;
    border-radius: 999px;
    background-color: #fff;
    color: #6f6b7d;
    font-size: 0.8125rem;
    font-weight: 600;
    text-decoration: none;
    transition:
        color 0.2s ease,
        border-color 0.2s ease,
        background-color 0.2s ease;
}

.tentang-tab:hover {
    border-color: #d5d0fb;
    color: #7367f0;
}

.tentang-tab:focus-visible {
    outline: 2px solid #7367f0;
    outline-offset: 2px;
}

.tentang-tab.is-active {
    border-color: #7367f0;
    background-color: #7367f0;
    color: #fff;
    box-shadow: 0 4px 12px rgba(115, 103, 240, 0.25);
}

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

.tentang-list {
    display: grid;
    gap: 0.75rem;
}

/* <details> dipakai, bukan accordion Bootstrap, supaya isi halaman ini tetap
   bisa dibuka-tutup walau JS tidak jalan — ini halaman informasi layanan
   publik, jadi isinya tidak boleh bergantung pada skrip. */
.tentang-item {
    border: 1px solid #ebe9f1;
    border-radius: 12px;
    background-color: #fff;
    overflow: hidden;
}

.tentang-item__summary {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0.875rem 1.125rem;
    color: #5d596c;
    font-size: 0.9375rem;
    font-weight: 700;
    line-height: 1.45;
    cursor: pointer;
    /* segitiga bawaan browser dimatikan, diganti chevron sendiri di bawah */
    list-style: none;
}

.tentang-item__summary::-webkit-details-marker {
    display: none;
}

.tentang-item__summary:hover {
    color: #7367f0;
}

.tentang-item__summary:focus-visible {
    outline: 2px solid #7367f0;
    outline-offset: -2px;
}

.tentang-item__chevron {
    flex-shrink: 0;
    margin-left: auto;
    color: #a5a3ae;
    transition: transform 0.2s ease;
}

.tentang-item[open] .tentang-item__summary {
    color: #7367f0;
    border-bottom: 1px solid #f1f0f4;
}

.tentang-item[open] .tentang-item__chevron {
    transform: rotate(90deg);
}

.tentang-item__body {
    padding: 1.125rem;
}

/* ---------- Isi dari editor ---------- */

/* Isi post ditulis admin lewat CKEditor, jadi tag-nya bisa apa saja. Blok ini
   memberi batas aman: gambar/tabel tidak boleh melebar melewati kartu, dan
   warna/jarak teksnya disamakan dengan halaman lain. */
.tentang-prose {
    color: #6f6b7d;
    font-size: 0.9375rem;
    line-height: 1.7;
}

.tentang-prose > :last-child {
    margin-bottom: 0;
}

.tentang-prose h1,
.tentang-prose h2,
.tentang-prose h3,
.tentang-prose h4,
.tentang-prose h5,
.tentang-prose h6 {
    margin-bottom: 0.5rem;
    color: #5d596c;
    font-weight: 700;
    line-height: 1.4;
}

.tentang-prose a {
    color: #7367f0;
    text-decoration: underline;
}

.tentang-prose img {
    max-width: 100%;
    height: auto;
    border-radius: 8px;
}

.tentang-prose ul,
.tentang-prose ol {
    margin-bottom: 1rem;
    padding-left: 1.25rem;
}

/* Tabel lebar digulir di dalam kotaknya sendiri, jadi halaman tidak ikut
   bergeser ke samping di layar sempit. */
.tentang-prose .table-wrap,
.tentang-prose figure.table {
    display: block;
    max-width: 100%;
    margin: 0 0 1rem;
    overflow-x: auto;
}

.tentang-prose table {
    width: 100%;
    border-collapse: collapse;
}

.tentang-prose th,
.tentang-prose td {
    padding: 0.5rem 0.75rem;
    border: 1px solid #ebe9f1;
    text-align: left;
}

/* ---------- Tab kontak ---------- */

.kontak-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
}

@media (min-width: 768px) {
    .kontak-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

.kontak-card {
    display: flex;
    align-items: flex-start;
    gap: 0.875rem;
    padding: 1.125rem;
}

.kontak-card__icon {
    display: grid;
    place-items: center;
    flex-shrink: 0;
    width: 2.5rem;
    height: 2.5rem;
    border-radius: 8px;
    background-color: rgba(115, 103, 240, 0.1);
    color: #7367f0;
    font-size: 1.125rem;
}

.kontak-card__icon--wa {
    background-color: rgba(40, 199, 111, 0.12);
    color: #28c76f;
}

.kontak-card__label {
    margin-bottom: 0.15rem;
    color: #a5a3ae;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

.kontak-card__value {
    margin-bottom: 0.15rem;
    color: #5d596c;
    font-size: 0.9375rem;
    font-weight: 700;
    /* nomor/surel panjang dipatahkan daripada melebarkan kartu */
    overflow-wrap: anywhere;
}

.kontak-card__value a {
    color: inherit;
    text-decoration: none;
}

.kontak-card__value a:hover,
.kontak-card__value a:focus-visible {
    color: #7367f0;
}

.kontak-card__note {
    margin: 0;
    color: #6f6b7d;
    font-size: 0.8125rem;
    line-height: 1.5;
}

@media (prefers-reduced-motion: reduce) {
    .tentang-tab,
    .tentang-item__chevron {
        transition: none;
    }
}

/* --------------------------------------------------------------------------
   Papan informasi Smart TV (halaman /smarttv)

   Halaman ini bukan halaman yang dibaca sambil dipegang: layarnya menempel di
   dinding, tidak ada yang menyentuh atau men-scroll-nya, dan yang lewat cuma
   punya beberapa detik untuk membaca. Tiga hal itu yang menentukan seluruh
   aturan di blok ini:

   1. TIDAK BOLEH ADA SCROLL. Tinggi halaman dikunci setinggi layar
      (100dvh). Isi yang tidak muat TIDAK dipotong diam-diam, tapi
      digilir per halaman oleh pager di dashboard-tv.blade.php — kalau
      dipotong, agenda ruang paling bawah tidak akan pernah terbaca sama
      sekali. Semua wadah di jalur tinggi ini memakai min-height: 0 supaya
      grid/flex benar-benar mau menyusut, bukan melar mengikuti isinya.

   2. UKURAN IKUT LAYAR. font-size root diskalakan ke vh + vw, jadi satu
      berkas yang sama tetap terbaca di monitor 1366x768 maupun TV 4K tanpa
      breakpoint per perangkat. Karena semua ukuran di bawah memakai rem,
      seluruh papan ikut membesar/mengecil bersama-sama.

   3. WARNANYA SAMA DENGAN HALAMAN PUBLIK. Ungu #7367f0, judul #5d596c, teks
      sekunder #6f6b7d, garis #ebe9f1, hijau "sedang berlangsung" #28c76f —
      persis palet .agenda-card di atas. Papan TV dan situsnya harus terbaca
      sebagai satu produk, bukan dua aplikasi berbeda.

   Sudut mengikuti aturan yang sama dengan blok agenda: kartu 12px, chip 6px.
   -------------------------------------------------------------------------- */

/* Diskalakan ke tinggi layar lebih besar dari lebarnya, karena yang membatasi
   papan ini memang tingginya. Batas bawah 14px menjaga halaman tetap terbaca
   kalau kebetulan dibuka di ponsel. */
html.tv-page {
    font-size: clamp(14px, 0.4vw + 1.05vh, 30px);
}

html.tv-page,
html.tv-page body {
    height: 100%;
    /* pengunci utama: apa pun yang terjadi pada isinya, papan tidak pernah
       memunculkan scrollbar */
    overflow: hidden;
}

.tv-app {
    --tv-primary: #7367f0;
    --tv-primary-soft: rgba(115, 103, 240, 0.1);
    --tv-live: #28c76f;
    --tv-live-soft: rgba(40, 199, 111, 0.12);
    --tv-heading: #5d596c;
    --tv-muted: #6f6b7d;
    --tv-line: #ebe9f1;
    --tv-gap: 0.75rem;
    /* tinggi area kartu; diisi ulang dari JS supaya satu kartu tidak pernah
       lebih tinggi dari satu halaman gilirannya */
    --tv-vp-h: 100vh;

    /* inset: 0 pada elemen fixed, bukan height: 100dvh. Satuan vh/dvh tidak
       selalu sama dengan tinggi layar yang benar-benar terlihat (bilah browser
       di ponsel, jendela peramban di stik TV), dan selisih beberapa puluh
       piksel saja sudah membuat baris paling bawah papan terdorong ke luar
       layar. Kotak fixed selalu persis sebesar area yang terlihat. */
    position: fixed;
    inset: 0;
    display: grid;
    grid-template-rows: auto minmax(0, 1fr) auto;
    overflow: hidden;
    background-color: #f8f7fa;
    color: var(--tv-heading);
    font-family: "Public Sans", system-ui, -apple-system, sans-serif;
}

/* ---------- Kepala papan ---------- */

.tv-topbar {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0.7rem 1.1rem;
    border-bottom: 1px solid var(--tv-line);
    background-color: #fff;
}

.tv-brand {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    min-width: 0;
}

.tv-brand__logo {
    width: 2.6rem;
    height: auto;
    flex-shrink: 0;
}

.tv-brand__instansi {
    margin: 0;
    color: var(--tv-muted);
    font-size: 0.8rem;
    font-weight: 500;
    line-height: 1.3;
}

.tv-brand__app {
    margin: 0;
    color: var(--tv-heading);
    font-size: 1.15rem;
    font-weight: 700;
    line-height: 1.25;
    letter-spacing: -0.01em;
}

.tv-brand__app span {
    color: var(--tv-primary);
}

/* Ringkasan angka: dibaca sekilas dari jauh, jadi angkanya besar dan
   labelnya kecil — bukan sebaliknya. */
.tv-stats {
    display: flex;
    gap: 0.5rem;
    margin-left: auto;
}

.tv-stat {
    min-width: 4.6rem;
    padding: 0.35rem 0.7rem;
    border: 1px solid var(--tv-line);
    border-radius: 12px;
    background-color: #fff;
    text-align: center;
}

.tv-stat__num {
    display: block;
    color: var(--tv-heading);
    font-size: 1.3rem;
    font-weight: 700;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

.tv-stat__label {
    display: block;
    color: var(--tv-muted);
    font-size: 0.65rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
}

.tv-stat--live {
    border-color: rgba(40, 199, 111, 0.35);
    background-color: var(--tv-live-soft);
}

.tv-stat--live .tv-stat__num,
.tv-stat--live .tv-stat__label {
    color: var(--tv-live);
}

/* Jam dibuat paling menonjol di papan: di ruang tunggu, "sekarang jam berapa"
   adalah hal pertama yang dicari orang sebelum membaca jadwalnya. */
.tv-clock {
    padding-left: 1rem;
    border-left: 1px solid var(--tv-line);
    text-align: right;
}

.tv-clock__time {
    display: block;
    color: var(--tv-primary);
    font-size: 2rem;
    font-weight: 700;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

.tv-clock__date {
    display: block;
    margin-top: 0.15rem;
    color: var(--tv-muted);
    font-size: 0.78rem;
    font-weight: 600;
}

/* ---------- Badan: daftar ruang + panel kanan ---------- */

.tv-main {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 17rem);
    gap: var(--tv-gap);
    min-height: 0;
    padding: var(--tv-gap);
}

.tv-board {
    display: flex;
    flex-direction: column;
    min-height: 0;
    min-width: 0;
}

.tv-board__head {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin-bottom: 0.55rem;
}

.tv-board__title {
    margin: 0;
    color: var(--tv-heading);
    font-size: 1.05rem;
    font-weight: 700;
    letter-spacing: -0.01em;
}

.tv-board__date {
    flex-shrink: 0;
    padding: 0.2rem 0.55rem;
    border: 1px solid rgba(115, 103, 240, 0.2);
    border-radius: 8px;
    background-color: var(--tv-primary-soft);
    color: var(--tv-primary);
    font-size: clamp(0.82rem, 0.3vw + 0.7rem, 1rem);
    font-weight: 700;
    line-height: 1.25;
    white-space: nowrap;
}

/* Titik halaman hanya muncul kalau isinya memang digilir (dipasang JS), supaya
   papan yang isinya muat satu layar tidak menampilkan kontrol yang tidak
   berarti apa-apa. */
.tv-pager {
    display: none;
    align-items: center;
    gap: 0.6rem;
    margin-left: auto;
}

.tv-pager.is-active {
    display: flex;
}

.tv-pager__label {
    color: var(--tv-muted);
    font-size: 0.72rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.tv-pager__dots {
    display: flex;
    gap: 0.3rem;
}

.tv-pager__dot {
    width: 0.45rem;
    height: 0.45rem;
    border-radius: 50%;
    background-color: #dbdade;
    transition: background-color 0.3s ease, width 0.3s ease;
}

.tv-pager__dot.is-current {
    width: 1.3rem;
    border-radius: 999px;
    background-color: var(--tv-primary);
}

/* Jendela yang memotong. Grid di dalamnya digeser dengan transform, bukan
   scrollTop, supaya perpindahannya mulus dan tidak pernah menampilkan
   scrollbar di layar publik. */
.tv-board__viewport {
    position: relative;
    flex: 1;
    min-height: 0;
    overflow: hidden;
}

.tv-board__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr));
    /* start, bukan stretch: ruang yang kosong hari ini tidak perlu ikut setinggi
       ruang tersibuk di barisnya — kartu kosong setinggi layar terbaca seperti
       ada yang gagal dimuat. */
    align-items: start;
    gap: var(--tv-gap);
    transition: transform 0.7s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Kartu milik halaman lain disembunyikan, bukan dibiarkan mengintip di tepi
   bawah: kartu yang terpotong separuh di papan informasi terbaca sebagai
   tampilan rusak, bukan sebagai "masih ada lanjutannya". */
.tv-room.is-outside {
    opacity: 0;
}

.tv-room {
    transition: opacity 0.5s ease;
}

/* Ikon diberi tinggi baris tetap supaya kotaknya tidak bergantung pada metrik
   font ikon. Font ikon selesai dimuat belakangan; kalau tinggi barisnya ikut
   metrik font, tinggi kartu berubah SETELAH papan selesai dihitung, dan acara
   terakhir yang tadinya pas jadi terpotong. Dengan line-height angka, tinggi
   kotaknya sudah pasti sejak sebelum fontnya datang. */
.tv-room__name i,
.tv-tag i,
.tv-room__empty i,
.tv-board__empty i,
.tv-ticker__label i {
    flex-shrink: 0;
    line-height: 1;
}

/* Kalau isinya cuma lewat sedikit dari satu layar, jaraknya dirapatkan dulu
   sebelum papan memutuskan menggilir halaman: melihat semua ruang sekaligus
   jauh lebih berguna bagi orang yang lewat daripada harus menunggu giliran
   halaman kedua. Yang dirapatkan hanya jarak — ukuran huruf tidak diturunkan,
   karena papan ini dibaca dari jauh. */
.tv-board.is-compact {
    --tv-gap: 0.5rem;
}

.tv-board.is-compact .tv-event {
    padding: 0.35rem 0.65rem;
}

.tv-board.is-compact .tv-room__head {
    padding: 0.45rem 0.65rem;
}

.tv-board.is-compact .tv-event__title {
    margin-bottom: 0.05rem;
}

/* ---------- Kartu ruang ---------- */

.tv-room {
    display: flex;
    flex-direction: column;
    /* dibatasi setinggi satu halaman giliran; sisanya diringkas jadi "+N" oleh
       JS, bukan dipotong tanpa keterangan */
    max-height: var(--tv-vp-h);
    border: 1px solid var(--tv-line);
    border-radius: 12px;
    background-color: #fff;
    overflow: hidden;
}

/* Ruang yang sedang dipakai diberi tepi hijau: dari jauh, warna tepi terbaca
   lebih dulu daripada teks di dalamnya. */
.tv-room--live {
    border-color: rgba(40, 199, 111, 0.45);
    box-shadow: 0 0 0 1px rgba(40, 199, 111, 0.15);
}

.tv-room__head {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem 0.8rem;
    border-bottom: 1px solid var(--tv-line);
    background-color: #fcfcfd;
}

.tv-room__name {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin: 0;
    min-width: 0;
    color: var(--tv-heading);
    font-size: 0.98rem;
    font-weight: 700;
    line-height: 1.3;
}

.tv-room__name i {
    flex-shrink: 0;
    color: var(--tv-primary);
}

.tv-room__name span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.tv-room__count {
    flex-shrink: 0;
    margin-left: auto;
    padding: 0.1rem 0.45rem;
    border-radius: 6px;
    background-color: var(--tv-primary-soft);
    color: var(--tv-primary);
    font-size: 0.7rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.tv-room__list {
    /* 1 1 auto, bukan flex: 1. flex: 1 memberi flex-basis 0%, artinya kartu
       menghitung tingginya sendiri seolah daftar acaranya kosong — kartu jadi
       lebih pendek dari isinya dan acara terakhir terpotong. Dengan basis auto,
       daftar berangkat dari tinggi isinya dan baru menyusut kalau kartunya
       benar-benar mentok di max-height. */
    flex: 1 1 auto;
    /* min-height: 0 + overflow hidden = daftar acara mau menyusut mengikuti
       max-height kartunya, jadi kartu tidak pernah melewati tinggi halaman */
    min-height: 0;
    margin: 0;
    padding: 0;
    list-style: none;
    overflow: hidden;
}

/* Urutan baca yang dituju: JAM -> ACARA APA -> SIAPA. Jam ditaruh di kolom
   sendiri supaya deretan jam antar acara sejajar dan enak dipindai dari jauh. */
.tv-event {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: 0.6rem;
    padding: 0.5rem 0.8rem;
}

.tv-event + .tv-event {
    border-top: 1px solid #f4f3f7;
}

/* display: grid/flex di atas mengalahkan atribut [hidden] bawaan browser, jadi
   penyembunyian oleh JS (acara yang tidak muat, badge yang belum waktunya)
   harus dinyatakan ulang di sini. */
.tv-event[hidden],
.tv-room__more[hidden],
.tv-badge-live[hidden] {
    display: none;
}

.tv-event__time {
    padding-left: 0.5rem;
    border-left: 3px solid #dbdade;
    color: var(--tv-muted);
    font-size: 0.82rem;
    font-weight: 700;
    line-height: 1.35;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.tv-event__time small {
    display: block;
    font-size: 0.72em;
    font-weight: 500;
    opacity: 0.75;
}

.tv-event__title {
    margin: 0 0 0.15rem;
    color: var(--tv-heading);
    font-size: 0.92rem;
    font-weight: 700;
    line-height: 1.35;
    text-wrap: pretty;
    /* dua baris supaya satu acara berjudul panjang tidak menelan jatah baca
       acara lain di ruang yang sama */
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
}

.tv-event__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
    margin: 0;
}

/* Chip di sini sengaja sekeluarga dengan .agenda-tag di halaman publik */
.tv-tag {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    max-width: 100%;
    padding: 0.1rem 0.4rem;
    border-radius: 6px;
    background-color: #f4f3f7;
    color: var(--tv-muted);
    font-size: 0.7rem;
    font-weight: 500;
}

.tv-tag span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.tv-tag--multiday {
    background-color: rgba(255, 159, 67, 0.12);
    color: #ff9f43;
    font-weight: 600;
}

/* Acara yang sedang berjalan: garis kiri hijau + latar tipis. Ini satu-satunya
   info di papan yang basi kalau telat dibaca, jadi dibedakan paling tegas. */
.tv-event--live {
    background-color: rgba(40, 199, 111, 0.06);
}

.tv-event--live .tv-event__time {
    border-left-color: var(--tv-live);
    color: var(--tv-live);
}

/* Acara berikutnya diberi aksen ungu supaya jelas mana yang akan dipakai
   setelah yang sedang berjalan selesai. */
.tv-event--next .tv-event__time {
    border-left-color: var(--tv-primary);
    color: var(--tv-primary);
}

/* Yang sudah lewat tetap ditampilkan (orang perlu tahu ruang sempat dipakai),
   tapi diredupkan supaya tidak bersaing dengan yang masih relevan. */
.tv-event--done {
    opacity: 0.55;
}

.tv-badge-live {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.05rem 0.4rem;
    border-radius: 6px;
    background-color: var(--tv-live-soft);
    color: var(--tv-live);
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: uppercase;
}

.tv-badge-live::before {
    content: "";
    width: 0.35rem;
    height: 0.35rem;
    border-radius: 50%;
    background-color: currentColor;
    animation: agenda-status-pulse 1.6s ease-in-out infinite;
}

/* Sisa acara yang tidak muat diringkas, bukan dihilangkan diam-diam, supaya
   orang tahu masih ada jadwal lain di ruang itu. */
.tv-room__more {
    flex-shrink: 0;
    /* <p> membawa margin-bottom dari Bootstrap; di dalam kartu setinggi tetap,
       margin itu diam-diam memangkas tinggi daftar acaranya. */
    margin: 0;
    padding: 0.35rem 0.8rem;
    border-top: 1px solid var(--tv-line);
    background-color: var(--tv-primary-soft);
    color: var(--tv-primary);
    font-size: 0.72rem;
    font-weight: 600;
    text-align: center;
}

.tv-room__empty {
    display: flex;
    flex: 1;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.25rem;
    padding: 1.1rem 0.8rem;
    color: #a5a3ae;
    text-align: center;
}

.tv-room__empty i {
    font-size: 1.4rem;
    color: #c9c6f5;
}

.tv-room__empty span {
    font-size: 0.8rem;
    font-weight: 600;
}

/* Papan tanpa satu pun ruang tayang */
.tv-board__empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    height: 100%;
    border: 1px dashed #dbdade;
    border-radius: 12px;
    color: var(--tv-muted);
}

.tv-board__empty i {
    font-size: 2.5rem;
    color: #c9c6f5;
}

/* ---------- Panel kanan ---------- */

.tv-aside {
    display: flex;
    flex-direction: column;
    gap: var(--tv-gap);
    min-height: 0;
    min-width: 0;
}

.tv-carousel {
    position: relative;
    flex: 1;
    min-height: 0;
    border: 1px solid var(--tv-line);
    border-radius: 12px;
    overflow: hidden;
    background-color: #e9e7fb;
}

.tv-carousel .carousel,
.tv-carousel .carousel-inner,
.tv-carousel .carousel-item {
    height: 100%;
}

.tv-carousel .carousel-item {
    /* foto ruang dipasang sebagai background, bukan <img>: kalau berkasnya
       hilang yang muncul warna tint, bukan ikon gambar rusak di layar publik */
    background-position: center;
    background-size: cover;
}

.tv-carousel__caption {
    position: absolute;
    right: 0;
    bottom: 0;
    left: 0;
    padding: 1.6rem 0.8rem 0.7rem;
    background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.8) 60%);
    color: #fff;
}

.tv-carousel__name {
    margin: 0;
    font-size: 0.92rem;
    font-weight: 700;
    line-height: 1.3;
}

.tv-carousel__place {
    display: block;
    margin-top: 0.1rem;
    font-size: 0.72rem;
    opacity: 0.85;
}

/* Ajakan memesan + QR. Di papan informasi, QR adalah satu-satunya cara orang
   bisa membawa pulang alamat situsnya tanpa mengetik ulang. */
.tv-cta {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    flex-shrink: 0;
    padding: 0.7rem;
    border: 1px solid var(--tv-line);
    border-radius: 12px;
    background-color: #fff;
}

.tv-cta__qr {
    flex-shrink: 0;
    width: 4.2rem;
    height: 4.2rem;
    padding: 0.2rem;
    border: 1px solid var(--tv-line);
    border-radius: 8px;
    background-color: #fff;
}

.tv-cta__qr svg {
    display: block;
    width: 100%;
    height: 100%;
}

.tv-cta__text {
    min-width: 0;
}

.tv-cta__title {
    margin: 0 0 0.15rem;
    color: var(--tv-heading);
    font-size: 0.82rem;
    font-weight: 700;
    line-height: 1.3;
}

.tv-cta__url {
    display: block;
    color: var(--tv-primary);
    font-size: 0.72rem;
    font-weight: 600;
    word-break: break-all;
}

/* ---------- Teks berjalan ---------- */

/* Pengganti <marquee> yang sudah usang: elemennya digandakan lalu digeser
   sejauh 50%, jadi perulangannya mulus tanpa jeda kosong di ujung. */
.tv-ticker {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0.4rem 0 0.4rem 0.9rem;
    border-top: 1px solid var(--tv-line);
    background-color: var(--tv-heading);
    color: #fff;
    overflow: hidden;
}

.tv-ticker__label {
    flex-shrink: 0;
    padding: 0.15rem 0.5rem;
    border-radius: 6px;
    background-color: var(--tv-primary);
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.tv-ticker__viewport {
    flex: 1;
    min-width: 0;
    overflow: hidden;
}

.tv-ticker__track {
    display: flex;
    flex-shrink: 0;
    width: max-content;
    animation: tv-ticker-scroll 40s linear infinite;
}

.tv-ticker__item {
    flex-shrink: 0;
    padding-right: 3rem;
    font-size: 0.82rem;
    font-weight: 500;
    white-space: nowrap;
}

.tv-ticker__item u {
    text-decoration-color: var(--tv-primary);
    text-underline-offset: 0.15em;
}

@keyframes tv-ticker-scroll {
    from {
        transform: translateX(0);
    }
    to {
        transform: translateX(-50%);
    }
}

/* ---------- Layar sempit ---------- */

/* Papan ini dirancang untuk layar mendatar yang menempel di dinding. Kalau
   dibuka di ponsel, mengunci tinggi justru membuatnya tak terbaca: kartunya
   jadi seukuran perangko. Jadi di layar sempit penguncian dilepas, halaman
   boleh di-scroll seperti halaman biasa, dan pager dimatikan lewat
   --tv-pager (dibaca JS) supaya isinya tidak ikut digilir. */
.tv-app {
    --tv-pager: on;
}

@media (max-width: 991.98px) {
    html.tv-page,
    html.tv-page body {
        height: auto;
        overflow: visible;
    }

    .tv-app {
        --tv-pager: off;
        /* di layar sempit papan kembali jadi halaman biasa yang boleh
           di-scroll, jadi penguncian fixed dilepas */
        position: static;
        height: auto;
        min-height: 100dvh;
        overflow: visible;
    }

    .tv-main {
        grid-template-columns: minmax(0, 1fr);
    }

    .tv-board__viewport {
        overflow: visible;
    }

    .tv-board__grid {
        transform: none !important;
    }

    .tv-room.is-outside {
        opacity: 1;
    }

    .tv-room {
        max-height: none;
    }

    .tv-carousel {
        flex: none;
        aspect-ratio: 16 / 9;
    }

    .tv-topbar {
        flex-wrap: wrap;
    }

    .tv-clock {
        padding-left: 0;
        border-left: 0;
    }

    .tv-ticker {
        position: sticky;
        bottom: 0;
    }
}

@media (max-width: 575.98px) {
    .tv-stats {
        order: 3;
        width: 100%;
        margin-left: 0;
    }

    .tv-stat {
        flex: 1;
        min-width: 0;
    }

    .tv-clock {
        margin-left: auto;
        text-align: right;
    }
}

/* Layar sangat lebar (TV besar / videotron): kolom kartu dilebarkan supaya
   tidak muncul 6-7 kolom sempit yang judulnya terpotong semua. */
@media (min-width: 1800px) {
    .tv-board__grid {
        grid-template-columns: repeat(auto-fill, minmax(min(100%, 24rem), 1fr));
    }

    .tv-main {
        grid-template-columns: minmax(0, 1fr) minmax(0, 19rem);
    }
}

@media (prefers-reduced-motion: reduce) {
    .tv-board__grid,
    .tv-room,
    .tv-pager__dot {
        transition: none;
    }

    .tv-ticker__track,
    .tv-badge-live::before {
        animation: none;
    }
}

/* --------------------------------------------------------------------------
   Survey kepuasan untuk responden (halaman /kuisioner)

   Bedanya dengan halaman publik lain: ini satu-satunya halaman yang orang
   harus MENGERJAKAN, bukan sekadar dibaca. Tautannya dibagikan lewat WhatsApp
   setelah acara selesai, jadi hampir semua yang membuka ada di ponsel, sambil
   berdiri, dan tidak punya alasan kuat untuk menyelesaikannya. Itu yang
   menentukan keputusan di blok ini:

   1. SASARAN SENTUH BESAR. Tiap pilihan jawaban jadi satu baris penuh yang
      bisa ditekan di mana saja, bukan lingkaran radio 16px. Ini yang paling
      menentukan apakah survey di ponsel selesai atau ditinggal.
   2. SISA PEKERJAAN SELALU TERLIHAT. Bilah kemajuan menempel di atas: orang
      yang tahu tinggal dua pertanyaan lagi jauh lebih mungkin menyelesaikan
      daripada yang merasa daftarnya tidak habis-habis.
   3. KESALAHAN DITUNJUK DI TEMPATNYA. Pertanyaan wajib yang terlewat ditandai
      di pertanyaannya sendiri lalu digulir ke sana — bukan cuma daftar pesan
      di kotak dialog yang menutup layar dan hilang saat ditutup.

   Kartunya memakai .survey-card yang digabung ke kelompok .agenda-card di atas,
   jadi sudut 12px, garis #ebe9f1, dan bayangannya dijamin sama dengan kartu di
   halaman lain. Chip 6px, palet ungu #7367f0 — sama seperti blok lain di
   berkas ini.
   -------------------------------------------------------------------------- */

/* Kolom tunggal yang sempit. Formulir dibaca satu hal per waktu; lebar penuh
   membuat mata harus melompat jauh antar baris dan terasa seperti berkas kerja,
   bukan seperti beberapa pertanyaan singkat. */
.survey-shell {
    max-width: 46rem;
    margin-inline: auto;
}

.survey-intro {
    margin-bottom: 1rem;
    color: #6f6b7d;
    font-size: 0.9375rem;
    line-height: 1.6;
    text-wrap: pretty;
}

/* ---------- Konteks peminjaman ---------- */

/* Responden perlu tahu acara mana yang sedang dinilai — tautan survey sering
   dibuka berhari-hari setelah acaranya lewat. */
.survey-context {
    display: grid;
    gap: 0.625rem;
    padding: 1rem 1.125rem;
    margin-bottom: 1rem;
}

.survey-context__label {
    margin-bottom: 0.75rem;
    color: #a5a3ae;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

.survey-context__row {
    display: flex;
    align-items: flex-start;
    gap: 0.625rem;
    font-size: 0.875rem;
    line-height: 1.5;
}

.survey-context__row i {
    flex-shrink: 0;
    margin-top: 0.15rem;
    color: #7367f0;
    line-height: 1;
}

.survey-context__row strong {
    min-width: 0;
    color: #5d596c;
    font-weight: 700;
    overflow-wrap: anywhere;
    word-break: break-word;
}

.survey-context__row span {
    min-width: 0;
    color: #6f6b7d;
    overflow-wrap: anywhere;
    word-break: break-word;
}

/* Keterangan wajib ditempatkan sebelum daftar pertanyaan agar dibaca sebelum
   responden mulai mengisi, bukan baru setelah seluruh formulir selesai. */
.survey-required-note {
    margin: 0 0 0.875rem;
    padding: 0.75rem 1rem;
    border-radius: 8px;
    background-color: rgba(115, 103, 240, 0.06);
    color: #6f6b7d;
    font-size: 0.8125rem;
    line-height: 1.5;
    text-align: center;
}

.survey-required-note .survey-q__req {
    display: inline;
}

/* ---------- Bilah kemajuan ---------- */

.survey-progress {
    /*
     * Jangan dibuat sticky/fixed. Bilah kemajuan tetap berada dalam alur dokumen
     * agar tidak menutupi field, pilihan jawaban, atau tombol kirim saat di-scroll,
     * terutama pada viewport pendek seperti Chrome Android.
     */
    margin-bottom: 1rem;
    padding: 0.75rem 1.125rem;
    background-color: #fff;
}

.survey-progress__top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 0.5rem;
}

.survey-progress__text {
    color: #5d596c;
    font-size: 0.8125rem;
    font-weight: 600;
}

.survey-progress__count {
    color: #7367f0;
    font-size: 0.8125rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.survey-progress__track {
    height: 0.375rem;
    border-radius: 999px;
    background-color: #ebe9f1;
    overflow: hidden;
}

.survey-progress__bar {
    width: 0;
    height: 100%;
    border-radius: 999px;
    background-color: #7367f0;
    transition: width 0.35s ease;
}

.survey-progress--penuh .survey-progress__bar {
    background-color: #28c76f;
}

.survey-progress--penuh .survey-progress__count {
    color: #28c76f;
}

/* ---------- Identitas ---------- */

.survey-card__head {
    padding: 1rem 1.125rem;
    border-bottom: 1px solid #ebe9f1;
}

.survey-card__title {
    margin: 0;
    color: #5d596c;
    font-size: 1rem;
    font-weight: 700;
}

.survey-card__hint {
    margin: 0.15rem 0 0;
    color: #6f6b7d;
    font-size: 0.8125rem;
    line-height: 1.5;
}

.survey-card__body {
    padding: 1.125rem;
}

.survey-idgrid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0.875rem;
}

@media (min-width: 576px) {
    .survey-idgrid {
        grid-template-columns: repeat(2, 1fr);
    }
}

.survey-label {
    display: block;
    margin-bottom: 0.35rem;
    color: #5d596c;
    font-size: 0.8125rem;
    font-weight: 600;
}

/* ---------- Satu pertanyaan ---------- */

.survey-q + .survey-q {
    margin-top: 0.875rem;
}

.survey-q__head {
    display: flex;
    align-items: flex-start;
    gap: 0.625rem;
    margin-bottom: 0.875rem;
}

/* Nomor dipisah dari teks pertanyaan supaya baris kedua pertanyaan yang panjang
   tetap rata di bawah huruf pertama, bukan menyelip di bawah angkanya. */
.survey-q__num {
    display: grid;
    place-items: center;
    flex-shrink: 0;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 6px;
    background-color: rgba(115, 103, 240, 0.1);
    color: #7367f0;
    font-size: 0.75rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.survey-q__text {
    margin: 0;
    color: #5d596c;
    font-size: 0.9375rem;
    font-weight: 600;
    line-height: 1.5;
    text-wrap: pretty;
}

.survey-q__req {
    color: #ea5455;
    font-weight: 700;
}

/* ---------- Pilihan jawaban ---------- */

.survey-options {
    display: grid;
    gap: 0.5rem;
    /* fieldset bawaan browser punya margin & padding sendiri */
    margin: 0;
    padding: 0;
    border: 0;
}

/* Seluruh baris jadi sasaran sentuh, bukan cuma lingkaran radionya. Di ponsel
   inilah bedanya antara survey yang selesai dan survey yang ditinggal. */
.survey-option {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    /* min-height 2.75rem kira-kira 44px, ukuran sasaran sentuh yang nyaman */
    min-height: 2.75rem;
    padding: 0.625rem 0.875rem;
    border: 1px solid #ebe9f1;
    border-radius: 8px;
    color: #6f6b7d;
    font-size: 0.9375rem;
    line-height: 1.45;
    cursor: pointer;
    transition:
        border-color 0.15s ease,
        background-color 0.15s ease;
}

.survey-option input {
    flex-shrink: 0;
    margin: 0;
    cursor: pointer;
}

/* :has() dipakai sebagai penegas saja. Kalau browsernya belum mendukung, radio
   bawaan tetap terlihat tercentang — jadi responden tidak pernah kehilangan
   informasi mana yang sudah dipilih, cuma sorotannya yang tidak muncul. */
.survey-option:has(input:checked) {
    border-color: #7367f0;
    background-color: rgba(115, 103, 240, 0.06);
    color: #5d596c;
    font-weight: 600;
}

.survey-option:has(input:focus-visible) {
    outline: 2px solid #7367f0;
    outline-offset: 2px;
}

@media (hover: hover) {
    .survey-option:hover {
        border-color: #d5d0fb;
        background-color: rgba(115, 103, 240, 0.04);
    }
}

.survey-option:active {
    transform: scale(0.995);
}

/* ---------- Isian bebas ---------- */

.survey-count {
    margin: 0.35rem 0 0;
    color: #a5a3ae;
    font-size: 0.75rem;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.survey-count.is-limit {
    color: #ea5455;
    font-weight: 600;
}

/* ---------- Keadaan salah ---------- */

/* Pertanyaan wajib yang terlewat ditandai di tempatnya, bukan cuma disebut di
   kotak dialog yang langsung hilang begitu ditutup. */
.survey-q.is-error {
    border-color: rgba(234, 84, 85, 0.5);
    box-shadow: 0 0 0 1px rgba(234, 84, 85, 0.12);
}

.survey-q__error {
    display: none;
    align-items: center;
    gap: 0.35rem;
    margin: 0.625rem 0 0;
    color: #ea5455;
    font-size: 0.8125rem;
    font-weight: 600;
}

.survey-q.is-error .survey-q__error {
    display: flex;
}

.survey-q.is-error .survey-option,
.survey-q.is-error .form-control {
    border-color: rgba(234, 84, 85, 0.4);
}

/* Fokus sengaja dipindahkan ke pertanyaan bermasalah (dan ke panel terima
   kasih) supaya pembaca layar langsung membacakannya. Cincin fokus bawaan
   dimatikan di sini karena perpindahannya tidak dimulai dari papan ketik:
   penanda merah di atas sudah menyatakan keadaannya, dan cincin hitam tebal
   justru bersaing dengan penanda itu. Fokus dari papan ketik tetap terlihat
   lewat :focus-visible pada isian dan pilihan di dalamnya. */
.survey-q:focus,
.survey-state:focus {
    outline: none;
}

/* ---------- Tombol kirim ---------- */

.survey-actions {
    display: flex;
    align-items: center;
    margin-top: 1rem;
    padding: 1.125rem;
}

.survey-actions .btn {
    width: 100%;
    min-height: 2.75rem;
    padding-inline: 1.5rem;
    font-weight: 600;
}

/* ---------- Panel keadaan (tertutup / sudah diisi / terima kasih) ---------- */

.survey-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    padding: 2.5rem 1.5rem;
    text-align: center;
}

.survey-state__icon {
    display: grid;
    place-items: center;
    width: 3.5rem;
    height: 3.5rem;
    margin-bottom: 0.25rem;
    border-radius: 50%;
    background-color: rgba(115, 103, 240, 0.1);
    color: #7367f0;
    font-size: 1.75rem;
}

.survey-state__icon--sukses {
    background-color: rgba(40, 199, 111, 0.12);
    color: #28c76f;
}

.survey-state__icon--tutup {
    background-color: rgba(255, 159, 67, 0.12);
    color: #ff9f43;
}

.survey-state__title {
    margin: 0;
    color: #5d596c;
    font-size: 1.125rem;
    font-weight: 700;
}

.survey-state__text {
    margin: 0;
    max-width: 28rem;
    color: #6f6b7d;
    font-size: 0.9375rem;
    line-height: 1.6;
    text-wrap: pretty;
}

.survey-state .btn {
    margin-top: 0.75rem;
}

@media (prefers-reduced-motion: reduce) {
    .survey-option,
    .survey-progress__bar {
        transition: none;
    }

    .survey-option:active {
        transform: none;
    }
}

/* --------------------------------------------------------------------------
   Tabel data admin (dipakai tabel pinjaman di halaman /pinjaman)

   Kelas-kelas ini dipasang dari PHP, di PinjamanController::getData(), karena
   isi selnya memang dirakit di sisi server oleh DataTables.

   Yang dikejar: satu baris tabel bisa dibaca sekali lihat. Kolomnya sudah
   digabung dari dua belas jadi tujuh, jadi tiap sel sekarang memuat beberapa
   baris teks — dan susunan tiga tingkat inilah yang menjaganya tetap terbaca:

     tingkat 1  isi utama       gelap, tebal   (organisasi, acara, tanggal)
     tingkat 2  isi pendukung   abu, kecil     (nama peminjam, jam, keterangan)
     tingkat 3  penanda         chip berwarna  (ruangan, status, berkas)

   Palet dan sudutnya sama dengan blok lain di berkas ini: ungu #7367f0,
   judul #5d596c, teks sekunder #6f6b7d, chip 6px.
   -------------------------------------------------------------------------- */

/* Sel bisa setinggi tiga baris, jadi isinya dirata-tengah supaya baris tabel
   tidak terlihat berat sebelah. Padding ditambah karena baris yang rapat justru
   makin sulit dibaca begitu tiap selnya berisi lebih dari satu baris. */
table.pinjaman > tbody > tr > td {
    padding-block: 0.75rem;
    vertical-align: middle;
}

table.pinjaman > thead > tr > th,
table.ruangan > thead > tr > th,
table.pengguna > thead > tr > th,
table.table-post > thead > tr > th {
    /* judul kolom tidak ikut mengecil jadi dua baris di layar sempit */
    white-space: nowrap;
    color: #5d596c;
}

.tabel-potong {
    /* dipotong dua baris, teks penuhnya tetap ada di atribut title supaya bisa
       dibaca lewat tooltip tanpa melebarkan kolom */
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
    /* batas lebar sel: tanpa ini satu acara berjudul panjang bisa menggencet
       semua kolom lain sampai tabelnya harus digeser ke samping */
    max-width: 22rem;
}

.tabel-chip {
    display: inline-flex;
    align-items: center;
    margin-top: 0.25rem;
    padding: 0.2rem 0.45rem;
    border-radius: 6px;
    font-size: 0.6875rem;
    font-weight: 600;
}

.tabel-status {
    display: inline-flex;
    align-items: center;
    padding: 0.25rem 0.55rem;
    border-radius: 6px;
    font-size: 0.75rem;
    font-weight: 600;
}

/* Tombol berkas dibuat sekecil chip: di dalam tabel ia penanda "ada lampiran",
   bukan ajakan utama — tombol seukuran biasa akan menyaingi menu aksi. */
.tabel-berkas {
    display: inline-flex;
    align-items: center;
    padding: 0.2rem 0.5rem;
    border-radius: 6px;
    font-size: 0.6875rem;
    font-weight: 600;
    line-height: 1.4;
}

/* Angka jam disamakan lebarnya supaya rentang waktu antar baris sejajar dan
   enak dipindai dari atas ke bawah. nowrap menjaga satu rentang waktu tetap
   utuh dalam satu baris — "s.d 20 Agt 2026, 16.00 WIB" yang patah di tengah
   terbaca seperti dua tanggal yang berbeda. */
.tabel-angka {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.tabel-hubungi {
    text-decoration: none;
}

.tabel-hubungi:hover,
.tabel-hubungi:focus-visible {
    color: #28c76f !important;
}

/* ---------- Baris penyaring di atas tabel ---------- */

.tabel-filter {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 1rem;
}

.tabel-filter__label {
    margin: 0;
    color: #6f6b7d;
    font-size: 0.8125rem;
    font-weight: 600;
}

/* Status dipilih lewat tombol, bukan menu turun: pilihannya cuma lima dan
   semuanya perlu terlihat sekaligus.

   Rupanya sengaja diserahkan penuh ke tombol bawaan Vuexy: yang tidak dipilih
   .btn-outline-secondary, yang sedang dipilih .btn-primary (ditukar dari JS).
   Tidak ada aturan warna/garis di sini karena custom.css dimuat SETELAH
   core.css — satu baris `background-color` saja di .tabel-filter__pil sudah
   cukup untuk menimpa .btn-primary dan membuat tombol terpilih tidak berwarna.
   Kelas .tabel-filter__pil dibiarkan tanpa gaya, dipakai JS sebagai pegangan. */
.tabel-filter__pil {
    border-radius: 999px;
}

/* ---------- Isi pesan di detail log pengiriman ---------- */

/* Pesan WhatsApp bermakna lewat baris barunya (salam, isi, tautan), jadi
   ditampilkan apa adanya — bukan diratakan jadi satu paragraf. */
.log-pesan {
    margin: 0;
    padding: 0.75rem 0.875rem;
    border: 1px solid #e7e7e9;
    border-radius: 0.5rem;
    background-color: #f8f7fa;
    color: #5d596c;
    font-family: inherit;
    font-size: 0.8125rem;
    line-height: 1.6;
    white-space: pre-wrap;
    word-break: break-word;
}

/* --------------------------------------------------------------------------
   Footer halaman publik

   Memakai token yang sama dengan blok agenda di atas (primary #7367f0, judul
   #5d596c, teks sekunder #6f6b7d, garis #dbdade). Versi pertama footer ini
   memakai permukaan gelap dengan tiga abu-abu karangan sendiri — persis palet
   ketiga yang dihindari blok agenda. Permukaan putih dengan garis atas juga
   membuat footer terbaca sebagai kelanjutan kartu-kartu di atasnya, bukan
   potongan halaman dari produk lain.
   -------------------------------------------------------------------------- */

.footer-publik {
    margin-top: 4rem;
    padding: 3rem 0 1.5rem;
    border-top: 1px solid #dbdade;
    background-color: #fff;
    color: #6f6b7d;
    font-size: 0.875rem;
}

.footer-publik__brand {
    display: inline-flex;
    align-items: center;
    gap: 0.625rem;
    margin-bottom: 0.75rem;
    color: #5d596c;
    font-size: 1.25rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    text-decoration: none;
}

.footer-publik__brand:hover,
.footer-publik__brand:focus-visible {
    color: #7367f0;
}

.footer-publik__deskripsi {
    max-width: 34ch;
    margin: 0;
    line-height: 1.7;
}

/* Judul kolom sengaja jauh lebih kecil dari .agenda-head__title: keduanya
   memakai warna dan bobot yang sama, tapi footer bukan bagian yang harus
   menarik mata lebih dulu daripada isi halaman. */
.footer-publik__judul {
    margin-bottom: 0.875rem;
    color: #5d596c;
    font-size: 0.8125rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.footer-publik__tautan,
.footer-publik__kontak {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.footer-publik__tautan a,
.footer-publik__kontak a,
.footer-publik__kosong a,
.footer-publik__ke-atas {
    color: #6f6b7d;
    text-decoration: none;
    transition: color 0.15s ease;
}

.footer-publik__tautan a:hover,
.footer-publik__kontak a:hover,
.footer-publik__kosong a:hover,
.footer-publik__ke-atas:hover {
    color: #7367f0;
}

/* Garis fokus disamakan dengan kartu agenda: 2px solid primary, offset 2px.
   Tanpa ini satu-satunya penanda fokus keyboard di footer adalah perubahan
   warna teks — terlalu tipis untuk diandalkan. */
.footer-publik a:focus-visible {
    outline: 2px solid #7367f0;
    outline-offset: 2px;
    border-radius: 4px;
    color: #7367f0;
}

/* Ikon disejajarkan ke baris pertama, bukan ke tengah: alamat bisa memakan
   dua-tiga baris dan ikon yang melayang di tengahnya terbaca seperti milik
   baris yang salah. */
.footer-publik__kontak li {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    line-height: 1.6;
}

/* Warna ikon mengikuti .agenda-card__time — penanda meta di produk ini selalu
   primary, bukan abu-abu. */
.footer-publik__kontak i {
    margin-top: 0.15rem;
    color: #7367f0;
    flex-shrink: 0;
}

.footer-publik__kosong {
    margin: 0;
    line-height: 1.7;
}

.footer-publik__kosong a {
    font-weight: 600;
}

.footer-publik__bawah {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin-top: 2.5rem;
    padding-top: 1.25rem;
    border-top: 1px solid #dbdade;
    font-size: 0.8125rem;
}

.footer-publik__bawah p {
    margin: 0;
}

.footer-publik__ke-atas {
    display: inline-flex;
    align-items: center;
    gap: 0.15rem;
    font-weight: 600;
}

@media (max-width: 575.98px) {
    .footer-publik {
        padding-top: 2.25rem;
    }

    .footer-publik__bawah {
        justify-content: flex-start;
    }
}

@media (prefers-reduced-motion: reduce) {
    .footer-publik__brand,
    .footer-publik__tautan a,
    .footer-publik__kontak a,
    .footer-publik__kosong a,
    .footer-publik__ke-atas {
        transition: none;
    }
}

/* ---------- Panel perekam audio (halaman Rekaman) ---------- */

/* Kotak status memakai token yang sama dengan blok agenda (garis #dbdade,
   permukaan #f8f7fa) supaya tidak muncul palet baru di halaman ini. */
.rekam-kotak {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.875rem 1rem;
    border: 1px solid #dbdade;
    border-radius: 0.5rem;
    background-color: #f8f7fa;
}

.rekam-indikator {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    color: #6f6b7d;
    font-size: 0.8125rem;
    font-weight: 600;
}

/* Titik abu-abu saat diam, merah berdenyut saat merekam. Perekaman tidak punya
   tanda visual lain — tanpa ini satu-satunya cara tahu mikrofon masih menyala
   adalah membaca angka waktunya. */
.rekam-titik {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background-color: #a8aaae;
    flex-shrink: 0;
}

.rekam-titik--aktif {
    background-color: #ea5455;
    animation: rekam-denyut 1.2s ease-in-out infinite;
}

/* Dijeda: kuning dan DIAM. Titik yang tetap berdenyut saat dijeda terbaca
   sebagai "masih merekam" — persis salah paham yang paling mahal di sini. */
.rekam-titik--jeda {
    background-color: #ff9f43;
    animation: none;
}

@keyframes rekam-denyut {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.25; }
}

/* Angka waktu sama lebar supaya tidak bergeser tiap detik berganti. */
.rekam-waktu {
    color: #5d596c;
    font-size: 1.25rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

@media (prefers-reduced-motion: reduce) {
    .rekam-titik--aktif {
        animation: none;
    }
}

/* ---------- Halaman perekam publik (/rekam/{id}) ---------- */

/* Halaman ini dibuka orang yang tidak login, sering dari ponsel, dan sekali
   pakai. Isinya sengaja satu kartu di tengah tanpa navigasi tambahan: yang
   dituju cuma satu tindakan. */
.rekam-publik {
    padding: 3rem 0 4rem;
}

.rekam-publik__lencana {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin-bottom: 0.75rem;
    padding: 0.3rem 0.75rem;
    border-radius: 6px;
    background-color: rgba(115, 103, 240, 0.1);
    color: #7367f0;
    font-size: 0.8125rem;
    font-weight: 600;
}

.rekam-publik__judul {
    margin-bottom: 0.25rem;
    color: #5d596c;
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -0.01em;
}

.rekam-publik__meta {
    color: #6f6b7d;
    font-size: 0.875rem;
}

/* Tiga keadaan memakai bentuk yang sama dan hanya berbeda warna, supaya yang
   dibaca lebih dulu adalah kalimatnya — bukan menebak arti kotaknya. */
.rekam-publik__kabar {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.875rem 1rem;
    border: 1px solid #dbdade;
    border-radius: 0.5rem;
    background-color: #f8f7fa;
    color: #6f6b7d;
    font-size: 0.875rem;
    line-height: 1.6;
}

.rekam-publik__kabar i {
    margin-top: 0.15rem;
    font-size: 1.1rem;
    flex-shrink: 0;
}

.rekam-publik__kabar p {
    margin: 0;
}

.rekam-publik__kabar--tunggu {
    border-color: rgba(255, 159, 67, 0.35);
    background-color: rgba(255, 159, 67, 0.08);
}

.rekam-publik__kabar--tunggu i,
.rekam-publik__kabar--tunggu .fw-semibold {
    color: #ff9f43;
}

.rekam-publik__kabar--buka {
    border-color: rgba(40, 199, 111, 0.35);
    background-color: rgba(40, 199, 111, 0.08);
}

.rekam-publik__kabar--buka i,
.rekam-publik__kabar--buka .fw-semibold {
    color: #28c76f;
}

.rekam-publik__kabar--lewat i,
.rekam-publik__kabar--lewat .fw-semibold {
    color: #6f6b7d;
}

.rekam-publik__hitung {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.25rem;
    margin-top: 1.5rem;
    padding: 1rem;
    border: 1px dashed #dbdade;
    border-radius: 0.5rem;
    text-align: center;
}

.rekam-publik__hitung-angka {
    color: #5d596c;
    font-size: 1.125rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

/* ---------- Panduan sebelum merekam ---------- */

.rekam-panduan {
    padding: 0.875rem 1rem;
    border: 1px solid rgba(115, 103, 240, 0.25);
    border-radius: 0.5rem;
    background-color: rgba(115, 103, 240, 0.06);
    font-size: 0.8125rem;
    line-height: 1.6;
    color: #6f6b7d;
}

.rekam-panduan__judul {
    margin: 0 0 0.5rem;
    color: #5d596c;
    font-weight: 700;
}

.rekam-panduan__daftar {
    margin: 0;
    padding-left: 1.1rem;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

.rekam-panduan__daftar strong {
    color: #5d596c;
}

/* ---------- Perekam di layar ponsel ---------- */

/* Halaman ini dipakai sambil berdiri di ruang rapat, satu tangan memegang
   ponsel. Tombolnya dibuat selebar layar dan setinggi 48px — ukuran sasaran
   sentuh yang masih bisa ditekan tanpa melihat. */
@media (max-width: 575.98px) {
    .rekam-kotak {
        padding: 0.75rem 0.875rem;
    }

    .rekam-waktu {
        font-size: 1.5rem;
    }

    #rekam-panel .btn,
    #rekam-hasil .btn,
    #rekam-ulang {
        width: 100%;
        min-height: 48px;
        font-size: 0.9375rem;
    }

    /* Tombol berhenti harus berada tepat di bawah tombol rekam, bukan
       berdampingan: dua tombol sempit berdampingan di layar 360px membuat
       "Berhenti" gampang tertekan saat hendak menekan yang lain. */
    #rekam-panel .d-flex.flex-wrap.gap-2 {
        flex-direction: column;
    }

    .rekam-panduan {
        font-size: 0.78125rem;
    }
}

/* ---------- Keadaan "sudah direkam" di halaman publik ---------- */

.rekam-publik__kabar--selesai {
    border-color: rgba(40, 199, 111, 0.35);
    background-color: rgba(40, 199, 111, 0.08);
}

.rekam-publik__kabar--selesai i,
.rekam-publik__kabar--selesai .fw-semibold {
    color: #28c76f;
}

/* Transkripsi ditampilkan apa adanya: jeda barisnya bagian dari isinya. */
.rekam-publik__teks {
    margin: 0;
    padding: 0.875rem 1rem;
    border: 1px solid #dbdade;
    border-radius: 0.5rem;
    background-color: #f8f7fa;
    color: #5d596c;
    font-family: inherit;
    font-size: 0.8125rem;
    line-height: 1.7;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    max-height: 340px;
    overflow-y: auto;
}

@media (max-width: 575.98px) {
    .rekam-publik {
        padding: 1.5rem 0 2.5rem;
    }

    .rekam-publik .card-body {
        padding: 1.25rem !important;
    }

    .rekam-publik__judul {
        font-size: 1.25rem;
    }

    /* Label dan isinya menumpuk; dua kolom di 360px menyisakan lebar yang
       memaksa tanggal patah di tengah kata. */
    .rekam-publik dl.row dt,
    .rekam-publik dl.row dd {
        width: 100%;
        max-width: 100%;
        flex: 0 0 100%;
    }

    .rekam-publik dl.row dt {
        margin-bottom: 0.1rem;
    }

    .rekam-publik dl.row dd {
        margin-bottom: 0.75rem;
    }
}

/* --------------------------------------------------------------------------
   Notulen publik (/resume/{id})

   Halaman baca yang sering dibuka dari tautan WhatsApp, lalu diunduh sebagai
   PDF. Tokennya sama dengan blok agenda: primary #7367f0, judul #5d596c,
   teks #6f6b7d, garis #dbdade.
   -------------------------------------------------------------------------- */

.resume-publik {
    padding: 3rem 0 4rem;
}

.resume-publik__kepala {
    padding-bottom: 1rem;
    margin-bottom: 1.5rem;
    border-bottom: 2px solid #dbdade;
}

.resume-publik__lencana {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin-bottom: 0.75rem;
    padding: 0.3rem 0.75rem;
    border-radius: 6px;
    background-color: rgba(115, 103, 240, 0.1);
    color: #7367f0;
    font-size: 0.8125rem;
    font-weight: 600;
}

.resume-publik__judul {
    margin-bottom: 0.25rem;
    color: #5d596c;
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -0.01em;
}

.resume-publik__meta {
    color: #6f6b7d;
    font-size: 0.875rem;
}

.resume-publik__seksi {
    margin-bottom: 0.75rem;
    padding-bottom: 0.375rem;
    border-bottom: 1px solid #dbdade;
    color: #5d596c;
    font-size: 0.8125rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.resume-publik dl.row dt {
    color: #6f6b7d;
    font-weight: 400;
}

.resume-publik dl.row dd {
    color: #5d596c;
    margin-bottom: 0.35rem;
}

/* Ringkasan datang sebagai teks berparagraf dari model bahasa; jeda barisnya
   bagian dari isinya, jadi dipertahankan apa adanya. */
.resume-publik__isi {
    color: #5d596c;
    font-size: 0.9375rem;
    line-height: 1.8;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.resume-publik__kosong {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.875rem 1rem;
    border: 1px solid rgba(255, 159, 67, 0.35);
    border-radius: 0.5rem;
    background-color: rgba(255, 159, 67, 0.08);
    color: #6f6b7d;
    font-size: 0.875rem;
    line-height: 1.6;
}

.resume-publik__kosong i {
    margin-top: 0.15rem;
    color: #ff9f43;
    flex-shrink: 0;
}

.resume-publik__kosong p {
    margin: 0;
}

.resume-publik__kosong .fw-semibold {
    color: #ff9f43;
}

@media (max-width: 575.98px) {
    .resume-publik {
        padding: 1.5rem 0 2.5rem;
    }

    .resume-publik .card-body {
        padding: 1.25rem !important;
    }

    .resume-publik__judul {
        font-size: 1.25rem;
    }

    /* Label dan nilainya menumpuk; dua kolom di 360px memaksa tanggal patah
       di tengah kata. */
    .resume-publik dl.row dt,
    .resume-publik dl.row dd {
        width: 100%;
        max-width: 100%;
        flex: 0 0 100%;
    }

    .resume-publik dl.row dt {
        margin-bottom: 0.1rem;
    }

    .resume-publik dl.row dd {
        margin-bottom: 0.75rem;
    }
}

/* ---------- Riwayat pengiriman di modal survey ---------- */

.survey-log {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.survey-log__baris {
    padding: 0.625rem 0.75rem;
    border: 1px solid #e7e7e9;
    border-radius: 0.5rem;
    background-color: #fdfdfe;
}

/* Isi pesan disembunyikan di balik <details>: yang dicari admin hampir selalu
   cuma waktu dan status, sedangkan pesannya lima paragraf. */
.survey-log__pesan > summary {
    cursor: pointer;
    color: #7367f0;
    font-size: 0.75rem;
    margin-top: 0.375rem;
}

/* ---------- Bar aksi massal (kirim link survey) ---------- */

/* Muncul hanya saat ada baris tercentang. Warnanya sengaja setipis mungkin:
   ini bukan peringatan, hanya penanda bahwa ada pilihan yang menunggu aksi. */
.tabel-massal {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    margin-bottom: 1rem;
    padding: 0.625rem 0.875rem;
    border: 1px solid #e7e7e9;
    border-radius: 0.5rem;
    background-color: #f8f7fa;
}

/* Bootstrap .d-none memakai satu kelas, sama kuat dengan .tabel-massal di
   atas — tanpa penegasan ini barnya tetap terlihat saat belum ada pilihan. */
.tabel-massal.d-none {
    display: none !important;
}

.tabel-massal__info {
    color: #5d596c;
    font-size: 0.8125rem;
    font-weight: 600;
}

/* --------------------------------------------------------------------------
   Perbaikan tombol SweetAlert yang seharusnya tersembunyi

   SweetAlert menyembunyikan tombol yang tidak dipakai (deny/cancel) dengan
   menulis style inline `display: none`. Tapi tombolnya juga diberi kelas .btn,
   dan .btn di core.css Vuexy memakai `display: inline-flex !important` —
   !important mengalahkan style inline, jadi tombol yang seharusnya tidak ada
   tetap muncul.

   Akibatnya setiap dialog di panel admin menampilkan tombol ketiga bertuliskan
   "No" yang tidak melakukan apa-apa: dialog hapus pinjaman, konfirmasi status,
   dan seterusnya. Aturan di bawah hanya mengenai tombol yang MEMANG sudah
   ditandai tersembunyi oleh SweetAlert — tombol yang sengaja ditampilkan diberi
   `display: inline-block` inline, jadi tidak ikut terkena.
   -------------------------------------------------------------------------- */

.swal2-actions button.btn[style*="display: none"] {
    display: none !important;
}

/* --------------------------------------------------------------------------
   Formulir pinjaman

   Sepuluh ruas dalam satu kolom membuat modalnya harus digulir dua layar dan
   tidak memberi tahu apa pun tentang urutan mengisinya. Ruas-ruasnya kini
   dikelompokkan, dan judul kelompoknya dibuat setenang mungkin: cukup untuk
   memisahkan, tidak sampai bersaing dengan label ruasnya sendiri.

   Semua warnanya memakai variabel Bootstrap 5.3 yang sudah dipakai tema, jadi
   ikut berubah kalau tema terangnya ditukar.
   -------------------------------------------------------------------------- */

.form-seksi {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    margin: 1.5rem 0 1rem;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid var(--bs-border-color);
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
    font-weight: 600;
}

/* Kelompok pertama menempel ke atas badan modal; jaraknya sudah diberi oleh
   .modal-body sendiri. */
.modal-body > .form-seksi:first-of-type {
    margin-top: 0;
}

/* Flatpickr membungkus ruasnya dengan .flatpickr-wrapper agar kalender static
   punya tempat bergantung, dan bawaannya inline-block — kalau dibiarkan,
   kotak tanggalnya berhenti selebar isinya dan tidak lagi sejajar dengan ruas
   lain di barisnya. */
.flatpickr-wrapper {
    display: block;
}

/* Ruas yang salah di dalam .input-group: Bootstrap hanya memerahkan kotak
   isiannya, sementara kotak ikon atau satuan di sebelahnya tetap kelabu —
   sambungannya jadi terlihat separuh merah separuh kelabu. Dua pemilih:
   yang pertama untuk satuan yang berada SETELAH isian ("orang"), yang kedua
   untuk ikon yang berada SEBELUM isian (lambang WhatsApp). */
.input-group > .form-control.is-invalid ~ .input-group-text,
.input-group:has(> .form-control.is-invalid) > .input-group-text {
    border-color: var(--bs-form-invalid-border-color);
}

/* --------------------------------------------------------------------------
   Halaman ruangan

   Gambar kecil di dalam tabel. Sebelumnya <img width="100px"> tanpa batas
   tinggi: foto potret membuat barisnya jauh lebih jangkung daripada baris
   lain, dan tinggi baris jadi berbeda-beda sepanjang tabel.
   -------------------------------------------------------------------------- */

.tabel-gambar {
    flex-shrink: 0;
    width: 44px;
    height: 44px;
    border-radius: 6px;
    border: 1px solid var(--bs-border-color);
    object-fit: cover;
}

/* Ruangan yang belum punya foto: kotak seukuran sama supaya nama ruangan di
   sebelahnya tetap sejajar antar baris. Dulu src-nya tetap ditulis meski
   kolomnya kosong, jadi yang muncul ikon gambar rusak bawaan peramban. */
.tabel-gambar--kosong {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-style: dashed;
    color: var(--bs-secondary-color);
}

/* Pratinjau foto di dalam formulir. Rasionya dikunci supaya tiga kotak foto
   tetap sejajar berapa pun ukuran gambar yang dipilih. */
.foto-pratinjau {
    position: relative;
    aspect-ratio: 4 / 3;
    /* Di layar sempit ketiga kolom foto turun jadi selebar layar penuh; tanpa
       batas ini satu kotak pratinjau saja sudah setinggi 300px dan formulirnya
       jadi jauh lebih panjang daripada isinya. */
    max-height: 160px;
    overflow: hidden;
    border: 1px solid var(--bs-border-color);
    border-radius: 6px;
}

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

/* Kotak yang belum ada fotonya: garis putus-putus supaya jelas ini tempat
   kosong, bukan gambar yang gagal dimuat. */
.foto-pratinjau--kosong {
    border-style: dashed;
}

.foto-pratinjau__tanda {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--bs-secondary-color);
    font-size: 1.25rem;
}

/* --------------------------------------------------------------------------
   Editor konten (CKEditor) di dalam modal
   -------------------------------------------------------------------------- */

/* Bilah alat, menu, dan kotak dialog CKEditor digambar di luar modal dan
   memakai lapisan tersendiri. Lapisan bawaannya berada DI BAWAH modal
   Bootstrap (1055), jadi tanpa penyetelan ini menu "Sisip gambar" atau kotak
   tautan tertutup badan modalnya sendiri. */
:root {
    --ck-z-default: 1100;
    --ck-z-modal: calc(var(--ck-z-default) + 999);
    --ck-z-panel: calc(var(--ck-z-default) + 999);
}

/* Ruas konten yang belum diisi. Kotak editornya bukan .form-control, jadi
   .is-invalid bawaan Bootstrap tidak mengenainya. */
.editor-galat .ck.ck-editor__main > .ck-editor__editable {
    border-color: var(--bs-form-invalid-border-color);
}
