/* ============================================================================
   student.css — Pola khas Panel Siswa MasterOlimp, di atas Material Design 3

   Urutan muat (layout/master.blade.php):
       bootstrap.min.css → m3-tokens.css → m3.css → student.css

   Berkas ini sengaja TIDAK lagi memuat sistem desain sendiri. Tombol, kartu,
   kolom isian, badge, menu, dialog, tab, dan tipografi kini milik m3.css.
   Yang tinggal di sini hanya pola yang memang khas produk ini dan tidak punya
   padanan langsung di M3:

       kanvas berambience brand · hero · kartu aktivitas · panel filter
       nada "silver" untuk program yang sudah berakhir · tema Select2
       tabel yang berubah jadi kartu di layar sempit

   ── Lapisan alias ──
   Blok pertama memetakan seluruh nama token lama `--rb-*` ke role M3. Sekitar
   2.300 baris CSS inline yang tersebar di 20 view halaman masih memanggil
   nama-nama itu; dengan alias ini semuanya ikut berpindah ke palet M3 tanpa
   satu pun view perlu disunting serentak. Alias adalah jembatan, bukan tujuan:
   tulisan baru sebaiknya langsung memakai `--md-sys-*`.
   ============================================================================ */


/* ============================================================
   FONT — Inter, dimuat lokal (tanpa CDN)

   Alias 'Poppins' dipertahankan: sejumlah selektor lama masih menyebut nama
   itu, dan mengarahkannya ke berkas Inter lebih aman daripada memburu setiap
   penyebutannya.
   ============================================================ */
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('../assets/fonts/inter/inter-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('../assets/fonts/inter/inter-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: 'Poppins';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('../assets/fonts/inter/inter-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}


/* ============================================================
   ALIAS — nama token lama → role M3

   Setiap baris di bawah adalah satu keputusan pemetaan, bukan sekadar
   penggantian nama. Yang paling berpengaruh:

     --rb-surface   dulu putih polos, kini surface-container-low. Di M3
                    hierarki dibawa oleh TINGKAT permukaan, bukan oleh
                    bayangan — jadi kartu memang harus duduk satu tingkat di
                    atas kanvas.
     --rb-control-h dulu 34px, kini 40px (baku M3). Ini yang membuat baris
                    daftar dan toolbar filter tumbuh; disengaja, demi target
                    sentuh 48px.
     --rb-radius    dulu 16px, kini corner-large yang juga 16px — kebetulan
                    sama, jadi bentuk kartu nyaris tidak berubah.
   ============================================================ */
:root {
    /* Skala biru — dipetakan ke tone palet primary yang setara. */
    --rb-blue-50:  var(--md-ref-palette-primary-95);
    --rb-blue-100: var(--md-ref-palette-primary-90);
    --rb-blue-200: var(--md-ref-palette-primary-80);
    --rb-blue-300: var(--md-ref-palette-primary-70);
    --rb-blue-400: var(--md-ref-palette-primary-60);
    --rb-blue-500: var(--md-sys-color-primary);
    --rb-blue-600: var(--md-ref-palette-primary-30);
    --rb-blue-700: var(--md-ref-palette-primary-30);
    --rb-blue-800: var(--md-ref-palette-primary-20);
    --rb-navy:     var(--md-brand-navy);
    --rb-navy-900: var(--md-brand-navy-dim);
    --rb-cyan:     var(--md-sys-color-secondary);
    --rb-cyan-400: var(--md-sys-color-secondary);

    /* Emas. --rb-gold-500 sengaja menunjuk ke gold brand yang dipatok
       (tone 70 = warna seed logo), bukan ke role `tertiary` yang oleh M3
       diturunkan ke tone 40 demi kontras dan membaca perunggu. */
    --rb-gold-300: var(--md-ref-palette-tertiary-90);
    --rb-gold-400: var(--md-brand-gold-bright);
    --rb-gold-500: var(--md-brand-gold);
    --rb-gold-600: var(--md-brand-on-gold-container);
    --rb-gold-700: var(--md-brand-on-gold);

    /* Silver — nada "sudah berakhir". Tidak ada padanannya di M3 (skema M3
       hanya punya satu keluarga netral), jadi diturunkan dari netral M3
       supaya tetap satu keluarga dengan permukaan di sekitarnya. */
    --rb-silver-300: var(--md-sys-color-surface-container-high);
    --rb-silver-400: var(--md-sys-color-outline-variant);
    --rb-silver-500: var(--md-sys-color-outline);
    --rb-silver-600: var(--md-sys-color-on-surface-variant);
    --rb-silver-700: var(--md-sys-color-on-surface-variant);

    /* Semantik */
    --rb-success:   #146c2e;
    --rb-success-2: #2f7d43;
    --rb-danger:    var(--md-sys-color-error);
    --rb-danger-2:  var(--md-sys-color-error);
    --rb-warning:   var(--md-brand-gold);
    --rb-info:      var(--md-sys-color-secondary);
    --rb-purple:    #6750a4;
    --rb-pink:      #984061;
    --rb-teal:      #00695f;

    /* Gradien — hanya hero dan drawer yang masih memakainya. */
    --rb-grad-brand:      var(--md-brand-grad-primary);
    --rb-grad-brand-deep: var(--md-brand-grad-navy);
    --rb-grad-gold:       var(--md-brand-grad-gold);
    --rb-grad-navy:       var(--md-brand-grad-navy);
    --rb-grad-silver:     linear-gradient(135deg, var(--md-sys-color-surface-container-high) 0%, var(--md-sys-color-surface-container-highest) 45%, var(--md-sys-color-outline-variant) 100%);
    --rb-grad-success:    linear-gradient(135deg, #146c2e 0%, #2f7d43 100%);
    --rb-grad-danger:     linear-gradient(135deg, var(--md-sys-color-error) 0%, var(--md-sys-color-error) 100%);

    /* Kanvas */
    --rb-bg: var(--md-sys-color-surface);

    /* Teks di atas kanvas. Kanvas kini permukaan M3 biasa (terang di mode
       terang, gelap di mode gelap), jadi teksnya cukup mengikuti on-surface —
       tidak lagi perlu "selalu terang" seperti saat kanvasnya selalu navy. */
    --rb-on-canvas:       var(--md-sys-color-on-surface);
    --rb-on-canvas-muted: var(--md-sys-color-on-surface-variant);
    --rb-on-canvas-soft:  var(--md-sys-color-on-surface-variant);
    --rb-on-canvas-link:  var(--md-sys-color-primary);
    --rb-on-canvas-link-h:var(--md-sys-color-on-primary-container);
    --rb-on-canvas-brd:   var(--md-sys-color-outline);
    --rb-on-canvas-fill:  transparent;
    --rb-on-canvas-grad:  var(--md-brand-grad-primary);

    --rb-price: var(--md-brand-on-gold-container);
    --rb-loading-veil: color-mix(in srgb, var(--md-sys-color-surface) 66%, transparent);

    /* Permukaan bertingkat */
    --rb-surface:   var(--md-sys-color-surface-container-low);
    --rb-surface-2: var(--md-sys-color-surface-container);
    --rb-surface-3: var(--md-sys-color-surface-container-high);
    --rb-text:        var(--md-sys-color-on-surface);
    --rb-text-muted:  var(--md-sys-color-on-surface-variant);
    --rb-text-soft:   var(--md-sys-color-on-surface-variant);
    --rb-heading:     var(--md-sys-color-on-surface);
    --rb-border:    var(--md-sys-color-outline-variant);
    --rb-border-2:  var(--md-sys-color-outline-variant);

    /* Elevasi → level M3 */
    --rb-shadow-sm: var(--md-sys-elevation-level1);
    --rb-shadow:    var(--md-sys-elevation-level2);
    --rb-shadow-lg: var(--md-sys-elevation-level3);
    --rb-glow-brand: var(--md-sys-elevation-level2);
    --rb-glow-gold:  var(--md-sys-elevation-level2);
    --rb-glow-silver:var(--md-sys-elevation-level1);

    /* Geometri → shape M3 */
    --rb-control-h: var(--md-control-height);
    --rb-radius:    var(--md-sys-shape-corner-large);
    --rb-radius-sm: var(--md-sys-shape-corner-medium);
    --rb-radius-lg: var(--md-sys-shape-corner-large);
    --rb-radius-xl: var(--md-sys-shape-corner-extra-large);

    /* Glass — M3 tidak mengenal permukaan kaca; efeknya dilepas dan diganti
       permukaan tonal. Nama tokennya dipertahankan agar markup lama aman. */
    --rb-glass-bg:  var(--md-sys-color-surface-container);
    --rb-glass-brd: var(--md-sys-color-outline-variant);
    --rb-glass-blur: 0px;

    --rb-header-bg: var(--md-sys-color-surface);
}
[data-theme="dark"] {
    --rb-success:   #7ddb8f;
    --rb-success-2: #7ddb8f;
    --rb-purple:    #cfbcff;
    --rb-pink:      #ffb1c8;
    --rb-teal:      #4fdbc8;
    --rb-grad-success: linear-gradient(135deg, #29532f 0%, #33663b 100%);
    --rb-gold-600: var(--md-brand-gold-bright);
    --rb-price: var(--md-brand-gold-bright);
    --rb-blue-600: var(--md-ref-palette-primary-90);
    --rb-blue-700: var(--md-ref-palette-primary-90);
}


/* ============================================================
   KANVAS — permukaan M3 datar + ambience brand yang ditipiskan

   Ini bagian "dikombinasikan": bidangnya sudah permukaan M3 polos, tetapi
   tiga lapis ambience dari desain lama dipertahankan — sapuan radial emas &
   biru, kisi blueprint, dan dua orb mengambang. Opasitasnya diturunkan
   drastis (dulu .40/.55 untuk orb; kini .16/.24) sehingga terbaca sebagai
   karakter latar, bukan sebagai tekstur yang bersaing dengan isi.
   ============================================================ */
body {
    font-family: var(--md-sys-typescale-plain);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
    color: var(--md-sys-color-on-surface);
    background-color: var(--md-sys-color-surface);
    background-image:
        radial-gradient(760px 560px at 92% 94%, color-mix(in srgb, var(--md-brand-gold) 10%, transparent), transparent 55%),
        radial-gradient(820px 640px at 6% 82%, color-mix(in srgb, var(--md-sys-color-primary) 8%, transparent), transparent 55%),
        radial-gradient(720px 720px at 22% -8%, color-mix(in srgb, var(--md-brand-gold) 7%, transparent), transparent 60%);
    background-attachment: fixed;
    background-repeat: no-repeat;
}
/* Dark mode: kanvas jadi NAVY, resep gradien yang sama persis dengan halaman
   masuk. Chroma netral yang dinaikkan sudah membuat surface bernada navy;
   gradien ini menegaskannya dan menyatukan latar panel dengan latar login. */
[data-theme="dark"] body {
    background-color: var(--md-brand-navy);
    background-image:
        radial-gradient(760px 560px at 92% 94%, color-mix(in srgb, var(--md-brand-gold) 14%, transparent), transparent 55%),
        radial-gradient(820px 640px at 6% 82%, color-mix(in srgb, var(--md-sys-color-primary) 22%, transparent), transparent 55%),
        radial-gradient(720px 720px at 22% -8%, color-mix(in srgb, var(--md-brand-gold) 9%, transparent), transparent 60%),
        var(--md-brand-grad-navy);
}
/* Kisi blueprint — parameter sama dengan halaman login supaya kedua permukaan
   terbaca satu produk. */
body::before {
    content: '';
    position: fixed; inset: 0; z-index: 0; pointer-events: none;
    background-image:
        linear-gradient(color-mix(in srgb, var(--md-sys-color-outline) 22%, transparent) 1px, transparent 1px),
        linear-gradient(90deg, color-mix(in srgb, var(--md-sys-color-outline) 22%, transparent) 1px, transparent 1px);
    background-size: 46px 46px;
    -webkit-mask-image: radial-gradient(circle at 50% 60%, #000 30%, transparent 78%);
    mask-image: radial-gradient(circle at 50% 60%, #000 30%, transparent 78%);
    opacity: .5;
}
.auth-orb {
    position: fixed; border-radius: 50%; filter: blur(8px);
    z-index: 0; pointer-events: none;
    opacity: .16;
}
[data-theme="dark"] .auth-orb { opacity: .24; }
.auth-orb.o1 {
    width: 210px; height: 210px; bottom: 8%; right: 6%;
    background: radial-gradient(circle at 35% 30%, var(--md-brand-gold-bright), transparent 70%);
    animation: rb-floaty 13s ease-in-out infinite;
}
.auth-orb.o2 {
    width: 260px; height: 260px; top: 6%; left: 8%;
    background: radial-gradient(circle at 35% 30%, var(--md-sys-color-primary), transparent 70%);
    animation: rb-floaty 17s ease-in-out infinite reverse;
}
@keyframes rb-floaty {
    0%, 100% { transform: translate(0, 0); }
    50%      { transform: translate(14px, -22px); }
}
@media (prefers-reduced-motion: reduce) { .auth-orb { animation: none; } }


/* ============================================================
   TIPOGRAFI PRODUK

   Empat kelas pembantu yang dipakai di hampir setiap view. Nilainya kini
   diturunkan dari typescale M3, bukan angka lepas.
   ============================================================ */
.rb-display {
    font: 600 var(--md-sys-typescale-headline-medium-size)/var(--md-sys-typescale-headline-medium-line-height) var(--md-sys-typescale-brand);
    letter-spacing: -.02em;
}
.rb-eyebrow {
    display: block;
    font: var(--md-sys-typescale-label-medium-weight) var(--md-sys-typescale-label-medium-size)/var(--md-sys-typescale-label-medium-line-height) var(--md-sys-typescale-plain);
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--md-sys-color-on-surface-variant);
}
.rb-title {
    font: var(--md-sys-typescale-title-medium-weight) var(--md-sys-typescale-title-medium-size)/var(--md-sys-typescale-title-medium-line-height) var(--md-sys-typescale-plain);
    color: var(--md-sys-color-on-surface);
}
.rb-meta {
    font: 400 var(--md-sys-typescale-body-small-size)/var(--md-sys-typescale-body-small-line-height) var(--md-sys-typescale-plain);
    color: var(--md-sys-color-on-surface-variant);
}

/* Teks bergradien. Dipertahankan hanya untuk hero & judul kanvas — di tempat
   lain M3 menghendaki warna role yang rata. */
.rb-text-gradient {
    background-image: var(--md-brand-grad-primary);
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent; color: transparent;
}
.rb-text-gold {
    background-image: var(--md-brand-grad-gold);
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent; color: transparent;
}
.rb-gold { color: var(--md-brand-on-gold-container) !important; }
[data-theme="dark"] .rb-gold { color: var(--md-brand-gold-bright) !important; }

.bg-rb-grad      { background: var(--md-brand-grad-primary) !important; }
.bg-rb-grad-deep { background: var(--md-brand-grad-navy) !important; }
.bg-rb-gold      { background: var(--md-brand-grad-gold) !important; }

/* Nominal rupiah tidak boleh terpotong antara "Rp" dan angkanya. */
.rb-amount, .ord-amount, .pay-amount, .cat-price,
.db-stat-value, .stat-card .stat-value, .stat-val { white-space: nowrap; }

.rb-price { color: var(--rb-price); font-weight: 600; }

/* Utilitas yang tidak dikirim Bootstrap 5 tapi dipakai banyak view sebagai
   pasangan .text-truncate di dalam flexbox. */
.min-w-0 { min-width: 0 !important; }
.fw-600  { font-weight: 600 !important; }

/* Kelas kaca lama → permukaan tonal M3. */
.rb-glass {
    background: var(--md-sys-color-surface-container);
    border: 1px solid var(--md-sys-color-outline-variant);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
}

/* No-op yang dipertahankan: 31 view memakainya sebagai penanda garis aksen
   atas yang sudah lama dihapus. Dibiarkan kosong agar tidak perlu disunting
   serentak. */
.rb-accent-top { position: relative; }

.rb-hover-lift { cursor: pointer; }
.rb-hover-lift:hover { box-shadow: var(--md-sys-elevation-level2); }

/* Teks di atas kanvas — kanvas kini permukaan biasa, jadi aturannya menyusut
   jadi sekadar memastikan kepala halaman memakai role yang benar. */
.page-header h1, .page-header h2, .page-header h3,
.page-header h4, .page-header h5, .page-header h6,
.page-header .page-title,
.rb-on-canvas, .rb-on-canvas h1, .rb-on-canvas h2, .rb-on-canvas h3,
.rb-on-canvas h4, .rb-on-canvas h5, .rb-on-canvas h6 { color: var(--md-sys-color-on-surface); }
.page-header p, .page-header small,
.page-header .text-muted, .page-header .breadcrumb-item.active,
.rb-on-canvas p, .rb-on-canvas small, .rb-on-canvas .text-muted { color: var(--md-sys-color-on-surface-variant) !important; }


/* ============================================================
   HERO — resep "panji navy" halaman masuk, dibawa ke seluruh halaman konten

   Inilah tampilan .auth-head halaman login yang diminta dipakai di mana-mana:
   bidang navy bergradien, satu garis rambut EMAS di tepi bawah, dan pendar
   putih lembut di sudut kanan-atas. Tiga elemen itulah tanda khasnya.

   Struktur pseudo-nya identik dengan login supaya benar-benar satu wajah:
       ::before  pendar sudut (auth-head memakai ::after)
       ::after   garis rambut emas (auth-head memakai ::before)
   Dipakai lewat <x-siswa-hero>, atau markup manual .rb-hero > .rb-hero-content
   di halaman yang butuh isi tambahan (Katalog, Paket Soal, Dashboard, Profil
   — .db-hero/.pf-hero di situ hanya modifier tata letak, BUKAN implementasi
   terpisah). katalog/show.blade.php (.cd-hero) belum dipindahkan ke sini.

   Navy selalu gelap di kedua tema — sama seperti drawer dan logo di atasnya.
   ============================================================ */
.rb-hero {
    position: relative;
    overflow: hidden;
    isolation: isolate;
    padding: 24px;
    margin-bottom: 16px;
    border-radius: var(--md-sys-shape-corner-extra-large);
    background: var(--md-brand-navy);
    background-image: var(--md-brand-grad-navy);
    color: var(--md-brand-on-navy);
}
/* Pendar sudut kanan-atas — sama dengan .auth-head::after. */
.rb-hero::before {
    content: '';
    position: absolute; top: -120px; right: -70px; z-index: 0;
    width: 230px; height: 230px; border-radius: 50%;
    background: radial-gradient(circle at 35% 35%, rgba(255,255,255,.20), transparent 68%);
    pointer-events: none;
}
/* Garis rambut emas di tepi bawah — sama dengan .auth-head::before. */
.rb-hero::after {
    content: '';
    position: absolute; left: 0; right: 0; bottom: 0; height: 3px; z-index: 2;
    background: linear-gradient(90deg, transparent, var(--md-brand-gold) 25%, var(--md-brand-gold-bright) 50%, var(--md-brand-gold) 75%, transparent);
    pointer-events: none;
}
.rb-hero-content { position: relative; z-index: 1; }
/* Watermark ditambatkan ke TENGAH tepi kanan, bukan sudut bawah — supaya
   selalu terlihat berapa pun tinggi hero (sejak subjudul dihapus, hero bisa
   sangat pendek dan jangkar-bawah membuatnya nyaris hilang). Ukurannya dibatasi
   clamp agar tidak melebihi tinggi hero yang ringkas. */
.rb-hero-watermark {
    position: absolute; right: 1rem; top: 50%; transform: translateY(-50%); z-index: 0;
    font-size: clamp(3.25rem, 9vw, 5rem); line-height: 1;
    color: var(--md-brand-gold);
    opacity: .16;
    pointer-events: none; user-select: none;
}
/* Watermark berupa GAMBAR (pemilik 29 Okt 2026): logo MasterOlimp di Katalog,
   logo lomba di halaman satu Olimp. Tingginya mengikuti ukuran ikon di atas.
   --mo = ikon MasterOlimp (PNG transparan, berwarna): cukup diredam.
   --olimp = logo lomba (PNG RGB berlatar PUTIH): dibalik jadi terang lalu
   di-screen, sehingga latar putihnya (kini hitam) lenyap di atas navy — trik
   yang sama dengan watermark kartu Olimp di mode gelap. Hero ber-isolation,
   jadi pembaurannya tak tembus ke halaman. */
.rb-hero-watermark--img {
    width: auto; height: clamp(3.4rem, 9vw, 5.25rem);
    max-width: 38%; object-fit: contain; object-position: right center;
    font-size: 0;
}
.rb-hero-watermark--mo { opacity: .3; }
.rb-hero-watermark--olimp { opacity: .26; filter: grayscale(1) invert(1); mix-blend-mode: screen; }
.rb-hero-eyebrow {
    color: var(--md-brand-on-navy-variant) !important;
    margin-bottom: 4px;
}
.rb-hero-title,
.rb-hero h1, .rb-hero h2, .rb-hero h3,
.rb-hero h4, .rb-hero h5, .rb-hero h6 {
    font: 600 var(--md-sys-typescale-headline-small-size)/var(--md-sys-typescale-headline-small-line-height) var(--md-sys-typescale-brand);
    letter-spacing: -.015em;
    color: var(--md-brand-on-navy);
    margin: 0;
}
/* Kata beraksen di judul → teks emas, sebahasa dengan garis rambut. */
.rb-hero-gold {
    background-image: linear-gradient(135deg, var(--md-brand-gold-bright) 0%, var(--md-brand-gold) 100%);
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent; color: transparent;
}
/* Garis kini duduk DI ANTARA eyebrow dan judul — jaraknya dibalik: rapat ke
   eyebrow di atas, sedikit lega ke judul di bawah. */
.rb-hero-divider {
    width: 44px; height: 3px;
    border-radius: var(--md-sys-shape-corner-full);
    margin: 6px 0 10px;
    background: var(--md-brand-gold);
    opacity: .9;
}
.rb-hero-sub {
    font: 400 var(--md-sys-typescale-body-medium-size)/var(--md-sys-typescale-body-medium-line-height) var(--md-sys-typescale-plain);
    color: var(--md-brand-on-navy-variant);
    max-width: 52ch;
    margin: 0;
}

/* Slot `actions` opsional <x-siswa-hero>: satu tombol pil di pojok KANAN
   BAWAH hero, sejajar dengan tepi bawah teks — bukan rata-tengah vertikal
   (dulu begitu, tapi tombol pendek di sebelah judul+eyebrow yang lebih
   tinggi jadi terasa mengambang di tengah). Bedanya dengan .ps-pref/.kt-pref:
   baris ringkasan saringan itu memang berdiri SENDIRI di bawah judul,
   sedangkan slot ini tetap SEBARIS dengan teks, hanya rata ke bawahnya. */
.rb-hero-content--flex {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}
.rb-hero-main { min-width: 0; }
.rb-hero-actions { flex-shrink: 0; }

/* Prop `back` opsional <x-siswa-hero>: tombol kembali bulat sejajar dengan
   judul, dipromosikan dari .kt-back-icon/.kt-title-row yang tadinya hanya
   dipakai lokal di Katalog Olimp. (kt-hero). Sama-sama dipakai halaman detail
   (mis. rincian Transaksi) yang butuh navigasi kembali TANPA header terpisah
   di atas hero. color:inherit (bukan token navy tetap) supaya tetap benar di
   varian hero bergambar yang teksnya sudah dipaksa putih. */
.rb-hero-title-row { display: flex; align-items: center; gap: .5rem; }
.rb-hero-title-row .rb-hero-title { margin: 0; }
.rb-hero-back {
    flex-shrink: 0;
    width: 32px; height: 32px; border-radius: var(--md-sys-shape-corner-full);
    display: inline-flex; align-items: center; justify-content: center;
    color: inherit; text-decoration: none;
    border: 1px solid color-mix(in srgb, currentColor 45%, transparent);
    background: color-mix(in srgb, currentColor 8%, transparent);
    transition: background-color var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard),
                border-color var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
}
.rb-hero-back:hover {
    color: inherit;
    background: color-mix(in srgb, currentColor 18%, transparent);
    border-color: color-mix(in srgb, currentColor 70%, transparent);
}

/* Tombol pil di atas navy — dipromosikan dari .ps-pref-btn (Paket Soal) &
   .kt-pref-btn (Katalog Olimp.), yang sebelumnya dua salinan hampir identik.
   Dipakai untuk aksi sekunder di dalam hero: pembuka modal saringan
   ("Atur Tampilan"), atau tautan navigasi seperti "Dompet Koin" di halaman
   Isi Koin. `.rb-hero-pref-count` = lencana bulat opsional di sisinya (mis.
   jumlah saringan aktif). */
/* ── Ringkasan preferensi di dalam hero (.kt-pref) ────────────
   Baris fakta berikon di bawah eyebrow: "Kelas 6 · Matematika", "Olimpiade ·
   kelas 6", dan seterusnya. Dulu disalin utuh di dua berkas halaman
   (katalog/olimp & katalog/index) dengan warna yang sudah mulai berbeda —
   salinan ketiga di halaman rincian Ujian akhirnya lupa dibuat sama sekali,
   dan barisnya menumpuk ke bawah tanpa gaya apa pun. Diangkat ke sini supaya
   satu perubahan berlaku di semuanya.

   Warnanya memakai token on-navy, bukan rgba putih: hero bisa berganti nada
   (.rb-hero--gold) dan putih mentah akan hilang di atasnya. */
.kt-pref { margin-top: 14px; display: flex; flex-wrap: wrap; align-items: center; gap: 10px 18px; }
.kt-pref-lines { display: flex; flex-wrap: wrap; gap: 4px 20px; }
.kt-pref-line { display: inline-flex; align-items: baseline; gap: .45rem; font-size: .86rem; color: var(--md-brand-on-navy-variant); }
.kt-pref-line > .bi { font-size: .95rem; opacity: .7; }
.kt-pref-val { color: var(--md-brand-on-navy); font-weight: 600; }
.kt-pref-sub { font-size: .74rem; opacity: .6; }
.kt-pref-empty { font-style: italic; opacity: .8; }
/* Tombol aksi di dalam ringkasan didorong ke ujung kanan barisnya. */
.kt-pref .rb-hero-pref-btn { margin-left: auto; }

.rb-hero-pref-btn {
    display: inline-flex; align-items: center;
    border: 1px solid color-mix(in srgb, var(--md-brand-on-navy-variant) 45%, transparent);
    background: color-mix(in srgb, var(--md-brand-on-navy) 8%, transparent);
    color: var(--md-brand-on-navy); border-radius: 999px; text-decoration: none;
    padding: 5px 14px; font-size: .8rem; font-weight: 600;
    transition: background-color var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard),
                border-color var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
}
.rb-hero-pref-btn:hover {
    background: color-mix(in srgb, var(--md-brand-on-navy) 18%, transparent);
    border-color: var(--md-brand-on-navy-variant);
    color: var(--md-brand-on-navy);
}
.rb-hero-pref-count {
    margin-left: .4rem; min-width: 18px; height: 18px; padding: 0 5px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 999px; font-size: .68rem; line-height: 1;
    background: var(--md-brand-gold); color: var(--md-brand-on-gold);
}

/* Varian warna hero.

   .rb-hero--brand & .rb-hero--navy SENGAJA tidak didefinisikan ulang: keduanya
   kini SAMA dengan bentuk dasar (navy). "brand" adalah nilai bawaan prop
   <x-siswa-hero> yang dipakai hampir semua halaman, jadi membiarkannya jatuh ke
   dasar berarti seluruh hero otomatis memakai panji navy ini.

   .rb-hero--gold tetap ada untuk tempat yang memang ingin emas (mis. sorotan
   nilai), lengkap dengan pembalikan warna aksennya. */
.rb-hero--gold {
    background: var(--md-brand-gold-container);
    background-image: var(--md-brand-grad-gold);
    color: var(--md-brand-on-gold);
}
.rb-hero--gold::before { background: radial-gradient(circle at 35% 35%, rgba(255,255,255,.30), transparent 68%); }
.rb-hero--gold::after  { background: none; }
.rb-hero--gold .rb-hero-title,
.rb-hero--gold h1, .rb-hero--gold h2, .rb-hero--gold h3,
.rb-hero--gold h4, .rb-hero--gold h5, .rb-hero--gold h6 { color: var(--md-brand-on-gold); }
.rb-hero--gold .rb-hero-eyebrow   { color: color-mix(in srgb, var(--md-brand-on-gold) 78%, transparent) !important; }
.rb-hero--gold .rb-hero-sub       { color: color-mix(in srgb, var(--md-brand-on-gold) 82%, transparent); }
.rb-hero--gold .rb-hero-divider   { background: var(--md-brand-on-gold); opacity: .6; }
.rb-hero--gold .rb-hero-watermark { color: var(--md-brand-on-gold); opacity: .10; }
.rb-hero--gold .rb-hero-gold {
    background-image: linear-gradient(135deg, var(--md-brand-on-gold) 0%, var(--md-brand-on-gold-container) 100%);
}

/* Varian status (banner pesanan) & silver membawa MAKNA, bukan identitas navy —
   jadi garis rambut emas dan pendar sudutnya dimatikan. */
.rb-hero--success::after, .rb-hero--info::after, .rb-hero--danger::after, .rb-hero--silver::after { background: none; }
.rb-hero--success::before, .rb-hero--info::before, .rb-hero--danger::before, .rb-hero--silver::before { background: radial-gradient(circle at 35% 35%, rgba(255,255,255,.14), transparent 68%); }

.rb-hero--success, .rb-hero--info, .rb-hero--danger {
    background-image: none;
    background: var(--md-sys-color-secondary-container);
    color: var(--md-sys-color-on-secondary-container);
}
.rb-hero--success { background: #b8f1c0; color: #002107; }
.rb-hero--danger  { background: var(--md-sys-color-error-container); color: var(--md-sys-color-on-error-container); }
.rb-hero--success .rb-hero-title, .rb-hero--info .rb-hero-title, .rb-hero--danger .rb-hero-title,
.rb-hero--success h1, .rb-hero--success h2, .rb-hero--success h3, .rb-hero--success h4, .rb-hero--success h5,
.rb-hero--info h1, .rb-hero--info h2, .rb-hero--info h3, .rb-hero--info h4, .rb-hero--info h5,
.rb-hero--danger h1, .rb-hero--danger h2, .rb-hero--danger h3, .rb-hero--danger h4, .rb-hero--danger h5 { color: inherit; }
.rb-hero--success .rb-hero-watermark, .rb-hero--info .rb-hero-watermark, .rb-hero--danger .rb-hero-watermark { color: currentColor; opacity: .10; }
.rb-hero--success .rb-hero-divider, .rb-hero--info .rb-hero-divider, .rb-hero--danger .rb-hero-divider { background: currentColor; opacity: .5; }
.rb-hero--success .rb-hero-sub, .rb-hero--info .rb-hero-sub, .rb-hero--danger .rb-hero-sub { color: inherit; opacity: .85; }
[data-theme="dark"] .rb-hero--success { background: #29532f; color: #b8f1c0; }

/* ── Silver · "sudah berakhir" ──
   Gold = masih berjalan, silver = sudah lewat. Perbedaannya harus terbaca
   tanpa membaca badge, jadi seluruh properti gold ditimpa eksplisit. */
.rb-hero--silver {
    background: var(--md-sys-color-surface-container-high);
    background-image: none;
    color: var(--md-sys-color-on-surface-variant);
}
.rb-hero--silver .rb-hero-title,
.rb-hero--silver h1, .rb-hero--silver h2, .rb-hero--silver h3,
.rb-hero--silver h4, .rb-hero--silver h5, .rb-hero--silver h6 { color: var(--md-sys-color-on-surface); }
.rb-hero--silver .rb-hero-watermark { color: var(--md-sys-color-on-surface-variant); opacity: .08; }
.rb-hero--silver .rb-hero-eyebrow   { color: var(--md-sys-color-on-surface-variant) !important; }
.rb-hero--silver .rb-hero-divider   { background: var(--md-sys-color-outline); opacity: .8; }
.rb-hero--silver .rb-hero-sub       { color: var(--md-sys-color-on-surface-variant); }
.rb-hero--silver .rb-hero-gold {
    background-image: none;
    -webkit-text-fill-color: var(--md-sys-color-on-surface);
    color: var(--md-sys-color-on-surface);
}


/* ============================================================
   MODAL — satu tombol Tutup, pojok kanan atas, solid
   ============================================================
   Dipromosikan dari .ktd-close-danger yang tadinya hanya dipakai lokal di
   _detail-modal.blade.php. Sekarang komponen BERSAMA untuk SETIAP modal
   panel siswa: menggantikan .btn-close bawaan Bootstrap (silang tipis
   tanpa latar) dengan tombol bulat SOLID merah + ikon bi-x-lg, dipasang
   satu-satunya di modal-header. Modal TIDAK BOLEH punya close/dismiss
   kedua di modal-footer — kalau kaki modal butuh aksi "batal", pakai
   tombol berlabel teks ("Batal", "Periksa Lagi") yang sudah ada, bukan
   ikon X kedua. */
.rb-modal-close {
    background: var(--md-sys-color-error);
    color: var(--md-sys-color-on-error);
}

/* ============================================================
   KARTU AKTIVITAS — bahasa kartu bersama

   Satu-satunya sumber kebenaran untuk kartu di Dashboard, Katalog, Paket
   Soal, dan Transaksi. Di M3 ia adalah OUTLINED CARD: halaman-halaman itu
   padat berisi daftar, dan pada bidang seramai itu garis tipis memisahkan
   lebih tenang daripada bayangan yang bertumpuk.

   Warna status dibawa --ac-color (dan --ac-grad untuk sisa gradien), dipilih
   lewat satu kelas keadaan pada kartunya.
   ============================================================ */
.activity-card {
    position: relative;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    border-radius: var(--md-sys-shape-corner-medium);
    background: var(--md-sys-color-surface);
    border: 1px solid var(--md-sys-color-outline-variant);
    box-shadow: var(--md-sys-elevation-level0);
    color: var(--md-sys-color-on-surface);
    transition: box-shadow var(--md-sys-motion-duration-medium1) var(--md-sys-motion-easing-standard),
                border-color var(--md-sys-motion-duration-medium1) var(--md-sys-motion-easing-standard);
}
.activity-card:hover {
    box-shadow: var(--md-sys-elevation-level1);
    border-color: var(--md-sys-color-outline);
}

/* ── Aksen keadaan ── */
.activity-card-active,
.activity-card-completed,
.activity-card-scheduled,
.activity-card-past,
.activity-card-info     { --ac-color: var(--md-sys-color-primary);  --ac-grad: var(--md-brand-grad-primary); }
.activity-card-live,
.activity-card-ongoing,
.activity-card-danger   { --ac-color: var(--md-sys-color-error);    --ac-grad: linear-gradient(135deg, var(--md-sys-color-error), var(--md-sys-color-error)); }
.activity-card-soon,
.activity-card-upcoming,
.activity-card-warning  { --ac-color: var(--md-brand-on-gold-container); --ac-grad: var(--md-brand-grad-gold); }
.activity-card-success  { --ac-color: var(--rb-success);            --ac-grad: var(--rb-grad-success); }
.activity-card-cancelled,
.activity-card-muted    { --ac-color: var(--md-sys-color-on-surface-variant); --ac-grad: var(--rb-grad-silver); }
[data-theme="dark"] .activity-card-soon,
[data-theme="dark"] .activity-card-upcoming,
[data-theme="dark"] .activity-card-warning { --ac-color: var(--md-brand-gold-bright); }

/* ── Badan & kaki ── */
.activity-card-body { position: relative; padding: 16px 16px 12px; flex: 1 1 auto; }
.activity-card-footer {
    padding: 8px 16px;
    border-top: 1px solid var(--md-sys-color-outline-variant);
    background: var(--md-sys-color-surface-container-low);
    display: flex; align-items: center; justify-content: space-between; gap: 8px;
    min-height: 56px;
}

/* ── Ikon watermark ── */
.activity-card-icon {
    position: absolute; right: 12px; top: 50%;
    transform: translateY(-50%);
    font-size: 4.4rem; line-height: 1;
    color: var(--ac-color, var(--md-sys-color-primary));
    opacity: .08;
    pointer-events: none; user-select: none;
    transition: opacity var(--md-sys-motion-duration-medium1) var(--md-sys-motion-easing-standard);
}
.activity-card:hover .activity-card-icon { opacity: .12; }

/* ── Kepala: ubin ikon + label + nama ──
   Ubin ikon mengikuti bentuk elemen pemimpin daftar M3: lingkaran 40px
   berisi *-container. */
.activity-card-header { display: flex; align-items: center; gap: 12px; padding-right: 8px; }
.activity-type-icon {
    width: 40px; height: 40px; flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    border-radius: var(--md-sys-shape-corner-full);
    font-size: 20px;
    background: var(--md-sys-color-secondary-container);
    color: var(--md-sys-color-on-secondary-container);
}
.activity-type-kelas .activity-type-icon { background: #b8f1c0; color: #002107; }
.activity-type-ujian .activity-type-icon { background: var(--md-brand-gold-container); color: var(--md-brand-on-gold-container); }
[data-theme="dark"] .activity-type-kelas .activity-type-icon { background: #29532f; color: #b8f1c0; }
.activity-type-info { min-width: 0; }
.activity-type-label {
    font: var(--md-sys-typescale-label-small-weight) var(--md-sys-typescale-label-small-size)/1 var(--md-sys-typescale-plain);
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--ac-color, var(--md-sys-color-primary));
}
.activity-type-name {
    font: var(--md-sys-typescale-title-medium-weight) var(--md-sys-typescale-title-medium-size)/var(--md-sys-typescale-title-medium-line-height) var(--md-sys-typescale-plain);
    color: var(--md-sys-color-on-surface);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    margin-top: 2px;
}

/* ── Baris keterangan ── */
.activity-card-meta {
    font: 400 var(--md-sys-typescale-body-medium-size)/var(--md-sys-typescale-body-medium-line-height) var(--md-sys-typescale-plain);
    color: var(--md-sys-color-on-surface-variant);
    margin-top: 6px;
}
.activity-card-meta i { color: var(--ac-color, var(--md-sys-color-primary)); opacity: .8; }

/* ── Pil & badge di dalam kartu ── */
.activity-pill {
    display: inline-flex; align-items: center; gap: 6px;
    height: 24px; padding: 0 10px;
    border-radius: var(--md-sys-shape-corner-small);
    background: var(--md-sys-color-secondary-container);
    color: var(--md-sys-color-on-secondary-container);
    font: var(--md-sys-typescale-label-small-weight) var(--md-sys-typescale-label-small-size)/1 var(--md-sys-typescale-plain);
    letter-spacing: .05em; text-transform: uppercase;
}
.activity-pill-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ac-color, var(--md-sys-color-primary)); display: inline-block; flex-shrink: 0; }
.activity-badge {
    display: inline-flex; align-items: center;
    padding: 3px 10px;
    border-radius: var(--md-sys-shape-corner-small);
    background: var(--md-sys-color-surface-container-high);
    color: var(--md-sys-color-on-surface-variant);
    border: none;
    font: var(--md-sys-typescale-label-small-weight) var(--md-sys-typescale-label-small-size)/1.4 var(--md-sys-typescale-plain);
}
.activity-status-badge {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 3px 10px;
    border-radius: var(--md-sys-shape-corner-small);
    font: var(--md-sys-typescale-label-small-weight) var(--md-sys-typescale-label-small-size)/1.4 var(--md-sys-typescale-plain);
}
.activity-footer-info {
    display: flex; align-items: center; gap: 4px; min-width: 0;
    font: 400 var(--md-sys-typescale-body-small-size)/var(--md-sys-typescale-body-small-line-height) var(--md-sys-typescale-plain);
    color: var(--md-sys-color-on-surface-variant);
}
.activity-footer-info i { color: var(--ac-color, var(--md-sys-color-primary)); flex-shrink: 0; }

/* ── Strip peringatan ── */
.activity-card-notice {
    display: flex; align-items: center; gap: 6px;
    margin-top: 8px; padding: 8px 12px;
    border-radius: var(--md-sys-shape-corner-small);
    background: var(--md-brand-gold-container);
    color: var(--md-brand-on-gold-container);
    font: 400 var(--md-sys-typescale-body-small-size)/var(--md-sys-typescale-body-small-line-height) var(--md-sys-typescale-plain);
}
[data-theme="dark"] .activity-card-notice { background: var(--md-brand-on-gold-container); color: var(--md-brand-gold-container); }

/* ── Tombol di kaki kartu ──
   `.btn-action-primary` sudah jadi filled tertiary (gold) di m3.css. Di sini
   hanya "Hasil" yang perlu dibedakan: aksi MELIHAT, bukan ajakan mengerjakan,
   jadi ia filled primary (biru) — emas disisakan untuk yang benar-benar
   mengajak. */
.activity-card .btn-action-result {
    background: var(--md-sys-color-primary);
    color: var(--md-sys-color-on-primary);
}
.activity-card .btn-action-result:hover { color: var(--md-sys-color-on-primary); box-shadow: var(--md-sys-elevation-level1); }

/* ── Penanda "Live" / "Segera" ──
   Kedipan keras diganti pudar lembut dengan easing M3: premium berarti tenang,
   bukan gelisah. */
.live-badge-pill {
    display: inline-flex; align-items: center; gap: 6px;
    height: 24px; padding: 0 12px;
    border-radius: var(--md-sys-shape-corner-full);
    background: var(--md-sys-color-error); color: var(--md-sys-color-on-error);
    font: var(--md-sys-typescale-label-small-weight) var(--md-sys-typescale-label-small-size)/1 var(--md-sys-typescale-plain);
    letter-spacing: .06em;
    animation: rb-live-pulse 2.6s var(--md-sys-motion-easing-standard) infinite;
}
@keyframes rb-live-pulse {
    0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--md-sys-color-error) 55%, transparent); }
    50%      { box-shadow: 0 0 0 8px transparent; }
}
.live-dot, .live-dot-sm {
    display: inline-block; width: 8px; height: 8px; border-radius: 50%;
    background: currentColor;
    animation: rb-live-fade 2.4s ease-in-out infinite;
}
.live-dot-sm { width: 6px; height: 6px; }
@keyframes rb-live-fade { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
.live-ribbon, .soon-ribbon {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 2px 8px;
    border-radius: var(--md-sys-shape-corner-full);
    font: var(--md-sys-typescale-label-small-weight) var(--md-sys-typescale-label-small-size)/1.3 var(--md-sys-typescale-plain);
}
.live-ribbon { background: var(--md-sys-color-error); color: var(--md-sys-color-on-error); }
.soon-ribbon { background: var(--md-brand-gold); color: var(--md-brand-on-gold); }
.live-card-wrap .activity-card, .live-card-wrap .card { box-shadow: 0 0 0 1px var(--md-sys-color-error); }
.soon-card-wrap .activity-card, .soon-card-wrap .card { box-shadow: 0 0 0 1px var(--md-brand-gold); }

/* ── Nada silver: program yang masa berlakunya sudah lewat ──
   Tombolnya ikut redup supaya CTA emas tidak lagi mengundang aksi yang memang
   sudah tidak bisa dilakukan. "Hasil" SENGAJA tetap biru: di kartu yang serba
   mati, ia satu-satunya yang masih bisa dibuka. */
.btn-silver,
.activity-card.is-ended .btn-action-primary {
    background: var(--md-sys-color-surface-container-highest) !important;
    color: var(--md-sys-color-on-surface-variant) !important;
    box-shadow: none !important;
}
.btn-silver:hover, .activity-card.is-ended .btn-action-primary:hover { color: var(--md-sys-color-on-surface) !important; }
.btn-silver.disabled, .btn-silver:disabled,
.activity-card.is-ended .btn-action-primary.disabled { pointer-events: none; }
.btn-outline-silver {
    background: transparent;
    color: var(--md-sys-color-on-surface-variant);
    box-shadow: inset 0 0 0 1px var(--md-sys-color-outline);
}
.btn-outline-silver:hover { color: var(--md-sys-color-on-surface); background: transparent; }
.activity-card.is-ended { --ac-color: var(--md-sys-color-on-surface-variant); --ac-grad: var(--rb-grad-silver); }
.activity-card.is-ended .activity-type-icon {
    background: var(--md-sys-color-surface-container-highest);
    color: var(--md-sys-color-on-surface-variant);
}
.activity-card.is-ended .activity-type-label,
.activity-card.is-ended .activity-card-icon { color: var(--md-sys-color-on-surface-variant); }
.activity-card.is-ended .activity-badge {
    background: var(--md-sys-color-surface-container-high);
    color: var(--md-sys-color-on-surface-variant);
}


/* ============================================================
   KARTU STATISTIK & UBIN IKON
   ============================================================ */
.stat-card {
    background: var(--md-sys-color-surface);
    border: 1px solid var(--md-sys-color-outline-variant);
    border-radius: var(--md-sys-shape-corner-medium);
    overflow: hidden;
    transition: box-shadow var(--md-sys-motion-duration-medium1) var(--md-sys-motion-easing-standard);
}
.stat-card:hover { box-shadow: var(--md-sys-elevation-level1); }
.stat-icon, .stat-card .stat-icon {
    display: flex; align-items: center; justify-content: center;
    width: 48px; height: 48px; flex-shrink: 0;
    border-radius: var(--md-sys-shape-corner-full);
    font-size: 22px;
    background: var(--md-sys-color-secondary-container);
    color: var(--md-sys-color-on-secondary-container);
}
.stat-card .stat-value, .stat-val {
    font: 600 var(--md-sys-typescale-headline-small-size)/1.2 var(--md-sys-typescale-brand);
    letter-spacing: -.02em;
}
.stat-card .stat-label, .stat-lbl {
    font: 400 var(--md-sys-typescale-body-small-size)/var(--md-sys-typescale-body-small-line-height) var(--md-sys-typescale-plain);
    color: var(--md-sys-color-on-surface-variant);
    margin-bottom: 0;
}

/* Ubin ikon berwarna. Semua varian jatuh ke pasangan *-container M3 — di M3
   warna aksen memang selalu hadir sebagai pasangan bidang + teksnya, bukan
   sebagai warna teks di atas latar transparan. */
/* ============================================================
   KARTU RINCIAN UJIAN (.exd-*)

   Dipakai BERSAMA oleh halaman rincian ujian dan halaman persiapan lewat
   partial student/exams/_kartu-info & _kartu-aturan. Sempat hidup sebagai
   <style> lokal halaman rincian; begitu halaman persiapan menyertakan partial
   yang sama, seluruh kartunya tampil tanpa bentuk di sana — ubin komposisi
   soal jatuh jadi deretan teks telanjang. Jebakan yang sama dengan
   .rb-card-head dan .score-stat-box.
   ============================================================ */
/* ── Kartu INFORMASI / Tentang Ujian ──────────────────────────
   Satu kartu berisi deskripsi, komposisi bentuk soal, dan waktu pelaksanaan —
   susunan yang sama dengan kartu bernama sama di rincian ujian rumbo.id.
   `height: auto` eksplisit karena .rb-card membawa height:100% untuk keperluan
   grid, sedangkan kartu ini bertumpuk di dalam kolom. */
/* .rb-card dirancang untuk kartu SEBARIS (`height: 100%` supaya tingginya
   sama). Di halaman rincian & persiapan kartunya BERTUMPUK di dalam kolom,
   jadi tanpa penimpa ini tiap kartu mewarisi tinggi kolom terpanjang dan
   menyisakan ruang kosong sebesar layar di bawah isinya. */
.exd-page .rb-card,
.exd-page form > .rb-card { height: auto; }

.exd-sum { padding: 0; gap: 0; height: auto; }
/* Kartu yang bisa ditutup. Penanda segitiga bawaan peramban dibuang dan
   diganti chevron sendiri supaya kepala kartunya tetap serupa kartu lain. */
.exd-fold > summary { cursor: pointer; list-style: none; }
/* Kartu lipat yang isinya BUKAN kisi berpadding sendiri (mis. Aturan
   Pengawasan) butuh padding kartu biasa; yang isinya sudah berpadding
   (Tentang Ujian) tidak. */
/* ── Kartu lipat RINGKAS ──────────────────────────────────────
   Yang terlihat saat tertutup adalah RINGKASANNYA — kepala kartu plus ubin
   angka atau lencana; yang dilipat hanya prosanya. Dasarnya: ubin komposisi
   dan lencana pengawasan sudah terbaca sekilas dan justru itulah yang paling
   sering dicari, sedangkan yang memakan tinggi layar adalah paragraf dan
   daftar kalimat. Menyembunyikan keduanya sekaligus menghemat ruang dengan
   mengorbankan hal yang salah. */
.exd-fold--ringkas { padding: 0; }
.exd-fold--ringkas > summary { padding: 0; }
.exd-fold--ringkas > summary:hover { background: transparent; }
.exd-fold--ringkas > summary:hover .exd-head { background: var(--md-sys-color-surface-container-low); }
.exd-fold--ringkas .exd-head { margin: 0; padding: .9rem 1rem; }
.exd-fold--ringkas .exd-flags { margin: 0; padding: 0 1rem 1rem; border-top: 0; }
.exd-fold--ringkas .exd-fold-body {
    padding: .9rem 1rem 1rem;
    border-top: 1px solid var(--md-sys-color-outline-variant);
}
.exd-fold--ringkas .exd-fold-body > :last-child { margin-bottom: 0; }
/* Kata pendek di samping chevron — memberi tahu APA yang tersembunyi, supaya
   panah itu tidak sekadar panah tanpa janji. */
.exd-fold-hint {
    font: 700 var(--md-sys-typescale-label-small-size)/1 var(--md-sys-typescale-plain);
    letter-spacing: .05em; text-transform: uppercase;
    color: var(--md-sys-color-on-surface-variant); white-space: nowrap;
}

.exd-fold--pad > summary { padding: .9rem 1rem; }
.exd-fold--pad .exd-fold-body { padding: .9rem 1rem 1rem; border-top: 1px solid var(--md-sys-color-outline-variant); }
.exd-fold--pad .exd-fold-body > :last-child { margin-bottom: 0; }
.exd-fold > summary::-webkit-details-marker { display: none; }
.exd-fold > summary:hover { background: var(--md-sys-color-surface-container-low); }
.exd-fold-ico { flex-shrink: 0; transition: transform .18s ease; color: var(--md-sys-color-on-surface-variant); }
.exd-fold[open] .exd-fold-ico { transform: rotate(180deg); }
/* Ditutup, kepalanya tak lagi punya isi di bawahnya — garisnya ikut hilang. */
.exd-fold:not([open]) > summary { border-bottom: 0; }

.exd-info-head {
    display: flex; align-items: center; gap: .7rem;
    padding: .9rem 1rem; border-bottom: 1px solid var(--md-sys-color-outline-variant);
}
.exd-info-head .rb-eyebrow { margin: 0 0 .1rem; }

/* Deskripsi ujian: teks biasa di badan kartu. Sempat dikotaki bertepi kiri
   seperti kutipan, tetapi di kartu yang isinya memang keterangan, kotak itu
   hanya menambah bingkai tanpa menambah arti. */
.exd-info-desc { padding: 1rem 1rem 0; font-size: .84rem; line-height: 1.7; }
.exd-info-desc :last-child { margin-bottom: 0; }

/* ── Komposisi bentuk soal ────────────────────────────────────
   Ubinnya dibiarkan melebar sendiri (auto-fit) karena banyaknya bentuk soal
   berbeda tiap ujian: TKA tiga, OSN-K satu, OSN Final bisa empat. Kisi berkolom
   tetap akan menyisakan petak kosong pada yang satu dan memampatkan yang lain. */
.exd-komp { padding: 1rem 1rem 0; }
.exd-komp-lbl { margin: 0 0 .5rem; }
.exd-komp-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(92px, 1fr)); gap: .45rem; }
.exd-komp-item {
    border-radius: var(--md-sys-shape-corner-medium);
    background: var(--md-sys-color-surface-container);
    padding: .55rem .4rem; text-align: center;
}
.exd-komp-val {
    font: 600 1.3rem/1.1 var(--md-sys-typescale-brand); letter-spacing: -.02em;
    color: var(--md-sys-color-primary);
}
.exd-komp-name {
    font: var(--md-sys-typescale-label-small-weight) var(--md-sys-typescale-label-small-size)/1.3 var(--md-sys-typescale-plain);
    color: var(--md-sys-color-on-surface-variant); margin-top: 2px;
}

/* Susunan bagian, di dalam kartu informasi yang sama. Padding bawah PENUH:
   catatan "Bagian dikerjakan berurutan…" adalah baris terakhir kartu, dan
   tanpa itu ia menempel persis di garis tepi. */
.exd-susun { padding: 1rem; }

/* ── Waktu ujian ──────────────────────────────────────────────
   Mulai & berakhir sebagai dua baris berurut ke bawah, bukan dua angka
   berdampingan: keduanya TANGGAL LENGKAP, dan berdampingan keduanya terpaksa
   disingkat sampai kehilangan hari dalam pekan. */
.exd-waktu { padding: 1rem; }
.exd-wrow {
    display: flex; align-items: center; gap: .5rem;
    font-size: .84rem; padding: .2rem 0;
}
.exd-wico { font-size: .95rem; flex-shrink: 0; }
.exd-wico--mulai { color: var(--md-sys-color-primary); }
.exd-wico--akhir { color: var(--md-sys-color-error); }
.exd-wfoot {
    display: flex; flex-wrap: wrap; gap: 6px 16px;
    margin-top: .7rem; padding-top: .7rem;
    border-top: 1px solid var(--md-sys-color-outline-variant);
    font: 400 var(--md-sys-typescale-body-small-size)/1.5 var(--md-sys-typescale-plain);
    color: var(--md-sys-color-on-surface-variant);
}
.exd-wfoot b { color: var(--md-sys-color-on-surface); font-weight: 600; }
.exd-wfoot i { color: var(--md-sys-color-primary); margin-right: .3rem; }

/* ── Tata tertib ──────────────────────────────────────────────
   Daftar bernomor titik, bukan deretan baris berikon: yang dibaca peserta di
   sini adalah ATURAN, dan aturan dibaca sebagai daftar. Butir yang benar-benar
   bisa MENGGUGURKAN pekerjaannya ditandai merah — sisanya cukup netral, karena
   kalau semuanya merah tak ada yang menonjol. */
.exd-rules { margin: 0; padding-left: 1.15rem; font-size: .86rem; line-height: 1.7; }
.exd-rules li { margin-bottom: .3rem; }
.exd-rules li::marker { color: var(--md-sys-color-primary); }
.exd-rules li.is-strict { color: var(--md-sys-color-error); }
.exd-rules li.is-strict::marker { color: var(--md-sys-color-error); }
/* Ringkasan pengawasan yang AKTIF sebagai lencana di kaki kartu — sekali lihat
   ketahuan apa saja yang menyala tanpa membaca ulang seluruh daftarnya. */
.exd-flags { display: flex; flex-wrap: wrap; gap: .35rem; margin-top: .85rem; padding-top: .75rem; border-top: 1px solid var(--md-sys-color-outline-variant); }

/* Kepala kartu: chip ikon + eyebrow + judul. Pola yang sama dipakai kedua
   kartu supaya keduanya terbaca sebagai sepasang, bukan dua gaya berbeda. */
.exd-head { display: flex; align-items: center; gap: .7rem; margin-bottom: .85rem; }
.exd-chip {
    width: 2.1rem; height: 2.1rem; flex-shrink: 0; border-radius: 12px;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--md-sys-color-secondary-container); color: var(--md-sys-color-on-secondary-container);
    font-size: 1rem;
}
.exd-chip--gold { background: var(--md-brand-gold); color: var(--md-brand-on-gold); }
.exd-head-title { font-weight: 700; font-size: .95rem; line-height: 1.2; margin: 0; }
.exd-head .rb-eyebrow { margin: 0 0 .1rem; }

.exd-sec { display: flex; align-items: center; gap: .75rem; padding: .6rem 0; }
.exd-sec + .exd-sec { border-top: 1px solid var(--md-sys-color-outline-variant); }
.exd-sec-no {
    width: 1.9rem; height: 1.9rem; flex-shrink: 0; border-radius: 50%;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--md-sys-color-secondary-container); color: var(--md-sys-color-on-secondary-container);
    font-weight: 700; font-size: .8rem;
}
.exd-sec-name { font-weight: 600; font-size: .9rem; }
.exd-sec-sub { font-size: .76rem; color: var(--md-sys-color-on-surface-variant); }

/* ── Susunan Ujian sebagai PEMILIH bagian ─────────────────────────────────
   Hanya pada `exams.section_mode = per_bagian`. Di mode sekali duduk petak
   ini tetap daftar mati (.exd-sec di atas) — tiap baris cuma keterangan.
   Di sini tiap baris punya KEADAAN dan tombolnya sendiri, jadi ia butuh
   bidang & tepi, bukan sekadar garis pemisah antar-baris.

   Kelasnya sengaja BUKAN varian .exd-sec: aturan `.exd-sec + .exd-sec` di
   atas memasang garis atas, dan pada baris bertepi penuh itu jadi garis
   ganda. Dua penata letak yang bertabrakan lebih mahal daripada satu blok
   yang berdiri sendiri. */
.exd-pick {
    display: flex; align-items: center; gap: .75rem;
    padding: .6rem .7rem;
    border: 1px solid var(--md-sys-color-outline-variant);
    border-radius: var(--md-sys-shape-corner-medium);
}
.exd-pick + .exd-pick { margin-top: .45rem; }
.exd-pick-act { flex-shrink: 0; margin-left: auto; }

.exd-pick--kerjakan {
    border-color: var(--md-brand-gold);
    background: color-mix(in srgb, var(--md-brand-gold) 8%, var(--md-sys-color-surface));
}
.exd-pick--kerjakan .exd-sec-no { background: var(--md-brand-gold); color: var(--md-brand-on-gold); }

/* Bagian yang ditinggalkan di tengah — jamnya TETAP berjalan, jadi nadanya
   mendesak, bukan netral seperti bagian yang baru menunggu giliran. */
.exd-pick--berjalan {
    border-color: var(--md-sys-color-error);
    background: color-mix(in srgb, var(--md-sys-color-error) 8%, var(--md-sys-color-surface));
}
.exd-pick--berjalan .exd-sec-no { background: var(--md-sys-color-error); color: var(--md-sys-color-on-error); }

.exd-pick--selesai { background: var(--md-sys-color-surface-container-low); }
.exd-pick--selesai .exd-sec-no { background: var(--md-brand-gold-container); color: var(--md-brand-on-gold-container); }

.exd-pick--terkunci, .exd-pick--tertutup { opacity: .62; }


/* Nilai per bagian di dalam kartu Hasil. */
.exd-parts { border-top: 1px solid var(--md-sys-color-outline-variant); padding-top: .85rem; }
/* Baris penutup "Nilai Total": angka yang sama dengan ubin Nilai di atas,
   tetapi di sini ia berdiri sebagai JUMLAH dari baris-baris di atasnya, jadi
   ia perlu tepi atas yang tegas — bukan sekadar baris keempat yang senada. */
.exd-parts-total {
    border-top: 2px solid var(--md-sys-color-outline-variant);
    margin-top: .35rem;
    padding-top: .7rem;
}
.exd-parts-total .exd-sec-name { font-weight: 700; }
/* Aksi yang tersisa sesudah ujian dikerjakan, di kaki kartu Pencapaian. */
.exd-ulang { margin-top: 1rem; padding-top: .9rem; border-top: 1px solid var(--md-sys-color-outline-variant); }
.exd-ulang:empty { display: none; }

.res-medal { font-size: 1.6rem; }
.res-medal--gold   { color: #d4a017; }
.res-medal--silver { color: #9aa3b2; }
.res-medal--bronze { color: #b3702d; }
.res-board th, .res-board td { padding: .45rem .5rem; font-size: .82rem; }
.res-board tr.is-me { background: var(--md-sys-color-secondary-container); font-weight: 700; }

/* ============================================================
   PITA STATUS KARTU (.ps-ribbon)

   Dipakai BERSAMA kartu Paket Soal dan kartu Ujian. Sempat hidup sebagai
   <style> lokal halaman Paket Soal; dinaikkan ke sini begitu pemakainya dua —
   jebakan yang sudah berulang lima kali di panel ini: satu kelas di <style>
   satu halaman, lalu halaman kedua memakainya dan tampil tanpa bentuk.
   ============================================================ */
/* ── Pita status di sudut kanan-ATAS ────────────────────────────────
   Segitiga 45° klasik, sudut yang sama dengan .rb-card__ribbon "Gratis" di
   kartu Katalog. Pindah dari kanan-BAWAH 12 Agu 2026; sudut bawah yang
   ditinggalkannya kini dipakai lencana Tier (.kt-tierfoot).

   Ia memang menimpa ujung kanan pita warna Seri di tepi atas kartu — pita
   warna itu penanda PENGELOMPOKAN yang tugasnya sudah selesai begitu beberapa
   piksel pertamanya terlihat di tepi kiri, sedangkan status pengerjaan adalah
   hal yang benar-benar dibaca. Itu pertukaran yang disengaja.

   Terpotong rapi oleh `overflow: hidden` milik .rb-card. */
/* Ukuran kotak menentukan berapa panjang teks yang MUAT, dan hubungannya tidak
   lurus: yang membatasi bukan sisi kotak melainkan panjang potongan pita pada
   jaraknya dari pusat, yaitu 2 x (S x 0,7071 - D) dengan S sisi kotak dan D
   jarak dorong di bawah. Pada 104 px dan D 22 px, potongannya ~103 px — cukup
   untuk label terpanjang yang ada ("ARSIP BERAKHIR") berikut sisa napas.

   Kalau kelak ada label status yang lebih panjang, INILAH yang harus dihitung
   ulang; menambah kata saja akan membuatnya terpotong miring tanpa peringatan
   apa pun. */
.ps-ribbon {
    position: absolute; right: 0; top: 0; width: 104px; height: 104px;
    overflow: hidden; z-index: 2; pointer-events: none;
}
/* Penempatan pita lewat TRANSFORM, bukan bottom/right dalam piksel.
   Dengan cara lama, titik tengah pita ditentukan oleh tinggi barisnya sendiri —
   dan tinggi itu ikut berubah mengikuti fon yang benar-benar terpakai, sehingga
   pitanya meleset dari garis bagi sudut dan teksnya tampak bergeser.

   Urutannya dibaca kiri ke kanan: dipusatkan ke tengah kotak, diputar 45°, lalu
   didorong ke sudut sepanjang sumbu Y-nya SENDIRI yang sesudah pemutaran sudah
   mengarah ke sudut yang dituju. Pita karena itu selalu simetris terhadap garis
   bagi sudut, berapa pun tinggi barisnya.

   Untuk sudut kanan-ATAS tandanya DUA-DUANYA dibalik dari versi kanan-bawah:
   rotate(+45deg) dan translateY(-22px). Membalik salah satu saja melempar
   pitanya ke sudut kiri-bawah — arahnya ditentukan pasangan itu, bukan
   masing-masing. */
.ps-ribbon span {
    position: absolute; top: 50%; left: 50%; width: 170px;
    transform: translate(-50%, -50%) rotate(45deg) translateY(-22px);
    display: block; padding: 3px 0; text-align: center;
    /* nowrap: label dua kata ("Arsip berakhir") tanpa ini bisa patah jadi dua
       baris, dan pita miring dua baris jauh lebih buruk daripada teks kecil. */
    white-space: nowrap;
    font-size: .55rem; font-weight: 800; letter-spacing: .03em; text-transform: uppercase;
    /* letter-spacing menyisipkan jarak SESUDAH huruf terakhir juga, jadi teks
       yang di-center selalu duduk setengah spasi ke kiri. text-indent sebesar
       spasinya menggeser balik persis sebanyak itu. */
    text-indent: .03em;
    /* Bayangan jatuh ke BAWAH pita sekarang (dulu ke atas): sisi yang menghadap
       isi kartu berpindah begitu pitanya naik ke sudut atas. */
    box-shadow: 0 2px 5px rgba(0,0,0,.20);
}

/* Nada pita = status_bg yang ditetapkan PaketSoalListing:
     hijau      Selesai      — tuntas, apa pun sisa jatah percobaannya (dulu
                                "Selesai"/navy dan "Dikerjakan"/hijau dua pita
                                terpisah menurut sisa jatah; kini disatukan —
                                bedanya cuma boleh/tidaknya mengulang, dan itu
                                sudah dijawab tombol "Ulang" di modal, bukan pita)
     emas       Lanjutkan    — percobaan sedang berjalan (nada dibalik, lihat di bawah)
     merah      Timeout      — percobaan terakhir ditinggal/diabaikan
     biru       Terjadwal    — Seri belum dibuka
     kelabu     Arsip        — Seri sudah berakhir */
.ps-ribbon--success   span { background: var(--md-green); color: var(--md-on-green); }
/* "Lanjutkan" dibalik dari pita lain: latarnya nada TEKS gold baku, dan
   tekslah yang mengambil warna latar gold baku — supaya pita percobaan yang
   sedang berjalan tampak beda sendiri, bukan sekadar emas seperti nilai/koin
   di tempat lain pada kartu ini. */
.ps-ribbon--warning   span { background: var(--md-brand-on-gold-strong); color: var(--md-brand-gold-strong); }
.ps-ribbon--info      span { background: var(--md-sys-color-primary); color: var(--md-sys-color-on-primary); }
.ps-ribbon--secondary span { background: var(--md-sys-color-outline); color: var(--md-sys-color-surface); }
.ps-ribbon--danger    span { background: var(--md-sys-color-error); color: var(--md-sys-color-on-error); }

/* ── Ubin pencapaian ──────────────────────────────────────────
   Papan angka hasil pengerjaan. Dipakai halaman hasil latihan mandiri DAN
   halaman rincian ujian (yang sejak 12 Sep 2026 merangkap halaman hasil).
   Dinaikkan ke sini begitu pemakainya lebih dari satu — sebelumnya ia <style>
   lokal, dan halaman yang tidak memuat salinannya menampilkan ubin tanpa
   bentuk sama sekali. */
.score-stat-box {
    border: none; border-radius: var(--md-sys-shape-corner-medium);
    padding: 12px 8px; text-align: center;
    background: var(--md-sys-color-surface-container);
}
.score-stat-box .stat-val {
    font: 600 clamp(1.15rem, 4.5vw, var(--md-sys-typescale-title-large-size))/1.1 var(--md-sys-typescale-brand);
    letter-spacing: -.02em;
}
.score-stat-box .stat-lbl {
    font: var(--md-sys-typescale-label-small-weight) var(--md-sys-typescale-label-small-size)/1.3 var(--md-sys-typescale-plain);
    color: var(--md-sys-color-on-surface-variant); margin-top: 2px;
}
/* Dua ubin utama (nilai & durasi) lebih lebar, angkanya lebih besar. */
.score-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: .5rem; }
@media (min-width: 992px) { .score-grid { grid-template-columns: 1.5fr 1.5fr 1fr 1fr 1fr 1fr; } }
.score-stat-hero .stat-val { font-size: clamp(1.4rem, 5vw, 1.75rem); }
.stat-val-gold { color: var(--md-brand-on-gold-container); }
[data-theme="dark"] .stat-val-gold { color: var(--md-brand-gold-bright); }

/* Kepala kartu berikon: chip + (eyebrow, judul). Dulu hidup sebagai <style>
   lokal di halaman hasil latihan; begitu halaman hasil UJIAN memakainya juga,
   satu kelas berarti dua rupa — di halaman kedua ia tak berbentuk sama sekali.
   Pola yang sama dengan .btn-leave: dipindahkan ke sini begitu pemakainya
   lebih dari satu. */
.rb-card-head {
    display: flex; align-items: center; gap: 12px;
    min-height: 64px; padding: 12px 16px;
    border-bottom: 1px solid var(--md-sys-color-outline-variant);
}
.rb-card-head .rb-title { font-size: .98rem; margin: 0; }

.rb-chip {
    display: flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; flex-shrink: 0;
    border-radius: var(--md-sys-shape-corner-full);
    font-size: 20px;
    background: var(--md-sys-color-secondary-container);
    color: var(--md-sys-color-on-secondary-container);
}
.rb-chip-primary, .rb-chip-blue { background: var(--md-sys-color-primary-container); color: var(--md-sys-color-on-primary-container); }
.rb-chip-gold    { background: var(--md-brand-gold-container); color: var(--md-brand-on-gold-container); }
.rb-chip-success { background: #b8f1c0; color: #002107; }
.rb-chip-danger  { background: var(--md-sys-color-error-container); color: var(--md-sys-color-on-error-container); }
.rb-chip-info    { background: var(--md-sys-color-secondary-container); color: var(--md-sys-color-on-secondary-container); }
.rb-chip-purple  { background: #e9ddff; color: #22005d; }
.rb-chip-muted   { background: var(--md-sys-color-surface-container-highest); color: var(--md-sys-color-on-surface-variant); }
[data-theme="dark"] .rb-chip-success { background: #29532f; color: #b8f1c0; }
[data-theme="dark"] .rb-chip-purple  { background: #4f378a; color: #e9ddff; }


/* ============================================================
   KARTU DAFTAR STANDAR (.rb-card)

   Desain baku untuk SEMUA daftar kartu-butir di panel siswa — lahir sebagai
   kartu Katalog Olimp., kini dipromosikan jadi komponen bersama supaya seluruh
   daftar terbaca satu keluarga. Anatomi: cangkang membulat + pita aksen atas,
   kotak ikon, judul (+subjudul), pil tag, baris angka di dasar, dan batang
   kemajuan opsional. Boleh dipakai sebagai <a> (seluruh kartu tertaut) maupun
   <div> (kartu yang memuat kontrolnya sendiri).

   Pemodelan bagian memakai BEM ringkas (.rb-card__bagian) supaya tidak bentrok
   dengan kelas utilitas mana pun. Nada warna mengikuti kartu Olimp. asli:
   sebagian sengaja nilai tetap (biru/emas/hijau merek) yang sudah punya
   pasangan mode gelapnya di blok [data-theme="dark"] paling bawah.
   ============================================================ */
.rb-card {
    display: flex; flex-direction: column; height: 100%; gap: .55rem;
    padding: 1rem 1.05rem 1.1rem;
    background: var(--md-sys-color-surface);
    border: 1px solid var(--md-sys-color-outline-variant);
    /* Lewat variabel, bukan angka telanjang: lencana Tier di sudut kanan-bawah
       (.kt-tierfoot .kt-tier) harus melengkung SAMA PERSIS supaya kedua
       lengkungnya menyatu. Dua angka terpisah pasti berbeda suatu hari. */
    --rb-card-radius: 16px;
    border-radius: var(--rb-card-radius); color: inherit; text-decoration: none;
    position: relative; overflow: hidden;
    transition: border-color .16s ease, box-shadow .16s ease, transform .16s ease;
}
/* Pita aksen tipis di tepi atas — pembeda cepat antar kartu tanpa menambah satu
   elemen pun ke dalam alirannya. */
.rb-card::before {
    content: ''; position: absolute; inset: 0 0 auto 0; height: 3px; z-index: 1;
    background: linear-gradient(90deg, #1a78cf, #7cc2f5); opacity: .85;
}
/* Tuntas/dimiliki penuh: pita atas berubah hijau. */
.rb-card--done::before { background: linear-gradient(90deg, #0b7a5a, #6fd3ae); }
.rb-card:hover {
    border-color: var(--md-sys-color-primary);
    box-shadow: 0 6px 20px rgba(12,35,89,.10);
    transform: translateY(-2px);
}
.rb-card:focus-visible { outline: 2px solid var(--md-sys-color-primary); outline-offset: 2px; }
.rb-card > :last-child { margin-bottom: 0; }

/* Kepala: kotak ikon + judul/subjudul + lencana kanan. */
.rb-card__top { display: flex; align-items: flex-start; gap: .7rem; }
.rb-card__ico {
    flex-shrink: 0; width: 42px; height: 42px; border-radius: 12px;
    display: inline-flex; align-items: center; justify-content: center;
    background: rgba(26,120,207,.10); color: #1a78cf; font-size: 1.25rem;
}
.rb-card__head { min-width: 0; flex: 1 1 auto; }
.rb-card__title { font-weight: 700; font-size: 1rem; line-height: 1.25; color: var(--md-sys-color-on-surface); margin: 0; }
.rb-card__sub { font-size: .82rem; color: var(--bs-secondary-color); margin-top: 1px; }
.rb-card__badge {
    flex-shrink: 0; font-size: .72rem; font-weight: 700; padding: 3px 9px;
    border-radius: 999px; background: rgba(0,0,0,.05); white-space: nowrap;
}

.rb-card__tags { display: flex; flex-wrap: wrap; gap: .3rem; }
.rb-card__tag { font-size: .7rem; font-weight: 600; padding: 2px 9px; border-radius: 999px; background: rgba(26,120,207,.10); color: #1a78cf; }
.rb-card__tag--muted { background: rgba(0,0,0,.05); color: var(--bs-secondary-color); }
/* Seri kelas mana pun boleh ditukar (App\Support\GradeAccess — kelas hanya
   membatasi ujian). --ingat = catatan "bukan kelasmu", ke atas maupun bawah. */
.rb-card__tag--ingat { background: rgba(215,163,29,.16); color: #9a7310; }

/* Baris angka ditambatkan ke DASAR kartu (margin-top:auto) supaya sebaris kartu
   berbeda tinggi tetap rata di garis angkanya. */
.rb-card__stats { margin-top: auto; padding-top: .2rem; display: flex; align-items: center; gap: .5rem; font-size: .8rem; color: var(--bs-secondary-color); }
.rb-card__stats b { color: var(--bs-body-color); font-variant-numeric: tabular-nums; }
.rb-card__dot { width: 3px; height: 3px; border-radius: 50%; background: currentColor; opacity: .45; }

/* Pita sudut (mis. "Gratis"): segitiga 45° klasik di sudut kanan atas. */
.rb-card__ribbon { position: absolute; top: 0; right: 0; width: 84px; height: 84px; overflow: hidden; z-index: 2; pointer-events: none; }
.rb-card__ribbon span {
    position: absolute; top: 15px; right: -26px; width: 116px; padding: 3px 0; text-align: center;
    transform: rotate(45deg);
    background: linear-gradient(90deg, #0b7a5a, #12a374);
    color: #fff; font-size: .64rem; font-weight: 800; letter-spacing: .09em; text-transform: uppercase;
    box-shadow: 0 2px 5px rgba(0,0,0,.22);
}
.rb-card__ribbon--gold span { background: linear-gradient(90deg, #c8951a, #f0c14b); color: #3a2a00; }

[data-theme="dark"] .rb-card__ico,
[data-theme="dark"] .rb-card__tag { background: rgba(90,169,230,.14); color: #8cc6f2; }

/* Logo lomba pada kotak ikon (<x-olimp-mark>, olympiads.logo_path).
   Tinggi tetap 42 px seperti kotak ikon; LEBARNYA mengikuti bentuk logo lewat
   --r (lebar÷tinggi berkas, 1–2): logo persegi tetap 42 px, logo lebar sampai
   74 px. Isi kotak 32 px = 42 − 2 (garis tepi) − 8 (jarak).
   Latar SELALU putih, juga di tema gelap: logo lomba dirancang untuk latar
   terang, dan berkasnya sudah diratakan ke putih (App\Support\OlympiadLogo).
   Spesifisitasnya sengaja menandingi aturan nada-kotak lain yang menimpa
   background (.ps-card[class*="sg-c"] .rb-card__ico, [data-theme="dark"]
   .rb-card__ico, .rb-card.kt-ujian .rb-card__ico).
   Dua selektor pertama berlaku DI LUAR .rb-card juga (29 Okt 2026): kepala blok
   Olimp di Paket Soal & baris "Sedang Berlangsung" di Dashboard dulu jatuh ke
   latar biru transparan di tema gelap, sehingga logo tampak janggal. */
.rb-card__ico.rb-card__ico--logo,
[data-theme="dark"] .rb-card__ico.rb-card__ico--logo,
.rb-card .rb-card__ico.rb-card__ico--logo,
[data-theme="dark"] .rb-card .rb-card__ico.rb-card__ico--logo,
.ps-card[class*="sg-c"] .rb-card__ico.rb-card__ico--logo {
    box-sizing: border-box;
    width: calc(var(--r, 1) * 32px + 10px);
    padding: 4px;
    background: #fff;
    border: 1px solid rgba(15,35,70,.12);
}
.rb-card__ico--logo > img { display: block; width: 100%; height: 100%; object-fit: contain; }

/* Versi baris-sebaris (label Olimp di landing): setinggi teks label. */
.olimp-logo-inline {
    height: 22px; width: calc(var(--r, 1) * 22px); flex-shrink: 0;
    object-fit: contain; background: #fff; border-radius: 5px; padding: 2px;
    box-sizing: content-box;
}
[data-theme="dark"] .rb-card__badge,
[data-theme="dark"] .rb-card__tag--muted { background: rgba(255,255,255,.08); }
[data-theme="dark"] .rb-card__tag--ingat { background: rgba(235,189,80,.2); color: #f2d276; }

/* ============================================================
   TIER (tingkat kesulitan Seri) — App\Support\Tier

   ENAM langkah sebagai TANGGA: hijau → teal → biru → emas → merah → pekat.
   Urutannya harus terbaca sebagai NAIK meski labelnya tidak dibaca, karena di
   kisi tiga kolom mata menyapu warna lebih dulu daripada teks.

   Pembagiannya bukan sekadar gradasi — ia menandai tiga babak nyata:
     dingin (1-3)  latihan & lomba jalur umum
     hangat (4-5)  olimpiade berjenjang, OSN-K ke atas
     pekat  (6)    final nasional & naskah asli internasional

   ── TIGA PERAN WARNA PER TIER ──────────────────────────────
   Tiap Tier memasok tiga variabel, dan komponen di bawah hanya membacanya.
   Tanpa pemisahan ini, enam Tier x dua keadaan = dua belas blok warna yang
   hampir kembar, dan satu saja yang terlewat saat menyunting langsung terlihat
   sebagai lencana yang salah nada.

     --kt-c    rona dasar; dipakai untuk garis, tint, dan ISIAN saat pekat
     --kt-fg   warna teks saat LEMBUT (di atas tint)
     --kt-on   warna teks saat PEKAT (di atas isian penuh)

   Emas satu-satunya yang --kt-fg-nya berbeda dari --kt-c: emas #D6A33C di atas
   permukaan terang cuma ~2:1, tak terbaca sebagai teks. Ia memakai nada
   container yang gelap, sementara ronanya tetap dipakai untuk garis & tint.

   Teal langkah ke-2 TIDAK ada di m3-tokens.css — sistem token hanya memasok
   lima rona yang terpakai di sini, sedangkan skalanya butuh enam. Nilainya
   dipilih agar kontrasnya lolos di kedua tema dan ronanya jatuh tepat di
   antara hijau langkah 1 dan biru langkah 3.

   Palet ini dipakai TIGA halaman (kartu Olimp., kartu Seri, kartu Paket Soal),
   jadi ia tinggal di sini, bukan di @push('styles') salah satunya.
   ============================================================ */
:root {
    --kt-tier2:    #00696E;   /* teal — hanya untuk tangga Tier */
    --kt-tier2-on: #FFFFFF;
}
[data-theme="dark"] {
    --kt-tier2:    #4FD8E0;
    --kt-tier2-on: #00363A;
}
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --kt-tier2:    #4FD8E0;
        --kt-tier2-on: #00363A;
    }
}

/* Peta rona per Tier — SATU tempat, dibaca lencana maupun tombol saring. */
.kt-tier--beginner {
    --kt-c:  var(--md-green);
    --kt-fg: var(--md-green);
    --kt-on: var(--md-on-green);
}
.kt-tier--elementary {
    --kt-c:  var(--kt-tier2);
    --kt-fg: var(--kt-tier2);
    --kt-on: var(--kt-tier2-on);
}
.kt-tier--intermediate {
    --kt-c:  var(--md-sys-color-primary);
    --kt-fg: var(--md-sys-color-primary);
    --kt-on: var(--md-sys-color-on-primary);
}
.kt-tier--advanced {
    --kt-c:  var(--md-brand-gold);
    --kt-fg: var(--md-brand-on-gold-container);
    --kt-on: var(--md-brand-on-gold);
}
[data-theme="dark"] .kt-tier--advanced { --kt-fg: var(--md-brand-gold-bright); }
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .kt-tier--advanced { --kt-fg: var(--md-brand-gold-bright); }
}
.kt-tier--expert {
    --kt-c:  var(--md-sys-color-error);
    --kt-fg: var(--md-sys-color-error);
    --kt-on: var(--md-sys-color-on-error);
}
.kt-tier--master {
    --kt-c:  var(--md-sys-color-inverse-surface);
    --kt-fg: var(--md-sys-color-inverse-surface);
    --kt-on: var(--md-sys-color-inverse-on-surface);
}

/* "Free" — BUKAN Tier ketujuh, dan ronanya sengaja di luar tangga.
   Hijau sudah menjadi milik Beginner; memakainya di sini akan membuat seri
   gratis terbaca sebagai anak tangga paling bawah, padahal aturan seri gratis
   #1 (docs/README.md §1a) menetapkan naskahnya PENUH — ia di LUAR tangga,
   bukan di dasarnya. Netral adalah satu-satunya nada yang menyatakan itu. */
.kt-tier--free {
    --kt-c:  var(--md-sys-color-outline);
    --kt-fg: var(--md-sys-color-on-surface-variant);
    --kt-on: var(--md-sys-color-surface);
}

/* "Original Set" — juga BUKAN Tier (naskah resmi tak bertier); hanya tombol
   saring di daftar Seri. Navy-emas senada stempel & pita kartu Original
   (.kt-card--original): terang = navy berteks emas saat aktif; gelap = emas
   berteks navy, sebab navy di atas latar gelap tak terlihat. */
.kt-tier--original {
    --kt-c:  #0b2243;
    --kt-fg: #9a6b00;
    --kt-on: #ebbd50;
}
[data-theme="dark"] .kt-tier--original { --kt-c: #ebbd50; --kt-fg: #ebbd50; --kt-on: #0b2243; }
@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .kt-tier--original { --kt-c: #ebbd50; --kt-fg: #ebbd50; --kt-on: #0b2243; }
}

/* ── Lencana Tier di kartu ───────────────────────────────────
   Master satu-satunya yang PEKAT di sini: ia puncak tangga dan harus terbaca
   beda JENIS, bukan sekadar lebih merah. Lencana hanya punya SATU keadaan,
   jadi tidak ada yang hilang karenanya — beda dari tombol saring di bawah,
   yang justru butuh dua keadaan. */
.kt-tier {
    align-self: flex-start;
    display: inline-flex; align-items: center; gap: .32rem;
    padding: .16rem .5rem;
    border: 1px solid color-mix(in srgb, var(--kt-c) 38%, transparent);
    border-radius: var(--md-sys-shape-corner-full);
    background: color-mix(in srgb, var(--kt-c) 12%, transparent);
    color: var(--kt-fg);
    font: var(--md-sys-typescale-label-medium-weight) var(--md-sys-typescale-label-medium-size)/1.1 var(--md-sys-typescale-plain);
    white-space: nowrap;
}
.kt-tier--inline { margin-top: 0; }
.kt-tier .bi { font-size: .85em; }
.kt-tier.kt-tier--master {
    background: var(--kt-c);
    color: var(--kt-on);
    border-color: transparent;
}

/* ── Lencana Tier menempel sudut kanan-bawah kartu ───────────
   Dipakai KETIGA jenis kartu: kartu Olimp. (katalog hal. 1, isinya rentang),
   kartu Seri (hal. 2), dan kartu Paket Soal.

   POSISI ABSOLUT, keluar dari alur. Itu yang membuat dua syaratnya terpenuhi
   sekaligus: benar-benar berhimpit dengan tepi kartu, dan tidak menyisakan
   jarak apa pun terhadap isi di atasnya — termasuk `gap` milik .rb-card yang
   tak bisa dihapus oleh margin negatif selama `margin-top: auto` dipakai.

   Jangkarnya .rb-card (satu-satunya `position: relative` di rantai ini), jadi
   ia menempel tepi KARTU, bukan tepi .card-body yang masih punya padding.

   Ruang untuk lencana dipesan lewat padding-bawah kartunya (aturan :has di
   bawah) — tanpa itu ia menimpa baris terakhir isi kartu. */
.kt-tierfoot {
    position: absolute; right: 0; bottom: 0; z-index: 1;
    display: flex; align-items: flex-end;
}
/* Sudut LUAR diratakan: lengkung kartu sendiri yang membentuknya, karena
   .rb-card memotong dengan overflow:hidden. Garisnya pun hanya di sisi yang
   menghadap ke dalam — dua sisi lainnya berimpit dengan garis kartu. */
.kt-tierfoot .kt-tier {
    align-self: auto;
    /* Sudut kiri-ATAS lencana = sudut kanan-BAWAH kartu, angka yang sama persis.
       Keduanya saling membelakangi pada garis bagi sudut yang sama, jadi
       lengkung yang seragam membuatnya terbaca sebagai satu bentuk — bukan
       lencana yang kebetulan ditempelkan di sudut. Tiga sudut lainnya rata:
       yang kanan-bawah dibentuk lengkung kartu sendiri lewat overflow:hidden. */
    border-radius: var(--rb-card-radius, 16px) 0 0 0;
    border-width: 1px 0 0 1px;
    padding: .22rem .6rem .24rem .68rem;
}
/* ── Deret sebaran Tier (kartu Olimp., katalog hal. 1) ───────
   Satu pencacah berikon per Tier yang benar-benar ada di jalur itu. Wadahnya
   NETRAL dan ikonnya yang berwarna: enam kotak berwarna berjajar akan saling
   berteriak dan menghapus urutan tangganya sendiri — di sini yang harus
   terbaca adalah URUTAN rona kiri-ke-kanan, bukan tiap kotak satu per satu.

   Bentuk sudutnya sama persis dengan .kt-tierfoot .kt-tier: ia menempati sudut
   yang sama, jadi lengkung dan garisnya harus mengikuti aturan yang sama. */
.kt-tiermix {
    display: inline-flex; align-items: center; gap: .1rem;
    padding: .2rem .5rem .22rem .58rem;
    border: 1px solid var(--md-sys-color-outline-variant);
    border-width: 1px 0 0 1px;
    border-radius: var(--rb-card-radius, 16px) 0 0 0;
    background: var(--md-sys-color-surface-container-low);
    white-space: nowrap;
}
.kt-tiermix-i {
    display: inline-flex; align-items: center; gap: .15rem;
    padding: 0 .2rem;
    color: var(--kt-fg);
    font: var(--md-sys-typescale-label-medium-weight) var(--md-sys-typescale-label-medium-size)/1.1 var(--md-sys-typescale-plain);
    font-variant-numeric: tabular-nums;
}
.kt-tiermix-i .bi { font-size: .92em; }

/* Lencana JENIS di sudut kanan-bawah kartu ujian (Katalog & daftar Ujian).
   Bentuknya mengikuti .kt-tierfoot .kt-tier supaya menempati sudut yang persis
   sama; yang dibedakan hanya nadanya — emas pekat, karena di kartu ujian inilah
   satu-satunya lencana sudut. Dinaikkan dari <style> lokal halaman Katalog
   begitu daftar Ujian memakainya juga. */
.kt-typefoot {
    display: inline-flex; align-items: center; gap: .3rem;
    padding: .26rem .7rem .28rem .8rem;
    border: 1px solid var(--md-brand-gold, #c8a24a);
    border-width: 1px 0 0 1px;
    border-radius: var(--rb-card-radius, 16px) 0 0 0;
    background: var(--md-brand-gold, #c8a24a);
    color: var(--md-brand-on-gold, #1c1600);
    font: 700 var(--md-sys-typescale-label-medium-size)/1.1 var(--md-sys-typescale-plain);
    letter-spacing: .01em;
    white-space: nowrap;
}
.kt-typefoot .bi { font-size: .95em; }

/* Ruang di dasar kartu supaya isi terakhir tidak tertimpa lencana.

   Dua selektor, SATU nilai — sengaja digabung, bukan ditulis dua kali:
   yang pertama untuk kartu yang kakinya anak langsung kartu (kartu Olimp.),
   yang kedua untuk kartu yang isinya dibungkus .card-body (kartu Seri & kartu
   Paket Soal). Ruangnya harus sama besar di ketiganya — dua angka terpisah
   hanya menunggu untuk berbeda. */
.rb-card:has(> .kt-tierfoot),
.rb-card > .card-body:has(> .kt-tierfoot) { padding-bottom: 1.7rem; }

/* ── Daftar FITUR Seri: Simulasi · Pembahasan ─────────────────
   KETERANGAN ISI Seri, bukan status kepemilikan — ralat pemilik 26 Okt 2026:
   Seri dijual utuh, jadi kartu yang sudah dimiliki dan yang belum memakai
   lencana yang sama persis. Satu baris di atas batang harga kartu Seri dan di
   fakta modal Seri & Paket Soal.

     .kt-ft--sim   Simulasi    biru (warna aksi "Kerjakan"), ikon stopwatch
     .kt-ft--bhs   Pembahasan  ungu, ikon bohlam
     .kt-ft--na    tidak ada di Seri ini — bingkai putus-putus, redup

   Hijau & emas sengaja tidak dipakai: di kartu ini keduanya sudah berarti
   "dimiliki/gratis" dan "harga". */
.kt-feats {
    display: flex; flex-wrap: wrap; align-items: center; gap: .35rem .45rem;
    margin: 0 0 .55rem; min-height: 1.6rem;
}
.kt-ft {
    --ft-c: #1a78cf; --ft-ink: #0d4f8c;
    display: inline-flex; align-items: center; gap: .32rem;
    padding: .14rem .62rem .14rem .16rem;
    border: 1px solid color-mix(in srgb, var(--ft-c) 42%, transparent);
    border-radius: var(--md-sys-shape-corner-full, 999px);
    background: color-mix(in srgb, var(--ft-c) 8%, var(--md-sys-color-surface));
    color: var(--ft-ink);
    font-size: .74rem; font-weight: 700; line-height: 1.3; white-space: nowrap;
}
.kt-ft-ico {
    flex-shrink: 0; width: 1.3rem; height: 1.3rem; border-radius: 50%;
    display: inline-grid; place-items: center;
    background: var(--ft-c); color: #fff; font-size: .68rem;
    box-shadow: 0 1px 2px color-mix(in srgb, var(--ft-c) 45%, transparent);
}
.kt-ft--sim { --ft-c: #1a78cf; --ft-ink: #0d4f8c; }
.kt-ft--bhs { --ft-c: #7c5cd6; --ft-ink: #4b2fa0; }
[data-theme="dark"] .kt-ft--sim { --ft-c: #5aaef0; --ft-ink: #a9d4f7; }
[data-theme="dark"] .kt-ft--bhs { --ft-c: #a892ea; --ft-ink: #d2c6f6; }
[data-theme="dark"] .kt-ft-ico { color: #0f1117; }
.kt-ft.kt-ft--na {
    --ft-c: var(--md-sys-color-outline); --ft-ink: var(--md-sys-color-outline);
    border-style: dashed; background: transparent; font-weight: 600;
}
.kt-ft--na .kt-ft-ico { background: transparent; color: var(--md-sys-color-outline); box-shadow: inset 0 0 0 1px currentColor; }
/* Di dalam fakta modal (dd) barisnya tak butuh jarak bawah kartu. */
.kt-modal-facts .kt-feats { margin: 0; min-height: 0; }

/* ── Batang saring Tier (halaman daftar Seri) ─────────────────
   Menggulir mendatar di ponsel alih-alih membungkus jadi dua baris: tujuh
   tombol yang patah barisnya mendorong kartu pertama turun sampai keluar
   layar, tepat di halaman yang isinya kartu. */
.kt-tierbar {
    display: flex; align-items: center; gap: .4rem;
    margin: -.35rem 0 .9rem; padding-bottom: .15rem;
    overflow-x: auto; scrollbar-width: none;
}
.kt-tierbar::-webkit-scrollbar { display: none; }
.kt-tierbar-label {
    flex-shrink: 0; display: inline-flex; align-items: center; gap: .3rem;
    padding-right: .15rem;
    color: var(--md-sys-color-on-surface-variant);
    font: var(--md-sys-typescale-label-medium-weight) var(--md-sys-typescale-label-medium-size)/1 var(--md-sys-typescale-plain);
}
.kt-tierchip {
    flex-shrink: 0;
    display: inline-flex; align-items: center; gap: .32rem;
    padding: .28rem .6rem;
    border: 1px solid var(--md-sys-color-outline-variant);
    border-radius: var(--md-sys-shape-corner-full);
    background: var(--md-sys-color-surface-container-low);
    color: var(--md-sys-color-on-surface-variant);
    font: var(--md-sys-typescale-label-medium-weight) var(--md-sys-typescale-label-medium-size)/1.1 var(--md-sys-typescale-plain);
    text-decoration: none;
    transition: background .15s, border-color .15s, color .15s;
}
.kt-tierchip:hover { border-color: var(--md-sys-color-outline); }

/* ── Ragam LEGENDA (katalog hal. 1) ───────────────────────────
   Batang yang sama, tetapi MENERANGKAN, bukan menyaring: di halaman itu
   kartunya Varian — bukan Seri — jadi tidak ada yang bisa disaring per Tier.
   Sorot & kursor dimatikan supaya ia tidak berpura-pura bisa diklik; chip yang
   tampak bisa ditekan lalu diam jauh lebih buruk daripada legenda yang jujur. */
.kt-tierbar--legend .kt-tierchip { cursor: default; }
.kt-tierbar--legend .kt-tierchip:hover {
    border-color: color-mix(in srgb, var(--kt-c) 40%, transparent);
}

.kt-tierchip .bi { font-size: .85em; }
.kt-tierchip-n {
    padding: 0 .3rem; border-radius: var(--md-sys-shape-corner-full);
    background: color-mix(in srgb, currentColor 14%, transparent);
    font-variant-numeric: tabular-nums; font-size: .85em;
}

/* KEDUA keadaan berwarna menurut Tier-nya — tombol tidak pernah abu.
   Yang membedakan aktif dari tidak adalah KEPEKATAN, bukan ada/tidaknya warna:

     tidak aktif  tint 12% + garis 40% + teks --kt-fg   (kembar lencana kartu)
     aktif        isian penuh --kt-c + teks --kt-on     (tak mungkin tertukar)

   Bukan outline: tema ini memaksa
   `button:focus:not(:focus-visible){outline:none!important}`, jadi penanda
   berbasis outline lenyap tepat setelah diklik mouse dan terbaca seperti
   tombolnya tidak jalan. */
.kt-tierchip[class*="kt-tier--"] {
    border-color: color-mix(in srgb, var(--kt-c) 40%, transparent);
    background: color-mix(in srgb, var(--kt-c) 12%, transparent);
    color: var(--kt-fg);
}
.kt-tierchip[class*="kt-tier--"]:hover {
    border-color: color-mix(in srgb, var(--kt-c) 65%, transparent);
    background: color-mix(in srgb, var(--kt-c) 18%, transparent);
}
.kt-tierchip[class*="kt-tier--"].is-on,
.kt-tierchip[class*="kt-tier--"].is-on:hover {
    background: var(--kt-c);
    border-color: var(--kt-c);
    color: var(--kt-on);
    font-weight: 650;
}
/* Angka hitungan ikut membalik nada bersama tombolnya. */
.kt-tierchip[class*="kt-tier--"].is-on .kt-tierchip-n {
    background: color-mix(in srgb, var(--kt-on) 22%, transparent);
}
/* Tombol "Semua" tidak punya Tier, jadi ia tetap netral — dan justru itu yang
   membuatnya terbaca sebagai "tanpa saringan", bukan sebagai Tier ketujuh. */
.kt-tierchip.is-on:not([class*="kt-tier--"]) {
    color: var(--md-sys-color-on-surface);
    background: var(--md-sys-color-surface-container-highest);
    border-color: var(--md-sys-color-outline);
    font-weight: 650;
}


/* ============================================================
   PANEL FILTER (komponen x-siswa-filter)

   DUA bentuk, dipilih prop `bar` — dan bedanya bukan selera, melainkan peran:

     kartu (baku)  Kolom cari berdiri sebaris dengan <select> di dalam sebuah
                   formulir perkakas → OUTLINED TEXT FIELD (aturan di bawah).
     batang        Kolom cari berdiri sendiri di puncak halaman, memerintah
                   seluruh isi di bawahnya → SEARCH BAR (pil 56px; aturannya
                   tinggal bersama komponennya di siswa-filter.blade.php).

   Tombol Filter jadi chip filter yang bisa terpilih, tombol Reset jadi text
   button.
   ============================================================ */
.rb-filter-card {
    margin-bottom: 16px;
    background: transparent;
    border: none;
}
.rb-filter-card > .card-body { padding: 0; }

/* Bentuk KARTU: kolom pencari = OUTLINED TEXT FIELD M3 (sudut 4px, garis 1px),
   BUKAN komponen "Search bar" yang berbentuk pil.

   Alasannya spesifik: komponen Search bar M3 adalah elemen navigasi tingkat
   atas yang membuka "search view" — bukan kolom di dalam formulir. Di panel
   filter, kolom ini berdiri sebaris dengan <select> di bawahnya, jadi ia
   memang text field. Menjadikannya pil menciptakan lompatan bentuk pil→kotak
   yang tampak tidak konsisten; sebagai text field, ketiganya kini seragam 4px.

   Aturan di bawah ini juga menjadi DASAR bentuk batang — yang ditimpanya hanya
   bidang & sudutnya, sedangkan ikon-di-dalam-alur dan input tanpa bingkai
   sendiri dipakai kedua bentuk. */
.rb-filter-search-wrap {
    display: flex; align-items: center;
    min-height: var(--md-field-height);
    padding: 0 16px;
    background: var(--md-sys-color-surface);
    border: 1px solid var(--md-sys-color-outline);
    border-radius: var(--md-sys-shape-corner-extra-small);
    transition: border-color var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
}
/* Fokus: garis menebal jadi 2px primary — persis text field M3, bukan cincin
   luar. Padding disusut 1px agar tingginya tidak melompat. */
.rb-filter-search-wrap:focus-within {
    border-color: var(--md-sys-color-primary);
    border-width: 2px;
    padding: 0 15px;
    outline: none;
}
/* Ikon kaca pembesar diposisikan absolut oleh markup; di dalam text field ia
   duduk di alur sebagai leading icon, jadi posisinya dikembalikan ke statik. */
.rb-filter-search-wrap > .bi-search,
.rb-filter-form .position-relative > .bi-search {
    position: static !important;
    transform: none !important;
    margin-right: 12px;
    font-size: 22px;
    color: var(--md-sys-color-on-surface-variant) !important;
    flex: 0 0 auto;
}
.rb-filter-form .form-control.rb-filter-search,
.rb-filter-search {
    flex: 1 1 auto; min-width: 0;
    padding: 0 !important;
    min-height: auto;
    background: transparent !important;
    border: none !important;
    border-radius: 0;
    color: var(--md-sys-color-on-surface);
    font: 400 var(--md-sys-typescale-body-large-size)/var(--md-sys-typescale-body-large-line-height) var(--md-sys-typescale-plain);
}
.rb-filter-search:focus { outline: none !important; box-shadow: none !important; border: none !important; padding: 0 !important; }

.rb-filter-spinner {
    position: absolute; right: 16px; top: 50%; transform: translateY(-50%);
    width: 20px; height: 20px;
    color: var(--md-sys-color-primary);
    opacity: 0;
    transition: opacity var(--md-sys-motion-duration-short3) var(--md-sys-motion-easing-standard);
    pointer-events: none;
}
.rb-filter-form.is-loading .rb-filter-spinner { opacity: 1; }

/* Tombol Filter → chip filter M3 yang bisa terpilih. */
.btn-filter-toggle {
    min-height: var(--md-control-height);
    padding: 0 16px;
    border-radius: var(--md-sys-shape-corner-small);
    background: transparent;
    color: var(--md-sys-color-on-surface-variant);
    box-shadow: inset 0 0 0 1px var(--md-sys-color-outline);
}
.btn-filter-toggle:hover { background: transparent; color: var(--md-sys-color-on-surface); }
.btn-filter-toggle.is-active {
    background: var(--md-sys-color-secondary-container);
    color: var(--md-sys-color-on-secondary-container);
    box-shadow: none;
}
/* Tombol Reset → text button. */
.btn-filter-reset, .btn-soft-gold, .btn-soft-primary {
    min-height: var(--md-control-height);
    border-radius: var(--md-sys-shape-corner-small);
}
.rb-filter-panel { padding-top: 12px; }
.rb-filter-panel .rb-eyebrow { margin-bottom: 6px; }

/* Panel filter lawas (halaman yang belum memakai komponen). */
.filter-panel-wrapper {
    background: var(--md-sys-color-surface-container-low);
    border: 1px solid var(--md-sys-color-outline-variant);
    border-radius: var(--md-sys-shape-corner-medium);
    padding: 16px; margin-bottom: 16px;
}
.filter-toggle-btn {
    width: 100%;
    display: flex; justify-content: space-between; align-items: center;
    min-height: var(--md-control-height);
    padding: 0 16px;
    background: transparent;
    border: 1px solid var(--md-sys-color-outline);
    border-radius: var(--md-sys-shape-corner-small);
    color: var(--md-sys-color-on-surface-variant);
}
.filter-toggle-btn[aria-expanded="true"] {
    background: var(--md-sys-color-secondary-container);
    color: var(--md-sys-color-on-secondary-container);
    border-color: transparent;
}
.filter-panel, .filter-section { background-color: var(--md-sys-color-surface-container); }

/* ── Keadaan memuat (AJAX) ──
   Hasil ditutup tabir + indikator, bukan dikosongkan: tinggi halaman tidak
   melompat sehingga posisi gulir pengguna tetap terjaga saat filter berganti.
   Peredupan memakai tabir ::before, BUKAN opacity pada kontainernya — opacity
   akan ikut meredupkan indikator ::after di dalamnya sehingga justru samar. */
.rb-results-loading { position: relative; pointer-events: none; }
.rb-results-loading::before {
    content: '';
    position: absolute; inset: 0; z-index: 4;
    background: var(--rb-loading-veil);
    border-radius: var(--md-sys-shape-corner-large);
}
.rb-results-loading::after {
    content: '';
    position: absolute; z-index: 5;
    left: 50%; top: 40px;
    width: 40px; height: 40px;
    margin-left: -20px;
    background: var(--md-sys-color-primary);
    animation: md-loading-morph var(--md-sys-motion-duration-extra-long4) var(--md-sys-motion-easing-emphasized) infinite,
               md-loading-spin 2s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
    .rb-results-loading::after { animation: none; border-radius: 50%; }
}


/* ============================================================
   TABEL — dan perubahannya jadi kartu di layar sempit
   ============================================================ */
.table { color: var(--md-sys-color-on-surface); --bs-table-bg: transparent; }
.table > :not(caption) > * > * {
    border-bottom-color: var(--md-sys-color-outline-variant);
    background: transparent;
    padding: 12px;
}
.table thead th {
    color: var(--md-sys-color-on-surface-variant);
    font: var(--md-sys-typescale-title-small-weight) var(--md-sys-typescale-title-small-size)/var(--md-sys-typescale-title-small-line-height) var(--md-sys-typescale-plain);
    border-bottom-color: var(--md-sys-color-outline-variant);
    text-transform: none;
    letter-spacing: normal;
}

@media (max-width: 767.98px) {
    .table-responsive-mobile table,
    .table-responsive-mobile thead,
    .table-responsive-mobile tbody,
    .table-responsive-mobile th,
    .table-responsive-mobile td,
    .table-responsive-mobile tr { display: block; }
    .table-responsive-mobile thead tr { position: absolute; top: -9999px; left: -9999px; }
    .table-responsive-mobile tr {
        border: 1px solid var(--md-sys-color-outline-variant);
        border-radius: var(--md-sys-shape-corner-medium);
        margin-bottom: 12px;
        background: var(--md-sys-color-surface);
        padding: 12px;
    }
    .table-responsive-mobile td {
        border: none;
        border-bottom: 1px solid var(--md-sys-color-outline-variant);
        position: relative;
        padding-left: 45% !important;
        text-align: right;
        min-height: 44px;
        display: flex; align-items: center; justify-content: flex-end;
    }
    .table-responsive-mobile td::before {
        content: attr(data-label);
        position: absolute; top: 50%; left: 12px;
        transform: translateY(-50%);
        width: 40%; padding-right: 10px;
        white-space: nowrap; text-align: left;
        font-weight: 600;
        color: var(--md-sys-color-on-surface-variant);
    }
    .table-responsive-mobile td:last-child { border-bottom: 0; }
}


/* ============================================================
   PAGINASI
   ============================================================ */
.pagination { gap: 4px; }
.page-link {
    display: flex; align-items: center; justify-content: center;
    min-width: 40px; height: 40px;
    padding: 0 8px;
    border: none;
    border-radius: var(--md-sys-shape-corner-full);
    background: transparent;
    color: var(--md-sys-color-on-surface-variant);
    font: var(--md-sys-typescale-label-large-weight, 500) var(--md-sys-typescale-label-large-size)/1 var(--md-sys-typescale-plain);
}
.page-link:hover { background: color-mix(in srgb, var(--md-sys-color-on-surface) 8%, transparent); color: var(--md-sys-color-on-surface); }
.page-item.active .page-link {
    background: var(--md-sys-color-secondary-container);
    color: var(--md-sys-color-on-secondary-container);
}
.page-item.disabled .page-link { color: color-mix(in srgb, var(--md-sys-color-on-surface) 38%, transparent); background: transparent; }


/* ============================================================
   SELECT2 — disamakan dengan text field outlined M3

   Select2 menyuntik markupnya sendiri, jadi ia tidak ikut bridge Bootstrap di
   m3.css dan harus ditulis ulang di sini. Sasarannya: tidak ada yang bisa
   membedakan mana <select> asli dan mana Select2.
   ============================================================ */
.select2-container { width: 100% !important; }

.select2-container--default .select2-selection--single {
    height: var(--md-field-height) !important;
    padding: 0 16px !important;
    display: flex !important;
    align-items: center !important;
    border: 1px solid var(--md-sys-color-outline) !important;
    border-radius: var(--md-sys-shape-corner-extra-small) !important;
    background-color: var(--md-sys-color-surface) !important;
    transition: border-color var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
}
.select2-container--default .select2-selection--single .select2-selection__rendered {
    padding: 0 !important; margin: 0 !important;
    line-height: normal !important;
    font: 400 var(--md-sys-typescale-body-large-size)/var(--md-sys-typescale-body-large-line-height) var(--md-sys-typescale-plain);
    color: var(--md-sys-color-on-surface) !important;
    display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.select2-container--default .select2-selection--single .select2-selection__placeholder { color: var(--md-sys-color-on-surface-variant) !important; }
.select2-container--default .select2-selection--single .select2-selection__arrow {
    height: 100% !important; top: 0 !important; right: 12px !important;
    display: flex; align-items: center;
}
.select2-container--default .select2-selection--single .select2-selection__arrow b {
    border-color: var(--md-sys-color-on-surface-variant) transparent transparent transparent !important;
}
.select2-container--default .select2-selection--single .select2-selection__clear {
    margin-right: 0 !important; padding-right: 0 !important;
    height: auto !important; line-height: 1; font-size: 1.1rem;
    color: var(--md-sys-color-on-surface-variant);
    float: none !important; order: 2;
}

.select2-container--default .select2-selection--multiple {
    min-height: var(--md-field-height) !important;
    padding: 10px 12px !important;
    border: 1px solid var(--md-sys-color-outline) !important;
    border-radius: var(--md-sys-shape-corner-extra-small) !important;
    background-color: var(--md-sys-color-surface) !important;
    cursor: text !important;
}
.select2-container--default .select2-selection--multiple .select2-selection__rendered {
    display: flex !important; flex-wrap: wrap !important; align-items: center !important;
    padding: 0 !important; margin: 0 !important; list-style: none !important;
    gap: 6px; width: 100%; min-height: 32px;
}
/* Setiap pilihan = input chip M3: tinggi 32, sudut 8, bidang container. */
.select2-container--default .select2-selection--multiple .select2-selection__choice {
    margin: 0 !important;
    padding: 0 12px 0 30px !important;
    height: 32px;
    display: inline-flex !important; align-items: center;
    border-radius: var(--md-sys-shape-corner-small);
    background-color: var(--md-sys-color-secondary-container) !important;
    border: none !important;
    color: var(--md-sys-color-on-secondary-container);
    font: var(--md-sys-typescale-label-large-weight, 500) var(--md-sys-typescale-label-large-size)/1 var(--md-sys-typescale-plain);
    position: relative; max-width: 100%;
}
.select2-container--default .select2-selection--multiple .select2-selection__choice__display { padding: 0 !important; cursor: default; }
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
    position: absolute; left: 0; top: 0; height: 100%;
    display: flex; align-items: center; justify-content: center;
    width: 30px; padding: 0 !important;
    color: var(--md-sys-color-on-secondary-container) !important;
    background: transparent !important;
    border: none !important;
    font-size: 1rem;
}
.select2-container--default .select2-selection--multiple .select2-search--inline {
    display: inline-flex !important; align-items: center !important;
    padding: 0 !important; margin: 0 !important; float: none !important; flex: 0 1 auto;
}
.select2-container--default .select2-selection--multiple .select2-search--inline .select2-search__field {
    margin: 0 !important; padding: 0 !important;
    height: 32px !important;
    font: 400 var(--md-sys-typescale-body-large-size)/32px var(--md-sys-typescale-plain);
    color: var(--md-sys-color-on-surface);
    border: none !important; outline: none !important;
    width: auto !important; max-width: 100%; background: transparent;
}
.select2-container--default .select2-selection--multiple .select2-search--inline .select2-search__field::placeholder { color: var(--md-sys-color-on-surface-variant); }

.select2-container--default.select2-container--focus .select2-selection--single,
.select2-container--default.select2-container--focus .select2-selection--multiple,
.select2-container--default.select2-container--open .select2-selection--single,
.select2-container--default.select2-container--open .select2-selection--multiple {
    border-color: var(--md-sys-color-primary) !important;
    border-width: 2px !important;
    box-shadow: none !important;
    outline: 0 !important;
}

/* Daftar pilihan → menu M3. */
.select2-dropdown {
    border: none;
    border-radius: var(--md-sys-shape-corner-extra-small);
    box-shadow: var(--md-sys-elevation-level2);
    background: var(--md-sys-color-surface-container);
    z-index: 1060;
}
.select2-results__option {
    display: flex; align-items: center;
    min-height: 48px;
    padding: 0 12px;
    font: 400 var(--md-sys-typescale-body-large-size)/var(--md-sys-typescale-body-large-line-height) var(--md-sys-typescale-plain);
    color: var(--md-sys-color-on-surface);
    background: transparent;
}
.select2-container--default .select2-results__option--highlighted.select2-results__option--selectable {
    background-color: color-mix(in srgb, var(--md-sys-color-on-surface) 8%, transparent);
    color: var(--md-sys-color-on-surface);
}
.select2-container--default .select2-results__option--selected {
    background-color: var(--md-sys-color-secondary-container);
    color: var(--md-sys-color-on-secondary-container);
}
.select2-search--dropdown { padding: 8px; }
.select2-search--dropdown .select2-search__field {
    min-height: var(--md-control-height);
    padding: 0 12px;
    border: 1px solid var(--md-sys-color-outline) !important;
    border-radius: var(--md-sys-shape-corner-extra-small);
    background: var(--md-sys-color-surface);
    color: var(--md-sys-color-on-surface);
    outline: none;
}
.select2-search--dropdown .select2-search__field:focus {
    border-color: var(--md-sys-color-primary) !important;
    box-shadow: none;
}


/* ============================================================
   MOTION

   `.rb-animate` dipakai puluhan kali sebagai animasi masuk. Kurvanya diganti
   easing emphasized-decelerate M3 — elemen yang datang melambat menjelang
   tempatnya, bukan mengayun melewati.
   ============================================================ */
@keyframes rbFadeUp {
    from { opacity: 0; transform: translateY(12px); }
    to   { opacity: 1; transform: none; }
}
.rb-animate {
    animation: rbFadeUp var(--md-sys-motion-duration-medium4) var(--md-sys-motion-easing-emphasized-decelerate) both;
}
@media (prefers-reduced-motion: reduce) {
    .rb-animate { animation: none; }
}

/* Input angka: panah putar dilepas — di panel ini semua kolom angka diisi
   dengan mengetik, dan panahnya hanya menyempitkan ruang teks. */
input[type=number] { -moz-appearance: textfield; }
input[type=number]::-webkit-outer-spin-button,
input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }


/* ============================================================================
   SHELL PANEL SISWA — navigasi M3

   Sebelumnya seluruh blok ini hidup sebagai <style> inline sepanjang 482 baris
   di layout/master.blade.php. Dipindahkan ke sini tanpa mengubah satu pun nama
   kelas — jadi markup master.blade.php dan sidebar-siswa.blade.php tidak perlu
   dirombak — tetapi tampilannya kini empat komponen navigasi M3:

       .sidebar          → navigation drawer
       .main-header      → top app bar (small)
       .bottom-nav       → navigation bar
       .transaction-item → list item

   Drawer SENGAJA tetap navy di kedua tema, sama seperti logo di kepalanya.
   ============================================================================ */
:root {
    --sidebar-width: 280px;
    --header-height: 64px;
    --bottom-nav-height: 64px;
    --bottom-nav-gap: max(12px, env(safe-area-inset-bottom));
    /* Nama lama yang masih dirujuk beberapa view. */
    --primary: var(--md-sys-color-primary);
    --primary-dark: var(--md-sys-color-on-primary-container);
    --gold: var(--md-brand-gold);
    --sidebar-color: var(--md-brand-on-navy-variant);
    --sidebar-active: var(--md-brand-gold);
    --sidebar-hover: transparent;
}

/* ── Navigation drawer ── */
.sidebar {
    position: fixed; top: 0; left: 0;
    width: var(--sidebar-width); height: 100vh;
    z-index: 1050;
    display: flex; flex-direction: column;
    overflow-y: auto; overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
    background: var(--md-brand-navy);
    background-image: var(--md-brand-grad-navy);
    color: var(--md-brand-on-navy);
    /* Drawer permanen di layar lebar tidak berbayang di M3 — ia sebidang
       dengan kanvas, dipisahkan oleh warnanya sendiri. */
    box-shadow: none;
    transition: transform var(--md-sys-motion-duration-medium4) var(--md-sys-motion-easing-emphasized);
}
.sidebar::after { content: none; }
.sidebar-brand {
    height: var(--header-height);
    flex: 0 0 auto;
    padding: 0 16px;
    display: flex; align-items: center; gap: 12px;
    position: sticky; top: 0; z-index: 2;
    background: var(--md-brand-navy-dim);
    border-bottom: none;
    backdrop-filter: none; -webkit-backdrop-filter: none;
}
.sidebar-close {
    display: none;
    width: 40px; height: 40px; margin-left: auto;
    align-items: center; justify-content: center;
    border: none; background: transparent;
    border-radius: var(--md-sys-shape-corner-full);
    color: var(--md-brand-on-navy-variant);
    font-size: 22px; cursor: pointer;
}
.sidebar-close:hover { background: rgba(255,255,255,.08); color: var(--md-brand-on-navy); }
.sidebar-menu { padding: 12px; flex: 1 1 auto; }
.menu-label {
    padding: 16px 16px 8px;
    color: var(--md-brand-on-navy-variant);
    font: var(--md-sys-typescale-title-small-weight) var(--md-sys-typescale-title-small-size)/1 var(--md-sys-typescale-plain);
    text-transform: none;
    letter-spacing: normal;
}

/* Item drawer M3: tinggi 56, sudut PENUH, ikon 24, label label-large.
   Sudut penuh itulah penanda terpilih di M3 — menggantikan garis aksen di tepi
   kiri yang dipakai desain lama. */
.menu-item {
    position: relative;
    isolation: isolate;
    display: flex; align-items: center; gap: 12px;
    height: 56px;
    padding: 0 24px 0 16px;
    margin-bottom: 4px;
    border-radius: var(--md-sys-shape-corner-full);
    color: var(--md-brand-on-navy-variant);
    text-decoration: none;
    font: var(--md-sys-typescale-label-large-weight, 500) var(--md-sys-typescale-label-large-size)/1 var(--md-sys-typescale-plain);
    letter-spacing: var(--md-sys-typescale-label-large-tracking);
    transition: background-color var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard),
                color var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
}
.menu-item::after {
    content: ''; position: absolute; inset: 0; border-radius: inherit;
    background: currentColor; opacity: 0; pointer-events: none;
    transition: opacity var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
}
.menu-item:hover::after  { opacity: var(--md-sys-state-hover-opacity); }
.menu-item:active::after { opacity: var(--md-sys-state-pressed-opacity); }
.menu-item:hover { color: var(--md-brand-on-navy); background: transparent; transform: none; }
/* Ubin ikon desain lama dilepas: di M3 ikon item drawer berdiri sendiri tanpa
   bidang. Elemennya dipertahankan agar markup tidak perlu diubah. */
.menu-item .menu-icon {
    width: 24px; height: 24px; min-width: 24px;
    display: flex; align-items: center; justify-content: center;
    background: transparent;
    border-radius: 0;
    font-size: 24px;
    box-shadow: none;
}
.menu-item:hover .menu-icon { background: transparent; }
.menu-item.active {
    background: var(--md-brand-gold);
    color: var(--md-brand-on-gold);
    box-shadow: none;
    font-weight: 600;
}
.menu-item.active::before { content: none; }
.menu-item.active::after { opacity: 0; }
.menu-item.active .menu-icon { background: transparent; color: var(--md-brand-on-gold); box-shadow: none; }
/* Badge di ujung item. */
.menu-item .badge { margin-left: auto; }
.menu-item.active .badge.bg-danger { background: var(--md-brand-on-gold) !important; color: var(--md-brand-gold); }

.sidebar-credit {
    padding: 12px 16px;
    text-align: center;
    color: var(--md-brand-on-navy-variant);
    border-top: 1px solid rgba(255,255,255,.10);
    font: 400 var(--md-sys-typescale-body-small-size)/var(--md-sys-typescale-body-small-line-height) var(--md-sys-typescale-plain);
}
.sidebar-credit a { color: var(--md-brand-gold); text-decoration: underline; }

/* Scrim drawer modal (layar sempit). */
.sidebar-backdrop {
    display: none; position: fixed; inset: 0;
    z-index: 1045;
    background: var(--md-sys-color-scrim);
    opacity: .32;
    backdrop-filter: none;
}

/* State ringkas di desktop — disimpan JS di localStorage. */
html.sidebar-collapsed-init .sidebar { transform: translateX(-100%); transition: none !important; }
html.sidebar-collapsed-init .main-wrapper { margin-left: 0; transition: none !important; }
.sidebar.sidebar-collapsed { transform: translateX(-100%); }
.main-wrapper.sidebar-collapsed { margin-left: 0; }

/* ── Kerangka utama ── */
.main-wrapper {
    margin-left: var(--sidebar-width);
    min-height: 100vh;
    display: flex; flex-direction: column;
    position: relative; z-index: 1;
    transition: margin-left var(--md-sys-motion-duration-medium4) var(--md-sys-motion-easing-emphasized);
}

/* ── Top app bar ──
   64px, tanpa kaca. Saat halaman digulir bar naik ke surface-container +
   elevasi 2 — isyarat M3 bahwa ada isi yang lewat di bawahnya. Kelas
   .is-scrolled dipasang skrip di master.blade.php. */
.main-header {
    height: var(--header-height);
    display: flex; align-items: center; justify-content: space-between;
    gap: 8px;
    padding: 0 8px 0 12px;
    position: sticky; top: 0; z-index: 1030;
    background: var(--md-sys-color-surface);
    border-bottom: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    transition: background-color var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard),
                box-shadow var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
}
.main-header.is-scrolled {
    background: var(--md-sys-color-surface-container);
    box-shadow: var(--md-sys-elevation-level2);
}
.main-header::after { content: none; }
.header-left  { display: flex; align-items: center; gap: 4px; min-width: 0; flex: 1; }
.header-right { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }
.header-brand-mini { display: none; align-items: center; min-width: 0; overflow: hidden; margin-left: 4px; }
.header-brand-mini img { height: 30px; width: auto; max-width: 100%; display: block; object-fit: contain; object-position: left center; }
.header-brand-mini .logo-dark { display: none; }
[data-theme="dark"] .header-brand-mini .logo-light { display: none; }
[data-theme="dark"] .header-brand-mini .logo-dark  { display: block; }

/* Tombol ikon di top app bar → standard icon button M3: tanpa bidang, tanpa
   garis, hanya state layer. Ini perubahan yang paling terasa dari desain lama
   (lingkaran bergaris) dan memang disengaja: bar atas M3 harus terbaca lapang. */
.hamburger,
.head-icon-btn,
.btn-back-circle {
    position: relative;
    isolation: isolate;
    display: flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; min-width: 40px;
    flex: 0 0 auto; padding: 0 !important;
    background: transparent;
    border: none;
    border-radius: var(--md-sys-shape-corner-full) !important;
    color: var(--md-sys-color-on-surface-variant);
    font-size: 22px; line-height: 1;
    text-decoration: none; cursor: pointer;
    transition: color var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
}
.hamburger::after, .head-icon-btn::after, .btn-back-circle::after {
    content: ''; position: absolute; inset: 0; border-radius: inherit;
    background: currentColor; opacity: 0; pointer-events: none;
    transition: opacity var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
}
.hamburger:hover::after, .head-icon-btn:hover::after, .btn-back-circle:hover::after { opacity: var(--md-sys-state-hover-opacity); }
.hamburger:active::after, .head-icon-btn:active::after, .btn-back-circle:active::after { opacity: var(--md-sys-state-pressed-opacity); }
.hamburger:hover, .head-icon-btn:hover, .btn-back-circle:hover {
    color: var(--md-sys-color-on-surface);
    background: transparent;
    border-color: transparent;
    transform: none;
}
/* Area sentuh 48px tanpa membesarkan lingkarannya. */
.hamburger::before, .head-icon-btn::before, .btn-back-circle::before {
    content: ''; position: absolute; top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    width: var(--md-touch-target); height: var(--md-touch-target);
    min-height: 0;
}

/* Saldo koin → assist chip M3 bernada gold. Bentuknya pil karena ANGKA-nya
   yang harus terbaca: lebarnya mengikuti isi, tingginya disamakan dengan
   tombol ikon di sebelahnya agar barisnya tetap lurus. */
.head-coin-pill {
    position: relative;
    isolation: isolate;
    display: flex; align-items: center; gap: 8px;
    height: 40px; padding: 0 16px; flex: 0 0 auto;
    border-radius: var(--md-sys-shape-corner-full);
    background: var(--md-brand-gold-container);
    color: var(--md-brand-on-gold-container);
    border: none;
    text-decoration: none; white-space: nowrap;
    font: var(--md-sys-typescale-label-large-weight, 500) var(--md-sys-typescale-label-large-size)/1 var(--md-sys-typescale-plain);
}
.head-coin-pill::after {
    content: ''; position: absolute; inset: 0; border-radius: inherit;
    background: currentColor; opacity: 0; pointer-events: none;
    transition: opacity var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
}
.head-coin-pill:hover::after { opacity: var(--md-sys-state-hover-opacity); }
.head-coin-pill:hover { color: var(--md-brand-on-gold-container); background: var(--md-brand-gold-container); border-color: transparent; transform: none; }
.head-coin-pill .bi { font-size: 18px; line-height: 1; }
.head-coin-pill .head-coin-val { font-variant-numeric: tabular-nums; }
[data-theme="dark"] .head-coin-pill,
[data-theme="dark"] .head-coin-pill:hover { background: var(--md-brand-on-gold-container); color: var(--md-brand-gold-container); }

/* Tombol pengguna → text button beravatar. */
.user-dropdown .btn {
    display: flex; align-items: center; gap: 8px;
    height: 40px; min-height: 40px; padding: 4px 12px 4px 4px;
    background: transparent;
    border: none;
    border-radius: var(--md-sys-shape-corner-full);
    color: var(--md-sys-color-on-surface);
    font: var(--md-sys-typescale-label-large-weight, 500) var(--md-sys-typescale-label-large-size)/1 var(--md-sys-typescale-plain);
    white-space: nowrap;
}
.user-dropdown .btn:hover { background: transparent; color: var(--md-sys-color-on-surface); box-shadow: none; border-color: transparent; }
.user-dropdown .btn::before { content: none; }
.user-avatar {
    width: 32px; height: 32px; min-width: 32px;
    border-radius: var(--md-sys-shape-corner-full);
    display: flex; align-items: center; justify-content: center;
    overflow: hidden;
    background: var(--md-sys-color-primary-container);
    color: var(--md-sys-color-on-primary-container);
    border: none; box-shadow: none;
    font: var(--md-sys-typescale-title-small-weight) var(--md-sys-typescale-title-small-size)/1 var(--md-sys-typescale-plain);
}
.user-avatar img { width: 100%; height: 100%; object-fit: cover; }

/* Tombol putar tema — ikon dipilih oleh kelas .is-light/.is-dark. */
.theme-toggle .ti-light, .theme-toggle .ti-dark { display: none; }
.theme-toggle.is-light .ti-light { display: inline; }
.theme-toggle.is-dark  .ti-dark  { display: inline; }
/* Pemilih tema di dropdown pengguna (pengganti tombol header di layar sempit).
   Sengaja memakai .is-active, bukan .active, agar tidak kena blok warna penuh
   milik Bootstrap — cukup centang beraksen. */
.theme-mode-item { width: 100%; text-align: left; border: 0; background: transparent; }
.theme-mode-item .theme-mode-check { opacity: 0; color: var(--md-sys-color-primary); }
.theme-mode-item.is-active { color: var(--md-sys-color-primary); font-weight: 600; }
.theme-mode-item.is-active .theme-mode-check { opacity: 1; }

/* ── Isi halaman ── */
.content-wrapper {
    flex: 1;
    width: 100%; max-width: 1340px; margin: 0 auto;
    padding: clamp(12px, 2.4vw, 24px);
}
.page-header { margin-bottom: clamp(12px, 2.5vw, 20px); }
.page-header h4, .page-header .page-title {
    margin: 0;
    font: 600 var(--md-sys-typescale-headline-small-size)/var(--md-sys-typescale-headline-small-line-height) var(--md-sys-typescale-brand);
    letter-spacing: -.015em;
    color: var(--md-sys-color-on-surface);
}
.page-header .breadcrumb {
    margin: 0; padding: 0; background: transparent;
    font: 400 var(--md-sys-typescale-body-small-size)/var(--md-sys-typescale-body-small-line-height) var(--md-sys-typescale-plain);
    --bs-breadcrumb-divider-color: var(--md-sys-color-on-surface-variant);
}
.page-header .breadcrumb-item a { color: var(--md-sys-color-primary); text-decoration: none; font-weight: 500; }
.page-header .breadcrumb-item.active { color: var(--md-sys-color-on-surface-variant); }
.page-header-flex { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; flex-wrap: wrap; }

.siswa-panel-footer {
    display: flex; justify-content: space-between; align-items: center;
    padding: 16px 24px;
    border-top: 1px solid var(--md-sys-color-outline-variant);
    background: transparent;
    color: var(--md-sys-color-on-surface-variant);
    font: 400 var(--md-sys-typescale-body-small-size)/var(--md-sys-typescale-body-small-line-height) var(--md-sys-typescale-plain);
}
.siswa-panel-footer a { color: var(--md-sys-color-primary); text-decoration: none; font-weight: 500; }
.siswa-panel-footer a:hover { text-decoration: underline; }
.siswa-panel-footer-links { display: flex; flex-wrap: wrap; gap: 4px 18px; justify-content: center; }

/* ── Navigation bar (layar sempit) — pil mengambang, kesan premium ──
   Ditinjau ulang total: bar tidak lagi menempel penuh di tepi layar (itu
   terasa seperti sisa browser chrome, bukan bagian dari produk), melainkan
   mengambang dengan jarak dari tepi, kaca buram (backdrop-filter), dan
   elevasi bertingkat — kombinasi yang dipakai aplikasi premium (Threads,
   Spotify) untuk navigasi utama. Indikator item aktif adalah pil EMAS
   bergradasi (--md-brand-grad-gold), bukan tonal container netral: bottom
   nav adalah elemen paling sering disentuh siswa, jadi ia layak memakai
   sentuhan "signature" gold yang di tempat lain dijaga eksklusif untuk
   drawer & aksi utama. */
.bottom-nav {
    display: none;
    position: fixed;
    left: 12px; right: 12px;
    bottom: var(--bottom-nav-gap);
    z-index: 1040;
    height: var(--bottom-nav-height);
    padding: 6px 8px;
    border-radius: var(--md-sys-shape-corner-extra-large);
    background: var(--md-sys-color-surface-container-high);
    background: color-mix(in srgb, var(--md-sys-color-surface-container-high) 92%, transparent);
    backdrop-filter: blur(20px) saturate(180%);
    -webkit-backdrop-filter: blur(20px) saturate(180%);
    border: 1px solid color-mix(in srgb, var(--md-sys-color-outline-variant) 55%, transparent);
    box-shadow: var(--md-sys-elevation-level3), 0 16px 32px -12px rgba(0,0,0,.28);
    align-items: stretch; justify-content: space-around;
    transition: transform var(--md-sys-motion-duration-medium2) var(--md-sys-motion-easing-emphasized);
}
.bottom-nav-item {
    position: relative;
    flex: 1 1 0; min-width: 0;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
    padding: 0;
    border-radius: var(--md-sys-shape-corner-large);
    text-decoration: none;
    color: var(--md-sys-color-on-surface-variant);
    font: var(--md-sys-typescale-label-small-weight) 10px/12px var(--md-sys-typescale-plain);
    letter-spacing: var(--md-sys-typescale-label-small-tracking);
    -webkit-tap-highlight-color: transparent;
    transition: color var(--md-sys-motion-duration-medium1) var(--md-sys-motion-easing-emphasized);
}
.bottom-nav-item i {
    position: relative;
    display: flex; align-items: center; justify-content: center;
    width: 48px; height: 32px; margin-bottom: 0;
    border-radius: var(--md-sys-shape-corner-full);
    font-size: 21px;
    transition: background var(--md-sys-motion-duration-medium2) var(--md-sys-motion-easing-emphasized),
                color var(--md-sys-motion-duration-medium2) var(--md-sys-motion-easing-emphasized),
                transform var(--md-sys-motion-duration-medium2) var(--md-sys-motion-easing-emphasized),
                box-shadow var(--md-sys-motion-duration-medium2) var(--md-sys-motion-easing-emphasized);
}
.bottom-nav-item > span:not(.bottom-nav-badge) {
    display: block; width: 100%;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: center;
    transition: font-weight var(--md-sys-motion-duration-medium1) var(--md-sys-motion-easing-emphasized);
}
.bottom-nav-item.active { color: var(--md-brand-gold-deep); }
[data-theme="dark"] .bottom-nav-item.active { color: var(--md-brand-gold-bright); }
.bottom-nav-item.active > span:not(.bottom-nav-badge) { font-weight: 600; }
.bottom-nav-item.active i {
    background: var(--md-brand-grad-gold);
    color: var(--md-brand-on-gold);
    transform: translateY(-3px);
    box-shadow: 0 6px 14px -4px color-mix(in srgb, var(--md-brand-gold) 60%, transparent);
}
.bottom-nav-item.active::before { content: none; }
.bottom-nav-item:hover { color: var(--md-sys-color-on-surface); }
.bottom-nav-item.active:hover { color: var(--md-brand-gold-deep); }
[data-theme="dark"] .bottom-nav-item.active:hover { color: var(--md-brand-gold-bright); }
/* Badge menempel di kanan-atas pil ikon; cincin selebar 2px senada latar bar
   supaya terlihat "memotong" pil, bukan menumpuk kasar di atasnya. */
.bottom-nav-badge {
    position: absolute; top: -1px; left: 50%; margin-left: 6px;
    min-width: 16px; height: 16px; padding: 0 4px;
    box-sizing: border-box;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: var(--md-sys-shape-corner-full);
    background: var(--md-sys-color-error); color: var(--md-sys-color-on-error);
    font: 600 11px/1 var(--md-sys-typescale-plain);
    border: 2px solid var(--md-sys-color-surface-container-high);
    box-shadow: none;
}

/* ── Baris transaksi → list item M3 ── */
.transaction-item {
    display: flex; flex-direction: column;
    padding: 12px 0;
    min-height: 72px; justify-content: center;
    border-bottom: 1px solid var(--md-sys-color-outline-variant);
}
.transaction-item:last-child { border-bottom: none; }
.transaction-item .btn { cursor: pointer !important; position: relative; z-index: 2; }
.transaction-icon {
    width: 40px; height: 40px; min-width: 40px;
    display: flex; align-items: center; justify-content: center;
    border-radius: var(--md-sys-shape-corner-full);
    font-size: 20px;
    background: var(--md-sys-color-secondary-container);
    color: var(--md-sys-color-on-secondary-container);
}
.transaction-icon.income, .transaction-icon.schedule { background: var(--md-sys-color-primary-container); color: var(--md-sys-color-on-primary-container); }
.transaction-icon.expense, .transaction-icon.payment-pending { background: var(--md-brand-gold-container); color: var(--md-brand-on-gold-container); }
.transaction-icon.payment { background: #b8f1c0; color: #002107; }
.transaction-icon.payment-expired { background: var(--md-sys-color-error-container); color: var(--md-sys-color-on-error-container); }
.transaction-icon.exam { background: var(--md-sys-color-secondary-container); color: var(--md-sys-color-on-secondary-container); }
[data-theme="dark"] .transaction-icon.payment { background: #29532f; color: #b8f1c0; }
.transaction-item.active-item {
    background: var(--md-sys-color-surface-container);
    border-radius: var(--md-sys-shape-corner-medium);
    margin: 0 -12px; padding-left: 12px; padding-right: 12px;
}

/* Lingkaran ikon serba guna (dipakai beberapa halaman). */
.icon-circle {
    display: flex; align-items: center; justify-content: center;
    border-radius: var(--md-sys-shape-corner-full);
}
.icon-circle > .bi { display: block; }

/* Nama lama tombol gradien — dipetakan ke filled tertiary (gold). */
.btn-primary-gradient {
    background: var(--md-brand-gold);
    color: var(--md-brand-on-gold);
    border: none;
    border-radius: var(--md-sys-shape-corner-full);
}
.btn-primary-gradient:hover { color: var(--md-brand-on-gold); box-shadow: var(--md-sys-elevation-level1); }


/* ============================================================
   RESPONSIF
   ============================================================ */
@media (max-width: 991.98px) {
    .sidebar { transform: translateX(-100%); width: min(86vw, 320px); }
    .sidebar.show { transform: translateX(0); }
    .sidebar-backdrop.show { display: block; }
    .sidebar-close { display: flex; }
    /* Bar kini mengambang di atas kanvas dengan jarak dari tepi bawah, jadi
       ruang aman untuk isi = tinggi bar + jarak itu + sedikit napas. */
    .main-wrapper { margin-left: 0; padding-bottom: calc(var(--bottom-nav-height) + var(--bottom-nav-gap) + 16px); }
    .hamburger { display: flex; }
    .header-brand-mini { display: flex; }
    .bottom-nav { display: flex; }
    .row.g-3 { --bs-gutter-x: 12px; --bs-gutter-y: 12px; }
}
@media (max-width: 575.98px) {
    :root { --header-height: 56px; }
    .main-header { padding: 0 4px 0 8px; gap: 2px; }
    .content-wrapper { padding: 12px; }
    .card-body { padding: 12px; }
    .page-header-flex { flex-direction: column; align-items: stretch; }
    .page-header-flex > .d-flex, .page-header-flex .btn-header-group { width: 100%; }
    /* Aksi di kepala halaman jadi selebar layar — KECUALI tombol kembali. */
    .page-header-flex .btn:not(.btn-back-circle) { width: 100%; }
    .page-header-flex .btn-header-group .btn { flex: 1; width: auto !important; }
    .rb-hero { padding: 20px 16px; }
}
@media print {
    .sidebar, .sidebar-backdrop, .main-header, .bottom-nav, .auth-orb { display: none !important; }
    .main-wrapper { margin-left: 0 !important; padding: 0 !important; }
    .content-wrapper { padding: 0 !important; }
    body::before { display: none !important; }
    .card, .activity-card { box-shadow: none !important; border: 1px solid #ddd; }
}


/* ============================================================================
   KONSISTENSI BENTUK & UKURAN

   Blok ini ada karena satu temuan konkret saat menelusuri halaman Katalog:
   Select2 dan <select> biasa berdiri bersebelahan dengan tinggi berbeda, dan
   ikon empty-state memakai radius inline yang berbeda-beda di tiap halaman
   (22px di Katalog, 20px di Keranjang, 18px di Dompet Koin).

   Penyebabnya sama di semua kasus: nilainya ditulis lepas di tempat pemakaian,
   bukan diambil dari skala. Jadi yang dipasang di sini bukan tambalan per
   halaman, melainkan PAGAR: apa pun yang lolos ke markup dipaksa kembali ke
   skala bentuk & ukuran M3.
   ============================================================================ */

/* ── Semua kendali berbagi satu tinggi ──
   Empat keluarga kontrol hidup berdampingan di panel filter — input, select,
   Select2 single, Select2 multiple. Ditulis sebagai satu daftar supaya tidak
   mungkin lagi ada yang tertinggal saat salah satunya disunting. */
.form-control,
.form-select,
.select2-container--default .select2-selection--single,
.select2-container--default .select2-selection--multiple {
    min-height: var(--md-field-height);
    border-radius: var(--md-sys-shape-corner-extra-small);
}
/* Kecuali yang memang bukan text field tunggal: textarea & select berbaris
   ganda (tingginya ditentukan isinya). */
textarea.form-control,
select.form-select[multiple],
select.form-select[size]:not([size="1"]) { min-height: 96px; height: auto; }
/* Input di dalam pembungkusnya (kolom cari filter, search bar galeri) tidak
   bergaris sendiri — pembungkusnyalah yang jadi bidang field-nya. */
.rb-filter-search, .md-search-bar > .form-control { min-height: 0; border-radius: 0; }

/* ── Ikon keadaan kosong ──
   Satu bentuk untuk seluruh halaman. Lingkaran, bukan kotak membulat: di M3
   wadah ikon berdiameter penuh adalah bentuk baku, dan itu juga yang dipakai
   ubin ikon di kartu aktivitas — sehingga halaman kosong dan halaman berisi
   memakai bahasa bentuk yang sama. */
.rb-empty-icon {
    display: flex; align-items: center; justify-content: center;
    width: 72px; height: 72px;
    border-radius: var(--md-sys-shape-corner-full);
    background: var(--md-sys-color-surface-container-highest);
    color: var(--md-sys-color-on-surface-variant);
    font-size: 32px;
}
.rb-empty-icon--primary { background: var(--md-sys-color-primary-container); color: var(--md-sys-color-on-primary-container); }
.rb-empty-icon--gold    { background: var(--md-brand-gold-container); color: var(--md-brand-on-gold-container); }

/* ── Utilitas .rounded-* Bootstrap dipetakan ke skala bentuk M3 ──
   Ada 51 pemakaian di markup halaman. Tanpa pemetaan ini, setiap satu di
   antaranya adalah radius di luar skala. */
.rounded        { border-radius: var(--md-sys-shape-corner-small) !important; }
.rounded-0      { border-radius: var(--md-sys-shape-corner-none) !important; }
.rounded-1      { border-radius: var(--md-sys-shape-corner-extra-small) !important; }
.rounded-2      { border-radius: var(--md-sys-shape-corner-small) !important; }
.rounded-3      { border-radius: var(--md-sys-shape-corner-medium) !important; }
.rounded-4      { border-radius: var(--md-sys-shape-corner-large) !important; }
.rounded-5      { border-radius: var(--md-sys-shape-corner-extra-large) !important; }
.rounded-pill   { border-radius: var(--md-sys-shape-corner-full) !important; }
.rounded-circle { border-radius: var(--md-sys-shape-corner-full) !important; }

/* ── Dialog ──
   Diatur lewat VARIABEL Bootstrap, bukan dengan menimpa margin .modal-dialog.

   Kenapa penting: .modal-dialog { margin: 16px auto } tampak benar, tetapi di
   layar sempit dialog selebar viewport sehingga margin `auto` kiri-kanan
   menyusut jadi 0 — popup menempel ke tepi. --bs-modal-margin dipakai Bootstrap
   untuk margin DAN perhitungan tinggi dialog-centered sekaligus, jadi menyetel
   variabelnya memberi jarak 16px di SEMUA sisi pada mobile tanpa merusak
   pemusatan. Di layar ≥592px (560 + 2×16) dialog memusat pada lebar 560. */
.modal { --bs-modal-margin: 16px; --bs-modal-width: 560px; }
.modal .modal-lg, .modal .modal-xl { --bs-modal-width: 720px; }
@media (min-width: 592px) { .modal { --bs-modal-margin: 28px; } }

/* ── Tombol di dalam kartu ──
   Beberapa halaman masih memberi .btn-sm pada aksi di kaki kartu. Ukurannya
   sudah diseragamkan di m3.css; yang perlu dijaga di sini hanya agar tombol
   bersebelahan tidak saling beda tinggi karena salah satunya <a> dan satunya
   <button>. */
.activity-card .btn,
.card-footer .btn,
.activity-card-footer .btn { min-height: var(--md-control-height); }


/* ============================================================
   IKON KOIN — gambar coin.png sebagai ikon mata uang

   Dipakai lewat <x-coin-icon>. Berperilaku seperti glyph ikon: ukurannya
   mengikuti font-size induk (1em), sejajar dengan baseline teks di sebelahnya,
   sehingga bisa menggantikan <i class="bi bi-coin"> tanpa penyesuaian ukuran
   per tempat. Sedikit lebih besar dari 1em karena koin bundar terbaca lebih
   kecil dari kotak huruf pada ukuran yang sama.
   ============================================================ */
.coin-ic {
    display: inline-block;
    width: 1.15em; height: 1.15em;
    object-fit: contain;
    vertical-align: -0.22em;
    user-select: none;
    flex-shrink: 0;
}
/* Konteks yang tadinya menyetel ukuran glyph lewat font-size tetap bekerja:
   .coin-ic mengikuti font-size, jadi pil header (18px), chip dompet, dan
   watermark besar semuanya ikut menyesuaikan sendiri. */


/* ============================================================
   BUTIR ASLI PAST PAPER — label sumber di badan soal

   _docs/PLANNING_BUTIR_ASLI_PAST_PAPER.md. Ditanam langsung di
   `paket_soal_questions.content` sebagai
   <span class="soal-sumber">(SASMO Paper A 2020)</span>, jadi aturan ini
   otomatis berlaku di kelima jalur render (take/result/questions/preview/
   answer-review) tanpa sunting Blade — konten selalu tampil apa adanya lewat
   {!! $question->content !!}.

   Warna dari token brand yang sudah dipakai untuk koin/harga (m3-tokens.css:
   --md-brand-gold-deep, "gold utama — teks & ikon di atas permukaan
   terang"), BUKAN warna baru — butir asli memang bagian dari nilai jual yang
   sama. Fallback hex ditulis eksplisit karena kelas ini juga dipakai di
   halaman yang tidak memuat m3-tokens.css (lihat app.css untuk tema panel).

   ⚠️ Butir bertipe `exploration` dirender di dalam <iframe srcdoc> yang
   ISOLASI PENUH dari CSS ini (dokumennya sendiri, <style> sendiri) — untuk
   tipe itu span-nya WAJIB dibubuhi inline style, aturan di sini tidak
   pernah sampai ke sana. Lihat tools/naskah/asli/asli.php::sourceSpan().

   ⚠️ tools/naskah/sidikjari.php membuang <span class="soal-sumber"> sebelum
   membuat sidik jari anti-duplikasi — JANGAN ganti nama kelas ini tanpa
   menyunting tambalan itu juga (pelajaran 9 Sep 2026 di berkas itu).
   ============================================================ */
.soal-sumber {
    font-weight: 600;
    color: var(--md-brand-gold-deep, #A87A12);
    white-space: nowrap;
}

/* Paragraf PEMBUNGKUS label sumber (tools/naskah/asli/asli.php::
   sisipkanSumberNonEksplorasi()) — SELALU paragraf baru terpisah dari soal,
   bukan anak dari paragraf terakhir. Pelajaran 9 Sep 2026 (ditemukan user
   lewat tangkapan layar SEAMO 2021 Paper A #1): banyak butir menaruh
   rumus/deret sebagai paragraf sendiri berstyle besar-tebal-rata-tengah
   (mis. font:700 18px Georgia, text-align:center) — kalau label ditanam DI
   DALAM paragraf itu, ia ikut mewarisi ukuran & perataan itu (.soal-sumber
   sendiri cuma mengatur warna/tebal, bukan ukuran/famili huruf). Sebagai
   paragraf saudara baru, warisan gaya itu terputus dan tampilannya SELALU
   memakai ukuran/famili huruf paragraf biasa, apa pun paragraf sebelumnya. */
.soal-sumber-line {
    margin: 6px 0 0;
    text-align: left;
}

/* ============================================================
   TOMBOL KELUAR HALAMAN (.btn-leave)

   Dulu hanya hidup sebagai <style> lokal di halaman pengerjaan Paket Soal,
   padahal halaman Persiapan Ujian dan Hasil Ujian memakai kelas yang sama —
   di kedua halaman itu tombolnya tampil sebagai tautan biru bergaris bawah
   tanpa bidang, bukan tombol. Aturannya dipindahkan ke sini supaya satu kelas
   berarti satu rupa di seluruh panel siswa.
   ============================================================ */
.btn-leave {
    position: relative; isolation: isolate;
    display: flex; align-items: center; justify-content: center; gap: 8px;
    width: 100%; min-height: var(--md-control-height);
    padding: 0 16px;
    border: none; border-radius: var(--md-sys-shape-corner-full);
    font: var(--md-sys-typescale-label-large-weight) var(--md-sys-typescale-label-large-size)/1 var(--md-sys-typescale-plain);
    color: var(--md-sys-color-on-secondary-container);
    background: var(--md-sys-color-secondary-container);
    box-shadow: var(--md-sys-elevation-level1);
    text-decoration: none;
}
.btn-leave::after {
    content: ''; position: absolute; inset: 0; border-radius: inherit;
    background: var(--md-sys-color-on-secondary-container);
    opacity: 0; pointer-events: none;
    transition: opacity var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
}
.btn-leave:hover::after { opacity: var(--md-sys-state-hover-opacity); }
.btn-leave:hover { color: var(--md-sys-color-on-secondary-container); box-shadow: var(--md-sys-elevation-level2); }
.btn-leave i { font-size: 18px; }

/* ════════════════════════════════════════════════════════════════════════
   KONTEN SOAL DI MODE GELAP (10 Okt 2026)
   Naskah soal adalah HTML ber-style inline yang ditulis untuk latar terang:
   kotak bacaan TKA (`background:#f7fafb`), kepala tabel (`#eef2f5`), kartu
   "Diketahui", dan SVG tanpa `fill`. Di mode gelap teksnya mewarisi warna tema
   yang terang, jadi tulisan di atas latar terang itu nyaris hilang, sedangkan
   teks SVG yang hitam tenggelam di latar gelap. Ribuan butir bank terdampak;
   aturan ini memperbaikinya di tampilan tanpa menyentuh data.
   Cakupan: ruang ujian/latihan (#questionBody) dan kartu tinjauan/pembahasan
   (.q-card). Rumus KaTeX dikecualikan — tanda akarnya SVG ber-currentColor.
   ════════════════════════════════════════════════════════════════════════ */
[data-theme="dark"] :is(#questionBody, .q-card) :is(
    [style*="background:#f"], [style*="background: #f"], [style*="background:#F"],
    [style*="background:#e"], [style*="background: #e"], [style*="background:#E"],
    [style*="background-color:#f"], [style*="background-color: #f"],
    [style*="background-color:#e"], [style*="background-color: #e"],
    [style*="background:white"], [style*="background: white"],
    [style*="background:#fff"], [style*="background-color:white"]) {
    color: #1a1a1a;
}
[data-theme="dark"] :is(#questionBody, .q-card) svg:not(.katex svg) {
    background: #fff;
    color: #1a1a1a;
    border-radius: 6px;
}

/* ============================================================
   ASAL SOAL & NAMA SERI (keputusan pemilik 26 Okt 2026)
   ------------------------------------------------------------
   Kartu Seri (Katalog): STEMPEL bulat di pojok kanan atas — <x-asal-stamp>.
   Kartu Paket Soal: LENCANA di sudut logo lomba — <x-asal-badge>, karena pojok
   kanan atas kartu itu milik pita status.

     original     navy-emas  Original Set   naskah resmi lomba (segel gerigi, senada hero)
     masterolimp  navy    MasterOlimp Set   soal buatan MasterOlimp
     free         hijau   Free Set          Seri gratis

   Pita atas kartu Seri ikut jenisnya (navy→emas / biru baku / hijau); kartu yang
   sudah dimiliki penuh tetap hijau "tuntas" (.rb-card--done).
   ============================================================ */
.asal-stamp {
    position: absolute; top: 6px; right: 8px; z-index: 2;
    width: 64px; height: 64px; transform: rotate(-12deg); opacity: .94;
}
/* Tier di lengkung bawah stempel MasterOlimp Set — rona dari peta .kt-tier--*
   (kelasnya dipasang di <svg>), jadi stempel & tombol saring Tier sewarna. */
.asal-stamp-tier { fill: var(--kt-fg, currentColor); }
/* Original Set = NAVY berbingkai EMAS, senada panji hero (pemilik 26 Okt). Warna segelnya tetap
   (gradasi di <x-asal-stamp>); `color` hanya cadangan bila simbol gagal dimuat. */
.asal-stamp--original { color: #0b2243; }
.asal-stamp--masterolimp { color: #1e3a6e; }
.asal-stamp--free        { color: #0b7a5a; }
[data-theme="dark"] .asal-stamp--original    { color: #ebbd50; }
[data-theme="dark"] .asal-stamp--masterolimp { color: #9ec1f0; }
[data-theme="dark"] .asal-stamp--free        { color: #6fd3ae; }
/* Stempel ber-Tier memakai rona Tier-nya, bukan navy MasterOlimp (pemilik 26 Okt):
   tulisan = --kt-fg (rona teks yang cukup kontras), cincin = --kt-c (rona Tier penuh).
   Pemilih sengaja lebih spesifik dari aturan tema gelap di atas. */
.asal-stamp.asal-stamp--tier,
[data-theme="dark"] .asal-stamp.asal-stamp--tier { color: var(--kt-fg); }
.asal-stamp--tier .asal-stamp-line { stroke: var(--kt-c); }
.asal-stamp--tier .asal-stamp-field { fill: var(--kt-c); }
/* Ruang kanan judul supaya tidak tertimpa stempel — kartu Seri (Katalog) dan
   kartu Paket Soal; judul yang tak muat berjalan (.rb-marquee), bukan patah baris. */
.rb-card.has-stamp .rb-card__head { padding-right: 3.85rem; }

/* Status kartu Paket Soal sebagai CHIP di depan baris fakta — dulu pita miring
   (.ps-ribbon) di pojok kanan atas, yang kini milik stempel. Rona sama dengan
   pita lama: hijau Selesai, emas-terbalik Lanjutkan, biru Terjadwal/Pembahasan,
   kelabu Arsip/Terkunci, merah Timeout. */
.ps-status {
    display: inline-flex; align-items: center; flex-shrink: 0;
    padding: .06rem .5rem; border-radius: var(--md-sys-shape-corner-full, 999px);
    font-size: .68rem; font-weight: 800; letter-spacing: .02em; line-height: 1.45; white-space: nowrap;
    background: var(--md-sys-color-primary); color: var(--md-sys-color-on-primary);
}
.ps-status--success   { background: var(--md-green); color: var(--md-on-green); }
.ps-status--warning   { background: var(--md-brand-on-gold-strong); color: var(--md-brand-gold-strong); }
.ps-status--info      { background: var(--md-sys-color-primary); color: var(--md-sys-color-on-primary); }
.ps-status--secondary { background: var(--md-sys-color-outline); color: var(--md-sys-color-surface); }
.ps-status--danger    { background: var(--md-sys-color-error); color: var(--md-sys-color-on-error); }

.kt-card--original:not(.rb-card--done)::before { background: linear-gradient(90deg, #0b2243, #ebbd50); opacity: 1; }
.kt-card--free:not(.rb-card--done)::before     { background: linear-gradient(90deg, #0b7a5a, #6fd3ae); opacity: 1; }

/* Lencana di sudut kanan-bawah kotak logo. Cincin warna permukaan memisahkannya
   dari logo putih maupun latar kartu. */
.rb-card__ico.rb-card__ico--asal { position: relative; overflow: visible; }
.asal-badge {
    position: absolute; right: -6px; bottom: -6px;
    width: 21px; height: 21px; border-radius: 50%;
    display: grid; place-items: center; line-height: 0;
    background: var(--md-sys-color-surface);
    box-shadow: 0 0 0 2px var(--md-sys-color-surface);
}
.asal-badge > svg, .asal-badge > img { display: block; width: 19px; height: 19px; border-radius: 50%; }
/* Versi sebaris untuk fakta "Asal soal" di modal. */
.asal-badge.asal-badge--inline {
    position: static; display: inline-grid; vertical-align: -4px; margin-right: .35rem;
    width: 18px; height: 18px; background: none; box-shadow: none;
}
.asal-badge--inline > svg, .asal-badge--inline > img { width: 18px; height: 18px; }

/* Fakta ringkas berikon di bawah judul kartu Seri: paket · soal · batas akses. */
.rb-facts-ic { display: inline-flex; flex-wrap: wrap; align-items: center; gap: .1rem .75rem; }
.rb-facts-ic > span { display: inline-flex; align-items: center; gap: .28rem; white-space: nowrap; font-variant-numeric: tabular-nums; }
.rb-facts-ic i { font-size: .8rem; opacity: .7; }

/* ── Judul SATU BARIS + tulisan berjalan (.rb-marquee) ─────────
   Judul tak pernah patah baris. Bila lebih panjang dari ruangnya (diukur
   public/js/judul-berjalan.js) ia bergeser bolak-balik: diam di awal → geser
   sampai ujungnya terlihat → diam → kembali. Tepi kanan memudar sebagai tanda
   masih ada lanjutan; tepi kiri baru memudar setelah teks bergeser (--rb-fl
   dianimasikan serempak), jadi huruf pertama utuh saat diam. Judul yang muat
   tetap diam; judul lengkap juga ada di atribut title.
   SENGAJA tanpa pengecualian prefers-reduced-motion (pemilik 27 Okt 2026): di
   laptop Windows ber-"Animation effects" mati judul dulu berhenti jadi elipsis,
   sementara di ponsel berjalan — pemilik ingin keduanya sama. Geraknya pelan,
   bolak-balik di tempat, dan berhenti di tiap ujung.
   Tiga kelas sengaja: harus mengalahkan .ps-card .rb-card__title yang
   mengizinkan patah baris. */
@property --rb-fl { syntax: "<length>"; inherits: false; initial-value: 0px; }
.rb-card .rb-card__title.rb-marquee { white-space: nowrap; overflow: hidden; }
.rb-marquee > span { display: inline-block; will-change: transform; }
.rb-marquee.is-over {
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 var(--rb-fl), #000 calc(100% - 14px), transparent);
            mask-image: linear-gradient(90deg, transparent 0, #000 var(--rb-fl), #000 calc(100% - 14px), transparent);
}
.rb-marquee.is-over.is-run { animation: rb-marquee-tepi var(--rb-dur, 6s) ease-in-out var(--rb-delay, 0s) infinite alternate; }
.rb-marquee.is-over.is-run > span { animation: rb-marquee var(--rb-dur, 6s) ease-in-out var(--rb-delay, 0s) infinite alternate; }
@keyframes rb-marquee { 0%, 18% { transform: translateX(0); } 82%, 100% { transform: translateX(calc(-1 * var(--rb-geser, 0px))); } }
@keyframes rb-marquee-tepi { 0%, 18% { --rb-fl: 0px; } 30%, 100% { --rb-fl: 10px; } }

/* Baris Tier di kartu Seri (Katalog) — Panduan Penamaan 26 Okt 2026:
   "Fighter · Siap bertanding". Nama Tier berona Tier (.kt-tier--* memasok --kt-fg),
   taglinenya netral. Satu baris; yang tak muat dipotong elipsis. */
.kt-tierline {
    font-size: .76rem; color: var(--bs-secondary-color); margin-top: 2px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.kt-tierline b { color: var(--kt-fg, currentColor); font-weight: 800; }

/* ── Kartu Olimp sempit (Katalog, pemilik 29 Okt 2026) ─────────────
   Empat ikon (Kelas · Minat · Original · MasterOlimp) berbagi baris dengan tiga
   chip angka. Kartu sempit (tiga kolom di layar ±1280 px, ±300 px) memadatkan
   chip & ikonnya supaya tetap SATU baris; baru membungkus bila tetap tak muat.
   Tinggal di sini, bukan di katalog/olimp.blade.php: `@container` di dalam Blade
   dibaca sebagai direktif. */
.kt-ocard { container-type: inline-size; }
@container (max-width: 360px) {
    .kt-ocard .kt-ochips { gap: 4px; padding-left: 10px; padding-right: 10px; }
    .kt-ochips .rb-card__badge, .kt-ochips .rb-card__tag, .kt-ochips .rb-card__owned { padding: 2px 7px; font-size: .67rem; }
    .kt-ochips .kt-fit { gap: 2px; }
    .kt-ochips .kt-fit > span { width: 20px; height: 20px; font-size: .66rem; }
}
