/**
 * Do not edit directly, this file was auto-generated.
 */

:root {
  --blur-sm: 4px;
  --blur-base: 8px;
  --blur-md: 12px;
  --blur-lg: 16px;
  --blur-xl: 24px;
  --border-0: 0px;
  --border-1: 1px;
  --border-2: 2px;
  --border-3: 3px;
  --border-4: 4px;
  --border-8: 8px;
  --border-default: 1px;
  --border-strong: 2px;
  --screen-sm: 640px;
  --screen-md: 768px;
  --screen-lg: 1024px;
  --screen-xl: 1280px;
  --screen-2xl: 1536px;
  --color-white: oklch(1 0 0); /** Putih murni. Primitive supaya semantic putih (background, card, popover, *-foreground) tetap merujuk core, bukan literal. */
  --color-slate-50: oklch(0.984 0.003 255);
  --color-slate-100: oklch(0.968 0.005 255);
  --color-slate-200: oklch(0.929 0.008 255);
  --color-slate-300: oklch(0.869 0.011 255);
  --color-slate-400: oklch(0.704 0.015 255);
  --color-slate-500: oklch(0.554 0.018 255);
  --color-slate-600: oklch(0.446 0.019 255);
  --color-slate-700: oklch(0.372 0.018 255);
  --color-slate-800: oklch(0.279 0.015 255);
  --color-slate-900: oklch(0.208 0.012 255);
  --color-slate-950: oklch(0.129 0.008 255);
  --color-blue-50: oklch(0.970 0.014 255);
  --color-blue-100: oklch(0.932 0.032 255);
  --color-blue-200: oklch(0.882 0.059 255);
  --color-blue-300: oklch(0.809 0.105 255);
  --color-blue-400: oklch(0.707 0.165 255);
  --color-blue-500: oklch(0.623 0.214 255);
  --color-blue-600: oklch(0.546 0.215 255);
  --color-blue-700: oklch(0.488 0.199 255);
  --color-blue-800: oklch(0.424 0.166 255);
  --color-blue-900: oklch(0.379 0.132 255);
  --color-blue-950: oklch(0.282 0.091 255);
  --color-red-50: oklch(0.971 0.013 25);
  --color-red-100: oklch(0.936 0.032 25);
  --color-red-200: oklch(0.885 0.062 25);
  --color-red-300: oklch(0.808 0.114 25);
  --color-red-400: oklch(0.704 0.191 25);
  --color-red-500: oklch(0.637 0.237 25);
  --color-red-600: oklch(0.577 0.245 25);
  --color-red-700: oklch(0.505 0.213 25);
  --color-red-800: oklch(0.444 0.177 25);
  --color-red-900: oklch(0.396 0.141 25);
  --color-red-950: oklch(0.258 0.092 25);
  --color-green-50: oklch(0.982 0.018 145);
  --color-green-100: oklch(0.962 0.044 145);
  --color-green-200: oklch(0.925 0.084 145);
  --color-green-300: oklch(0.871 0.150 145);
  --color-green-400: oklch(0.792 0.209 145);
  --color-green-500: oklch(0.723 0.219 145);
  --color-green-600: oklch(0.627 0.194 145);
  --color-green-700: oklch(0.527 0.154 145);
  --color-green-800: oklch(0.448 0.119 145);
  --color-green-900: oklch(0.393 0.095 145);
  --color-green-950: oklch(0.266 0.065 145);
  --color-teal-50: oklch(0.984 0.014 185);
  --color-teal-100: oklch(0.953 0.051 185);
  --color-teal-200: oklch(0.910 0.096 185);
  --color-teal-300: oklch(0.855 0.138 185);
  --color-teal-400: oklch(0.777 0.152 185);
  --color-teal-500: oklch(0.704 0.140 185);
  --color-teal-600: oklch(0.600 0.118 185); /** Ramp keenam, ditambah Batch 24 (Chart). Bukan untuk peran semantic mana pun — ia ada supaya deret data punya hue yang TIDAK berarti apa-apa. Sebelum ini palet cuma punya lima hue dan empat di antaranya sudah dipesan: biru aksi, merah bahaya, hijau sukses, amber peringatan. Memakai merah dan hijau sebagai warna deret berarti dua hal buruk sekaligus: pembaca membacanya sebagai penilaian, dan pasangan merah-hijau justru pasangan yang paling tidak bisa dibedakan penderita deuteranopia. */
  --color-teal-700: oklch(0.511 0.096 185);
  --color-teal-800: oklch(0.437 0.078 185);
  --color-teal-900: oklch(0.386 0.063 185);
  --color-teal-950: oklch(0.277 0.046 185);
  --color-violet-50: oklch(0.969 0.016 293);
  --color-violet-100: oklch(0.943 0.029 293);
  --color-violet-200: oklch(0.894 0.057 293);
  --color-violet-300: oklch(0.811 0.111 293);
  --color-violet-400: oklch(0.702 0.183 293);
  --color-violet-500: oklch(0.606 0.250 293); /** Ramp ketujuh, ditambah Batch 24 (Chart). Alasannya sama dengan teal: hue tanpa peran semantic, untuk deret data. Dipilih violet dan bukan pink karena jaraknya dari biru dan teal tetap jauh di simulasi protanopia maupun deuteranopia — diukur dengan validator palet, bukan dinilai dengan mata. */
  --color-violet-600: oklch(0.541 0.281 293);
  --color-violet-700: oklch(0.491 0.270 293);
  --color-violet-800: oklch(0.432 0.232 293);
  --color-violet-900: oklch(0.380 0.189 293);
  --color-violet-950: oklch(0.283 0.141 293);
  --color-amber-50: oklch(0.987 0.022 70);
  --color-amber-100: oklch(0.962 0.059 70);
  --color-amber-200: oklch(0.924 0.120 70);
  --color-amber-300: oklch(0.879 0.169 70);
  --color-amber-400: oklch(0.828 0.189 70);
  --color-amber-500: oklch(0.769 0.188 70);
  --color-amber-600: oklch(0.666 0.179 70);
  --color-amber-700: oklch(0.555 0.163 70);
  --color-amber-800: oklch(0.473 0.137 70);
  --color-amber-900: oklch(0.414 0.112 70);
  --color-amber-950: oklch(0.279 0.066 70);
  --color-cyan-50: oklch(0.984 0.019 200.873);
  --color-cyan-100: oklch(0.956 0.045 203.388);
  --color-cyan-200: oklch(0.917 0.080 205.041);
  --color-cyan-300: oklch(0.865 0.127 207.078);
  --color-cyan-400: oklch(0.789 0.154 211.53);
  --color-cyan-500: oklch(0.715 0.143 215.221);
  --color-cyan-600: oklch(0.609 0.126 221.723);
  --color-cyan-700: oklch(0.520 0.105 223.128);
  --color-cyan-800: oklch(0.450 0.085 224.283);
  --color-cyan-900: oklch(0.398 0.070 227.392);
  --color-cyan-950: oklch(0.302 0.056 229.695);
  --color-emerald-50: oklch(0.979 0.021 166.113);
  --color-emerald-100: oklch(0.950 0.052 163.051);
  --color-emerald-200: oklch(0.905 0.093 164.15);
  --color-emerald-300: oklch(0.845 0.143 164.978);
  --color-emerald-400: oklch(0.765 0.177 163.223);
  --color-emerald-500: oklch(0.696 0.170 162.48);
  --color-emerald-600: oklch(0.596 0.145 163.225);
  --color-emerald-700: oklch(0.508 0.118 165.612);
  --color-emerald-800: oklch(0.432 0.095 166.913);
  --color-emerald-900: oklch(0.378 0.077 168.94);
  --color-emerald-950: oklch(0.262 0.051 172.552);
  --color-fuchsia-50: oklch(0.977 0.017 320.058);
  --color-fuchsia-100: oklch(0.952 0.037 318.852);
  --color-fuchsia-200: oklch(0.903 0.076 319.62);
  --color-fuchsia-300: oklch(0.833 0.145 321.434);
  --color-fuchsia-400: oklch(0.740 0.238 322.16);
  --color-fuchsia-500: oklch(0.667 0.295 322.15);
  --color-fuchsia-600: oklch(0.591 0.293 322.896);
  --color-fuchsia-700: oklch(0.518 0.253 323.949);
  --color-fuchsia-800: oklch(0.452 0.211 324.591);
  --color-fuchsia-900: oklch(0.401 0.170 325.612);
  --color-fuchsia-950: oklch(0.293 0.136 325.661);
  --color-indigo-50: oklch(0.962 0.018 272.314);
  --color-indigo-100: oklch(0.930 0.034 272.788);
  --color-indigo-200: oklch(0.870 0.065 274.039);
  --color-indigo-300: oklch(0.785 0.115 274.713);
  --color-indigo-400: oklch(0.673 0.182 276.935);
  --color-indigo-500: oklch(0.585 0.233 277.117);
  --color-indigo-600: oklch(0.511 0.262 276.966);
  --color-indigo-700: oklch(0.457 0.240 277.023);
  --color-indigo-800: oklch(0.398 0.195 277.366);
  --color-indigo-900: oklch(0.359 0.144 278.697);
  --color-indigo-950: oklch(0.257 0.090 281.288);
  --color-lime-50: oklch(0.986 0.031 120.757);
  --color-lime-100: oklch(0.967 0.067 122.328);
  --color-lime-200: oklch(0.938 0.127 124.321);
  --color-lime-300: oklch(0.897 0.196 126.665);
  --color-lime-400: oklch(0.841 0.238 128.85);
  --color-lime-500: oklch(0.768 0.233 130.85);
  --color-lime-600: oklch(0.648 0.200 131.684);
  --color-lime-700: oklch(0.532 0.157 131.589);
  --color-lime-800: oklch(0.453 0.124 130.933);
  --color-lime-900: oklch(0.405 0.101 131.063);
  --color-lime-950: oklch(0.274 0.072 132.109);
  --color-orange-50: oklch(0.980 0.016 73.684);
  --color-orange-100: oklch(0.954 0.038 75.164);
  --color-orange-200: oklch(0.901 0.076 70.697);
  --color-orange-300: oklch(0.837 0.128 66.29);
  --color-orange-400: oklch(0.750 0.183 55.934);
  --color-orange-500: oklch(0.705 0.213 47.604);
  --color-orange-600: oklch(0.646 0.222 41.116);
  --color-orange-700: oklch(0.553 0.195 38.402);
  --color-orange-800: oklch(0.470 0.157 37.304);
  --color-orange-900: oklch(0.408 0.123 38.172);
  --color-orange-950: oklch(0.266 0.079 36.259);
  --color-pink-50: oklch(0.971 0.014 343.198);
  --color-pink-100: oklch(0.948 0.028 342.258);
  --color-pink-200: oklch(0.899 0.061 343.231);
  --color-pink-300: oklch(0.823 0.120 346.018);
  --color-pink-400: oklch(0.718 0.202 349.761);
  --color-pink-500: oklch(0.656 0.241 354.308);
  --color-pink-600: oklch(0.592 0.249 0.584);
  --color-pink-700: oklch(0.525 0.223 3.958);
  --color-pink-800: oklch(0.459 0.187 3.815);
  --color-pink-900: oklch(0.408 0.153 2.432);
  --color-pink-950: oklch(0.284 0.109 3.907);
  --color-purple-50: oklch(0.977 0.014 308.299);
  --color-purple-100: oklch(0.946 0.033 307.174);
  --color-purple-200: oklch(0.902 0.063 306.703);
  --color-purple-300: oklch(0.827 0.119 306.383);
  --color-purple-400: oklch(0.714 0.203 305.504);
  --color-purple-500: oklch(0.627 0.265 303.9);
  --color-purple-600: oklch(0.558 0.288 302.321);
  --color-purple-700: oklch(0.496 0.265 301.924);
  --color-purple-800: oklch(0.438 0.218 303.724);
  --color-purple-900: oklch(0.381 0.176 304.987);
  --color-purple-950: oklch(0.291 0.149 302.717);
  --color-rose-50: oklch(0.969 0.015 12.422);
  --color-rose-100: oklch(0.941 0.030 12.58);
  --color-rose-200: oklch(0.892 0.058 10.001);
  --color-rose-300: oklch(0.810 0.117 11.638);
  --color-rose-400: oklch(0.712 0.194 13.428);
  --color-rose-500: oklch(0.645 0.246 16.439);
  --color-rose-600: oklch(0.586 0.253 17.585);
  --color-rose-700: oklch(0.514 0.222 16.935);
  --color-rose-800: oklch(0.455 0.188 13.697);
  --color-rose-900: oklch(0.410 0.159 10.272);
  --color-rose-950: oklch(0.271 0.105 12.094);
  --color-sky-50: oklch(0.977 0.013 236.62);
  --color-sky-100: oklch(0.951 0.026 236.824);
  --color-sky-200: oklch(0.901 0.058 230.902);
  --color-sky-300: oklch(0.828 0.111 230.318);
  --color-sky-400: oklch(0.746 0.160 232.661);
  --color-sky-500: oklch(0.685 0.169 237.323);
  --color-sky-600: oklch(0.588 0.158 241.966);
  --color-sky-700: oklch(0.500 0.134 242.749);
  --color-sky-800: oklch(0.443 0.110 240.79);
  --color-sky-900: oklch(0.391 0.090 240.876);
  --color-sky-950: oklch(0.293 0.066 243.157);
  --color-yellow-50: oklch(0.987 0.026 102.212);
  --color-yellow-100: oklch(0.973 0.071 103.193);
  --color-yellow-200: oklch(0.945 0.129 101.54);
  --color-yellow-300: oklch(0.905 0.182 98.111);
  --color-yellow-400: oklch(0.852 0.199 91.936);
  --color-yellow-500: oklch(0.795 0.184 86.047);
  --color-yellow-600: oklch(0.681 0.162 75.834);
  --color-yellow-700: oklch(0.554 0.135 66.442);
  --color-yellow-800: oklch(0.476 0.114 61.907);
  --color-yellow-900: oklch(0.421 0.095 57.708);
  --color-yellow-950: oklch(0.286 0.066 53.813);
  --color-neutral-50: oklch(0.985 0 0);
  --color-neutral-100: oklch(0.970 0 0);
  --color-neutral-200: oklch(0.922 0 0);
  --color-neutral-300: oklch(0.870 0 0);
  --color-neutral-400: oklch(0.708 0 0);
  --color-neutral-500: oklch(0.556 0 0);
  --color-neutral-600: oklch(0.439 0 0);
  --color-neutral-700: oklch(0.371 0 0);
  --color-neutral-800: oklch(0.269 0 0);
  --color-neutral-900: oklch(0.205 0 0);
  --color-neutral-950: oklch(0.145 0 0);
  --color-stone-50: oklch(0.985 0.001 106.423);
  --color-stone-100: oklch(0.970 0.001 106.424);
  --color-stone-200: oklch(0.923 0.003 48.717);
  --color-stone-300: oklch(0.869 0.005 56.366);
  --color-stone-400: oklch(0.709 0.010 56.259);
  --color-stone-500: oklch(0.553 0.013 58.071);
  --color-stone-600: oklch(0.444 0.011 73.639);
  --color-stone-700: oklch(0.374 0.010 67.558);
  --color-stone-800: oklch(0.268 0.007 34.298);
  --color-stone-900: oklch(0.216 0.006 56.043);
  --color-stone-950: oklch(0.147 0.004 49.25);
  --color-zinc-50: oklch(0.985 0 0);
  --color-zinc-100: oklch(0.967 0.001 286.375);
  --color-zinc-200: oklch(0.920 0.004 286.32);
  --color-zinc-300: oklch(0.871 0.006 286.286);
  --color-zinc-400: oklch(0.705 0.015 286.067);
  --color-zinc-500: oklch(0.552 0.016 285.938);
  --color-zinc-600: oklch(0.442 0.017 285.786);
  --color-zinc-700: oklch(0.370 0.013 285.805);
  --color-zinc-800: oklch(0.274 0.006 286.033);
  --color-zinc-900: oklch(0.210 0.006 285.885);
  --color-zinc-950: oklch(0.141 0.005 285.823);
  --color-mauve-50: oklch(0.985 0 0);
  --color-mauve-100: oklch(0.960 0.003 325.6);
  --color-mauve-200: oklch(0.922 0.005 325.62);
  --color-mauve-300: oklch(0.865 0.012 325.68);
  --color-mauve-400: oklch(0.711 0.019 323.02);
  --color-mauve-500: oklch(0.542 0.034 322.5);
  --color-mauve-600: oklch(0.435 0.029 321.78);
  --color-mauve-700: oklch(0.364 0.029 323.89);
  --color-mauve-800: oklch(0.263 0.024 320.12);
  --color-mauve-900: oklch(0.212 0.019 322.12);
  --color-mauve-950: oklch(0.145 0.008 326);
  --color-olive-50: oklch(0.988 0.003 106.5);
  --color-olive-100: oklch(0.966 0.005 106.5);
  --color-olive-200: oklch(0.930 0.007 106.5);
  --color-olive-300: oklch(0.880 0.011 106.6);
  --color-olive-400: oklch(0.737 0.021 106.9);
  --color-olive-500: oklch(0.580 0.031 107.3);
  --color-olive-600: oklch(0.466 0.025 107.3);
  --color-olive-700: oklch(0.394 0.023 107.4);
  --color-olive-800: oklch(0.286 0.016 107.4);
  --color-olive-900: oklch(0.228 0.013 107.4);
  --color-olive-950: oklch(0.153 0.006 107.1);
  --color-mist-50: oklch(0.987 0.002 197.1);
  --color-mist-100: oklch(0.963 0.002 197.1);
  --color-mist-200: oklch(0.925 0.005 214.3);
  --color-mist-300: oklch(0.872 0.007 219.6);
  --color-mist-400: oklch(0.723 0.014 214.4);
  --color-mist-500: oklch(0.560 0.021 213.5);
  --color-mist-600: oklch(0.450 0.017 213.2);
  --color-mist-700: oklch(0.378 0.015 216);
  --color-mist-800: oklch(0.275 0.011 216.9);
  --color-mist-900: oklch(0.218 0.008 223.9);
  --color-mist-950: oklch(0.148 0.004 228.8);
  --color-taupe-50: oklch(0.986 0.002 67.8);
  --color-taupe-100: oklch(0.960 0.002 17.2);
  --color-taupe-200: oklch(0.922 0.005 34.3);
  --color-taupe-300: oklch(0.868 0.007 39.5);
  --color-taupe-400: oklch(0.714 0.014 41.2);
  --color-taupe-500: oklch(0.547 0.021 43.1);
  --color-taupe-600: oklch(0.438 0.017 39.3);
  --color-taupe-700: oklch(0.367 0.016 35.7);
  --color-taupe-800: oklch(0.268 0.011 36.5);
  --color-taupe-900: oklch(0.214 0.009 43.1);
  --color-taupe-950: oklch(0.147 0.004 49.3);
  --color-background: var(--color-white);
  --color-foreground: var(--color-slate-950);
  --color-card: var(--color-white);
  --color-card-foreground: var(--color-slate-950);
  --color-popover: var(--color-white);
  --color-popover-foreground: var(--color-slate-950);
  --color-overlay: oklch(0 0 0 / 50%); /** Kelam di belakang modal. shadcn memakai bg-black/50 di Dialog, Alert Dialog, Sheet, dan Drawer — nilainya sama di kedua tema, dan memang harus: yang dikelamkan adalah halaman, bukan permukaan komponen. Ditulis dua kali sesuai RULES Tema. */
  --color-primary: var(--color-blue-600);
  --color-primary-foreground: var(--color-white);
  --color-secondary: var(--color-slate-100);
  --color-secondary-foreground: var(--color-slate-900);
  --color-muted: var(--color-slate-100);
  --color-muted-foreground: var(--color-slate-500);
  --color-accent: var(--color-slate-100);
  --color-accent-foreground: var(--color-slate-900);
  --color-destructive: var(--color-red-600);
  --color-destructive-foreground: var(--color-white);
  --color-success: var(--color-green-700); /** green-700, bukan green-600. Teks putih di atas green-600 cuma 3,3:1 — di bawah ambang WCAG. Ketahuan dari tests/contrast.mjs, bukan dari mata. */
  --color-success-foreground: var(--color-white);
  --color-warning: var(--color-amber-500);
  --color-warning-foreground: var(--color-slate-950);
  --color-border: var(--color-slate-200);
  --color-input: var(--color-slate-500); /** slate-500, bukan slate-200 seperti shadcn. Garis tepi field adalah satu-satunya penanda batas kontrol, dan pada slate-200 kontrasnya cuma 1,2:1 — jauh di bawah ambang WCAG 1.4.11 (3:1). slate-400 sempat dicoba dan masih meleset (2,63:1), jadi naik satu langkah lagi. Dinaikkan atas keputusan Tony 5 Agu 2026. --color-border sengaja TIDAK ikut naik: garis kartu, separator, dan divider itu dekoratif, dan aturan yang sama tidak berlaku di sana. */
  --color-ring: var(--color-blue-500);
  --color-ring-focus: color-mix(in oklch, var(--color-ring) 50%, transparent); /** Halo lembut di sekeliling kontrol yang sedang difokus, digambar sebagai box-shadow. Ia BUKAN indikator fokusnya — yang memikul kontras itu --color-ring penuh yang dipasang di border-color pada baris di atasnya, dan itu yang diukur gerbang kontras. Halo ini menebalkan tanda supaya terlihat dari jauh, bukan menggantikannya. Tidak punya pasangan dark: nilainya menunjuk var(--color-ring), jadi ia ikut berganti sendiri saat tema berganti — alpha-nya tetap 50% di kedua tema, tidak seperti --color-destructive-ring. */
  --color-field: transparent; /** Latar field isian (input, textarea, checkbox, radio, select, kotak OTP, tombol outline). Di light mode field duduk langsung di atas halaman, jadi transparan. Di dark mode shadcn memberi film tipis supaya field terbaca sebagai cekungan — perbedaan itu tinggal di token, bukan di CSS komponen. */
  --color-field-hover: var(--color-accent); /** Latar field atau tombol outline saat kursor di atasnya. */
  --color-accent-hover: var(--color-accent); /** Latar tombol ghost saat kursor di atasnya. Di dark mode turun jadi 50% supaya sorotannya tidak seterang permukaan kartu. */
  --color-destructive-surface: var(--color-destructive); /** Latar penuh untuk tombol dan badge destructive. Di dark mode shadcn menurunkannya jadi 60% supaya merah pekat tidak menyilaukan di latar gelap. */
  --color-destructive-ring: color-mix(in oklch, var(--color-destructive) 20%, transparent); /** Ring fokus untuk kontrol bernilai tidak sah. Alpha-nya naik jadi 40% di dark mode — ring tipis hilang di latar gelap. */
  --color-destructive-item: color-mix(in oklch, var(--color-destructive) 10%, transparent); /** Latar item menu destructive saat tersorot. Naik jadi 20% di dark mode. */
  --color-sidebar: var(--color-slate-50); /** Permukaan panel navigasi samping. Ditaruh di tier semantic, bukan component, karena dua alasan: shadcn sendiri menaruhnya di lapisan tema (--sidebar dan kawan-kawan berdiri sejajar dengan --background), dan cuma tier ini yang punya pasangan dark. Nilainya sengaja tidak sama dengan --color-background maupun --color-card: panel samping harus terbaca sedikit mundur dari area kerja di sebelahnya, dan itu satu langkah abu, bukan garis. */
  --color-sidebar-foreground: var(--color-slate-950);
  --color-sidebar-primary: var(--color-slate-900); /** Latar kotak lambang di kepala panel samping — kotak kecil berisi logo yang menandai ruang kerja mana yang sedang dibuka. Ia perlu terbaca sebagai TANDA, bukan sebagai lubang di permukaan panel, jadi warnanya harus cukup jauh dari warna panelnya sendiri. */
  --color-sidebar-primary-foreground: var(--color-slate-50);
  --color-sidebar-accent: var(--color-slate-100); /** Sorotan item menu samping. Nilainya kebetulan sama dengan --color-accent hari ini, tapi tetap ditulis terpisah: begitu permukaan sidebar digeser, sorotannya harus ikut bergeser, sedangkan sorotan menu di halaman tidak. */
  --color-sidebar-accent-foreground: var(--color-slate-900);
  --color-sidebar-border: var(--color-slate-200);
  --color-sidebar-ring: var(--color-blue-500);
  --color-sidebar-ring-focus: color-mix(in oklch, var(--color-sidebar-ring) 50%, transparent); /** Padanan --color-ring-focus di dalam panel samping. Ditulis terpisah dengan alasan yang sama seperti --color-sidebar-accent: nilainya kebetulan sama hari ini, tapi begitu --color-sidebar-ring digeser, halonya harus ikut bergeser sedangkan halo di halaman tidak. */
  --color-chart-1: var(--color-blue-600); /** Warna deret data ke-1 dari 5. Ditaruh di tier semantic, bukan component, dengan alasan yang sama persis seperti --color-sidebar: shadcn menaruh --chart-1 sampai --chart-5 di lapisan tema sejajar dengan --background, dan cuma tier ini yang punya pasangan dark. Urutan slot ini TETAP — deret pertama selalu memakai chart-1, juga setelah deret lain dimatikan lewat legend. Warna mengikuti entitasnya, bukan peringkatnya; kalau slot digeser mengikuti sisa deret, pembaca yang sudah hafal 'Desktop itu biru' jadi salah baca. */
  --color-chart-2: var(--color-amber-600); /** Deret ke-2. amber-600, satu langkah lebih gelap dari --color-warning yang memakai amber-500. Langkahnya sengaja dibedakan: warna status disimpan untuk arti baik/buruk, dan warna deret cuma identitas. Nilai persisnya juga dipaksa oleh pengukuran — amber-500 lolos ambang kontras di atas latar terang, tapi jaraknya ke teal-600 di simulasi protanopia lebih sempit. */
  --color-chart-3: var(--color-teal-600); /** Deret ke-3. Hue baru yang tidak dipakai peran semantic mana pun. teal-500 sempat dipakai dan gagal satu check: kontrasnya di atas latar putih cuma 2,41:1, di bawah ambang 3:1 untuk elemen non-teks. teal-600 lolos di kedua tema. */
  --color-chart-4: var(--color-violet-500); /** Deret ke-4. Hue baru kedua. Nilainya sama di light dan dark karena violet-500 satu-satunya langkah yang masuk pita lightness KEDUA tema sekaligus (0,43-0,77 di terang, 0,48-0,67 di gelap) — violet-400 terlalu terang untuk latar gelap. Tetap ditulis dua kali sesuai RULES Tema. */
  --color-chart-5: var(--color-green-600); /** Deret ke-5. green-600, sementara --color-success memakai green-700 di light dan green-500 di dark — tidak pernah bertabrakan dengan langkah status di tema mana pun. Slot kelima adalah yang TERAKHIR: deret keenam tidak mendapat warna baru dan tidak memutar ulang dari slot 1, karena warna keenam yang dibuat-buat pasti bertabrakan dengan salah satu slot yang sudah ada di mata sebagian pembaca. */
  --duration-75: 75ms;
  --duration-100: 100ms;
  --duration-150: 150ms;
  --duration-200: 200ms;
  --duration-300: 300ms;
  --duration-500: 500ms;
  --duration-700: 700ms;
  --duration-1000: 1000ms;
  --duration-fast: 150ms;
  --duration-medium: 300ms;
  --duration-slow: 500ms;
  --easing-linear: linear;
  --easing-in: cubic-bezier(0.4, 0, 1, 1);
  --easing-out: cubic-bezier(0, 0, 0.2, 1);
  --easing-in-out: cubic-bezier(0.4, 0, 0.2, 1);
  --easing-standard: cubic-bezier(0.4, 0, 0.2, 1);
  --easing-decelerate: cubic-bezier(0, 0, 0.2, 1);
  --easing-accelerate: cubic-bezier(0.4, 0, 1, 1);
  --opacity-0: 0;
  --opacity-5: 0.05;
  --opacity-10: 0.1;
  --opacity-20: 0.2;
  --opacity-25: 0.25;
  --opacity-30: 0.3;
  --opacity-40: 0.4;
  --opacity-50: 0.5;
  --opacity-60: 0.6;
  --opacity-70: 0.7;
  --opacity-75: 0.75;
  --opacity-80: 0.8;
  --opacity-90: 0.9;
  --opacity-95: 0.95;
  --opacity-100: 1;
  --radius-none: 0px;
  --radius-sm: 0.125rem;
  --radius-base: 0.25rem;
  --radius-md: 0.375rem;
  --radius-lg: 0.5rem;
  --radius-xl: 0.75rem;
  --radius-2xl: 1rem;
  --radius-3xl: 1.5rem;
  --radius-full: 9999px;
  --radius-control-sm: 0.125rem;
  --radius-control-md: 0.375rem;
  --radius-control-lg: 0.5rem;
  --shadow-1: 0 1px 2px 0 rgb(0 0 0 / 0.05);
  --shadow-2: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
  --shadow-3: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
  --shadow-4: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
  --shadow-5: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
  --space-0: 0rem;
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-7: 1.75rem;
  --space-8: 2rem;
  --space-9: 2.25rem;
  --space-10: 2.5rem;
  --space-11: 2.75rem;
  --space-12: 3rem;
  --space-14: 3.5rem;
  --space-16: 4rem;
  --space-20: 5rem;
  --space-24: 6rem;
  --space-0-5: 0.125rem;
  --space-1-5: 0.375rem;
  --space-2-5: 0.625rem;
  --space-3-5: 0.875rem;
  --typography-family-sans: 'IBM Plex Sans', sans-serif;
  --typography-family-mono: 'JetBrains Mono', monospace;
  --typography-size-xs: 0.75rem;
  --typography-size-sm: 0.875rem;
  --typography-size-base: 1rem;
  --typography-size-lg: 1.125rem;
  --typography-size-xl: 1.25rem;
  --typography-size-2xl: 1.5rem;
  --typography-size-3xl: 1.875rem;
  --typography-size-4xl: 2.25rem;
  --typography-size-5xl: 3rem;
  --typography-size-6xl: 3.75rem;
  --typography-weight-normal: 400;
  --typography-weight-medium: 500;
  --typography-weight-semibold: 600;
  --typography-weight-bold: 700;
  --typography-leading-none: 1;
  --typography-leading-tight: 1.25;
  --typography-leading-snug: 1.375;
  --typography-leading-normal: 1.5;
  --typography-leading-relaxed: 1.625;
  --typography-tracking-tighter: -0.05em;
  --typography-tracking-tight: -0.025em;
  --typography-tracking-normal: 0em;
  --typography-tracking-wide: 0.025em;
  --typography-tracking-wider: 0.05em;
  --typography-tracking-widest: 0.1em;
  --typography-text-display: 700 3.75rem/1 'IBM Plex Sans', sans-serif;
  --typography-text-heading-1: 700 2.25rem/1.25 'IBM Plex Sans', sans-serif;
  --typography-text-heading-2: 700 1.875rem/1.25 'IBM Plex Sans', sans-serif;
  --typography-text-heading-3: 600 1.5rem/1.375 'IBM Plex Sans', sans-serif;
  --typography-text-heading-4: 600 1.25rem/1.375 'IBM Plex Sans', sans-serif;
  --typography-text-heading-5: 600 1.125rem/1.375 'IBM Plex Sans', sans-serif;
  --typography-text-heading-6: 600 1rem/1.5 'IBM Plex Sans', sans-serif;
  --typography-text-body: 400 1rem/1.5 'IBM Plex Sans', sans-serif;
  --typography-text-caption: 400 0.875rem/1.5 'IBM Plex Sans', sans-serif;
  --typography-text-label: 500 0.875rem/1 'IBM Plex Sans', sans-serif;
  --z-0: 0;
  --z-10: 10;
  --z-20: 20;
  --z-30: 30;
  --z-40: 40;
  --z-50: 50;
  --z-auto: auto;
  --z-dropdown: 30;
  --z-sticky: 20;
  --z-toast: 50;
  --overlay-blur: 8px; /** Blur pada lapisan kelam di belakang panel modal. Penambahan sengaja di luar shadcn — sumbernya cuma memakai hitam 50% tanpa blur. Ditokenkan di tier semantic karena berlaku untuk keempat komponen modal sekaligus; menuliskannya per komponen berarti empat salinan yang pasti melenceng. Kalau terasa berat di perangkat lemah, turunkan referensinya ke blur.sm tanpa menyentuh satu pun file komponen. */
  --ring-width: 3px;
  --ring-offset: 1px;
  --elevation-0: none;
  --elevation-1: 0 1px 2px 0 rgb(0 0 0 / 0.05);
  --elevation-2: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
  --elevation-3: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
  --elevation-4: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
  --elevation-5: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
  --spacing-inset-sm: 0.5rem;
  --spacing-inset-md: 1rem;
  --spacing-inset-lg: 1.5rem;
  --spacing-stack-sm: 0.5rem;
  --spacing-stack-md: 1rem;
  --spacing-stack-lg: 2rem;
  --alert-dialog-max-width: 32rem; /** shadcn `sm:max-w-lg` di AlertDialogContent ukuran default. Nilainya kebetulan sama dengan dialog-max-width, tapi tokennya sendiri — token component milik satu komponen saja, dan melebarkan dialog biasa tidak boleh ikut melebarkan dialog konfirmasi. Preseden: select-min-width terhadap dropdown-menu-min-width. */
  --alert-dialog-max-width-sm: 20rem; /** shadcn `data-[size=sm]:max-w-xs`. Ukuran ringkas untuk konfirmasi satu kalimat, dengan tombolnya berdampingan dua kolom. */
  --alert-destructive-description: color-mix(in oklch, var(--color-destructive) 90%, transparent); /** shadcn memberi deskripsi alert destructive warna destructive/90 — sedikit lebih redup dari judulnya, supaya judul tetap yang pertama terbaca. Persentase di dalam color-mix tidak bisa memakai token opacity: color-mix menuntut persen, sedangkan --opacity-90 bernilai 0.9. Ditokenkan supaya tidak menambah literal baru di CSS komponen, mengikuti pola --color-destructive-item. */
  --appointment-picker-rail-width: 10rem; /** Lebar kolom slot di layout side. Diambil dari isi terpanjang yang mungkin, bukan dari selera: label jam di locale ber-AM/PM ditulis 09.00 AM, dan tombol harus memuatnya tanpa melipat. Nilai di luar skala --space-* karena skala itu berhenti di 6rem sementara kolom ini butuh lebih; sama kasusnya dengan max-width kotak search di catalog.css. */
  --appointment-picker-rail-height: var(--space-24); /** Tinggi maksimum daftar slot sebelum digulung, dikalikan tiga di CSS. Dipatok, bukan dibiarkan ikut tinggi kalender: jumlah baris kalender berubah antar bulan (4 sampai 6), dan rail yang ikut berubah tinggi membuat seluruh kartu melompat tiap ganti bulan. */
  --appointment-picker-slot-min-width: var(--space-20); /** Lebar minimum satu kolom slot di layout grid. Ini yang menentukan berapa kolom muat — grid memakai auto-fill, jadi jumlah kolomnya hasil pembagian lebar wadah oleh nilai ini, bukan angka yang ditulis. */
  --appointment-picker-fold-width: 26rem; /** Lebar wadah tempat layout side melipat jadi grid. Ditulis di sini supaya nilainya punya satu rumah walau CSS TIDAK BISA membacanya — container query tidak menerima var() di dalam kondisinya, sama seperti media query. Nilainya diulang di appointment-picker.css dan wajib diubah bersamaan. */
  --appointment-picker-max-width: 30rem; /** Lebar alami kartu layout side: kalender (15.5rem) + garis + rail (10rem) + padding. Kartunya TIDAK boleh diukur dari isinya (width: fit-content) — root-nya container-type: inline-size, dan containment membuat lebar elemen berhenti bergantung pada isinya. Jadi lebarnya datang dari luar: width 100% dijepit max-width ini. */
  --appointment-picker-max-width-stacked: 20rem; /** Padanannya untuk layout grid dan footer, yang cuma selebar kalender. Alasan yang sama. */
  --autocomplete-min-width: 12.5rem; /** Batas bawah lebar panel. Panelnya selebar wadah kotak ketik lewat --pz-anchor-width; token ini yang menahannya saat fieldnya dipasang di kolom sempit, supaya daftar saran tidak jadi lebih sempit dari isinya sendiri. Nilainya sama dengan combobox.min-width dan itu disengaja: dua panel saran berdampingan yang lebar minimumnya berbeda akan terbaca sebagai dua komponen dari sistem yang berbeda. Di luar skala spacing project yang berhenti di space-24 (6rem) — preseden token off-scale: popover.json, select.json, dialog.json, combobox.json. */
  --button-outline-border: var(--color-slate-300); /** Garis tepi tombol outline. Sengaja lebih terang dari --color-input (slate-500): aturan 3:1 WCAG 1.4.11 berlaku untuk field isian karena garis itu satu-satunya penanda batas kontrol, sedangkan tombol sudah ditandai labelnya sendiri plus --shadow-1. slate-300 tetap setingkat lebih tegas dari --color-border (slate-200) supaya tombol tidak lebur dengan garis kartu. Keputusan Tony 19 Sep 2026. */
  --calendar-cell: var(--space-8); /** Sisi satu kotak tanggal. Di sumbernya ini custom property --cell-size bernilai --spacing(8), dan dipakai di lima tempat sekaligus: ukuran tombol navigasi, tinggi baris caption, padding kiri-kanan caption supaya judul bulan tidak bertabrakan dengan tombol navigasi yang melayang di atasnya, lebar minimum tombol tanggal, dan lebar kolom nomor minggu. Satu nilai, lima pemakai — persis alasan kenapa ia jadi variabel di sumbernya, bukan angka yang diulang. */
  --calendar-day-label-size: 0.8rem; /** Nama hari di kepala grid dan nomor minggu. Di sumbernya ditulis text-0.8rem — nilai di luar skala Tailwind, sengaja diambil di antara xs 0.75rem dan sm 0.875rem supaya tujuh nama hari muat di lebar kotak tanggal tanpa terlihat mengecil. Ditokenkan, bukan ditulis mentah, karena ia memang ukuran desain yang bisa berubah. */
  --calendar-dropdown-icon: 0.875rem; /** Chevron di pemilih bulan dan tahun saat caption layout dropdown. Di sumbernya size-3.5, lebih kecil dari ikon tombol biasa yang size-4, supaya panah tidak menyaingi teks bulannya sendiri. */
  --calendar-dropdown-height: var(--space-8); /** Tinggi kotak pemilih bulan dan tahun. Di sumbernya h-8, sengaja lebih pendek dari tinggi tombol biasa var(--space-9) supaya baris caption tidak mendorong grid ke bawah. */
  --chart-height: 16rem; /** Tinggi bawaan area gambar, sudah termasuk pita label sumbu di bawahnya. Di luar skala spacing yang berhenti di 6rem — preseden nilai di luar skala: sidebar.json width, dialog.json, data-table.json. Pemakai boleh menggantinya lewat --chart-height di elemennya sendiri. Angkanya bukan hiasan: di bawah kira-kira 12rem, tick sumbu Y mulai berdesakan sampai harus dipangkas jadi dua, dan grafik berhenti bisa dibaca nilainya tanpa tooltip. */
  --chart-bar-max: 1.5rem; /** Tebal maksimum satu batang. Batang TIDAK pernah memenuhi jatah slotnya — sisanya sengaja dibiarkan jadi udara, karena blok tebal berwarna pekat terbaca berisik justru saat datanya sedikit. Nilainya kebetulan sama dengan --space-6, tapi tidak di-reference ke sana: token component cuma boleh menunjuk semantic (Tier Reference Rule), dan skala spacing semantic tidak punya ukuran setebal ini. */
  --chart-dot-size: 0.5rem; /** Diameter penanda titik yang muncul saat garis disorot. Batas bawah 8px datang dari kebutuhan sasaran sentuh, bukan dari selera bentuk: titik yang lebih kecil dari ini tidak bisa dikenai pointer dengan andal. Sasaran sorotnya sendiri jauh lebih lebar dari titiknya — yang dipakai pita di sepanjang sumbu X, bukan lingkaran ini. */
  --chart-axis-gap: var(--space-2); /** Jarak antara area gambar dan pita label sumbu (gutter tick nilai, jarak label kategori, penyangga hitung `skip` berselang). Dibaca JS lewat `padding-block-start` elemen meteran `.chart__metrics` (lihat RULES §Coding Conventions, Batch 15) — sebelum token ini ada, `.chart__metrics` tidak pernah diberi padding sama sekali, jadi `m.axisGap` selalu NOL dan keempat pemakainya berjalan tanpa jarak, cuma selamat karena `measureWidth` mengukur kotak huruf yang sudah punya sedikit sisa. Nilainya `var(--space-2)`, bukan referensi semantic: skala spacing semantic (`inset`/`stack`) tidak punya entri sekecil ini, jadi ditulis langsung ke core seperti `--sidebar-width-icon` — pola yang sama, bukan pengecualian baru. */
  --combobox-min-width: 12.5rem; /** Lebar minimum trigger dan panel. shadcn menulis w-200px di keduanya; Base UI menyerahkannya ke lebar jangkar. Di sini panel selebar trigger lewat --pz-anchor-width, dan token ini jadi batas bawahnya supaya panel tidak pernah lebih sempit dari isinya saat triggernya sendiri sempit. Di luar skala spacing project yang berhenti di space-24 (6rem) — preseden token off-scale: popover.json, select.json, dialog.json. */
  --command-list-max-height: 18.75rem; /** shadcn `max-h-300px` di CommandList. Di luar skala spacing project, yang berhenti di space-24 (6rem). Ditulis rem, bukan px seperti sumbernya: pada ukuran font root bawaan nilainya identik (300px), tapi rem membuat tinggi daftar ikut tumbuh saat pengguna memperbesar teks. Kalau tetap px, jumlah baris yang terlihat justru menyusut persis di saat teksnya diperbesar. Preseden token off-scale: popover.json, dialog.json. */
  --command-dialog-max-width: 38.25rem; /** Lebar palette di dalam <dialog> (Command Dialog): dialog-max-width (32rem) + 100px, permintaan Tony supaya palette terasa lebih lega dari dialog biasa. Dulu ditulis `calc(var(--dialog-max-width) + 100px)` di command.css — ditulis ulang jadi nilai jadi karena token component tidak boleh menunjuk token component lain (Tier Reference Rule), dan 100px mentah melanggar lint. Konsekuensinya: kalau dialog-max-width berubah, token ini TIDAK ikut — sengaja, lebar palette keputusan tersendiri. Pada font root bawaan identik dengan nilai lama (612px). */
  --command-dialog-list-max-height: 25rem; /** Tinggi maksimum daftar di Command Dialog: list-max-height (18.75rem) + 100px, pasangan dari dialog-max-width di atas — palette layar penuh memuat lebih banyak baris dari Command di dalam kartu. Pada font root bawaan identik dengan nilai lama (400px). Rem, bukan px, dengan alasan yang sama seperti list-max-height. */
  --context-menu-min-width: 8rem; /** shadcn `min-w-[8rem]` di ContextMenuContent dan ContextMenuSubContent. Skala spacing project berhenti di space-24 (6rem), jadi nilai ini di luar skala manapun. Sengaja tidak mereferensi token Dropdown Menu walau nilainya kebetulan sama: token component milik satu komponen saja, dan mengubah lebar menu klik-kanan tidak boleh ikut mengubah menu tombol. */
  --data-table-filter-width: 24rem; /** Lebar maksimum kotak pencarian di bilah alat. Di sumbernya max-w-sm, yang di skala Tailwind bernilai 24rem — ukuran container, bukan ukuran spacing, jadi tidak ada padanannya di skala space project ini. Preseden nilai di luar skala: sidebar.json width, sheet.json, dialog.json. */
  --data-table-page-size-width: 4.375rem; /** Lebar pemilih ukuran halaman. Di sumbernya w-70px, nilai lepas di luar skala mana pun karena ia dipas ke isinya: dua digit plus ikon chevron. Ditokenkan supaya tidak jadi literal di CSS komponen. */
  --data-table-page-indicator-width: 10rem; /** Lebar penunjuk 'Halaman X dari Y'. Lebarnya dikunci supaya tombol navigasi di sebelahnya tidak bergeser saat jumlah digitnya bertambah — tombol yang berpindah tempat sendiri membuat orang salah klik. Di sumbernya w-100px, cukup untuk 'Page 1 of 3'; 'Halaman 10 dari 12' tidak muat di situ dan terpotong jadi dua baris. Ini penyimpangan yang disebabkan bahasa, bukan pilihan desain — nilainya diambil dari kalimat terpanjang yang mungkin, bukan dari kalimat yang kebetulan sedang tampil. */
  --data-table-facet-width: 12.5rem; /** Lebar panel faceted filter. Di sumbernya w-200px, nilai lepas di luar skala spacing project yang berhenti di space-24 (6rem). Nilainya sama dengan --combobox-min-width dan --autocomplete-min-width, dan itu disengaja: tiga panel berisi daftar yang bisa dicari, dengan lebar berbeda, akan terbaca sebagai tiga komponen dari sistem yang berbeda. TIDAK di-reference ke sana — token component tidak boleh menunjuk token component lain (Tier Reference Rule). Bedanya dengan Combobox: di sini lebarnya PASTI, bukan batas bawah, karena panel ini tidak menempel pada lebar triggernya (trigger 'Status' jauh lebih sempit dari daftar isinya). */
  --date-picker-trigger-width: 15rem; /** Lebar tombol pemicu di contoh resmi shadcn, w-240px. Lebarnya dikunci supaya tombol tidak berubah ukuran saat labelnya berpindah dari placeholder pendek ke tanggal panjang — pergeseran itu menggeser apa pun yang ada di sebelahnya. */
  --date-picker-trigger-width-range: 18.75rem; /** Lebar pemicu untuk rentang tanggal, w-300px di sumbernya. Lebih lebar karena labelnya memuat dua tanggal sekaligus. */
  --dialog-max-width: 32rem; /** shadcn `sm:max-w-lg` di DialogContent. Skala spacing project berhenti di space-24 (6rem), jadi lebar maksimum panel di luar skala manapun. Preseden: popover.json, hover-card.json. */
  --drawer-max-height: 80vh; /** shadcn `max-h-[80vh]` untuk drawer atas dan bawah. Nilainya relatif tinggi layar, bukan skala spacing — panel yang ditarik dari tepi harus selalu menyisakan halaman yang terlihat di belakangnya, berapa pun tinggi layarnya. */
  --drawer-max-width: 24rem; /** shadcn `sm:max-w-sm` untuk drawer kiri dan kanan. Nilainya kebetulan sama dengan sheet-max-width, tapi tokennya sendiri — token component milik satu komponen saja, dan melebarkan Sheet tidak boleh ikut melebarkan Drawer. Preseden: select-min-width terhadap dropdown-menu-min-width. */
  --drawer-handle-width: 100px; /** shadcn `w-[100px]` untuk batang penanda seret. Nilai arbitrary di luar skala spacing manapun. Tingginya sendiri on-scale (space-2), jadi tidak ditokenkan. */
  --drawer-dismiss-ratio: 0.25; /** Seberapa jauh panel harus diseret sebelum dilepas berarti menutup — seperempat ukurannya sendiri. Angka perilaku, bukan ukuran, jadi tidak ada skala core yang cocok. Dibaca drawer.js lewat --pz-dismiss-ratio, mengikuti pola --pz-side-offset di overlay. */
  --dropdown-menu-min-width: 8rem; /** shadcn `min-w-[8rem]`. Skala spacing project berhenti di space-24 (6rem), jadi nilai ini di luar skala manapun. Dibulatkan ke bawah akan melanggar Fidelity Constraint. Preseden: switch.json, skeleton.json. */
  --hover-card-width: 16rem; /** shadcn `w-64` di HoverCardContent. Skala spacing project berhenti di space-24 (6rem), jadi lebar ini di luar skala manapun. Nilai default — konsumen boleh menimpanya lewat inline style. Preseden: popover.json. */
  --hover-card-open-delay: 700ms; /** Default openDelay Radix HoverCard. Jeda perilaku, bukan durasi animasi: skala motion core cuma berisi durasi animasi, dan tier rule melarang component mereferensi core. Ditulis mentah di sini supaya tetap satu tempat kalau nanti dirasa terlalu lambat. */
  --hover-card-close-delay: 300ms; /** Default closeDelay Radix HoverCard. Jeda ini yang membuat kursor sempat berpindah dari trigger ke isi kartu tanpa kartunya keburu tertutup. */
  --menubar-min-width: 12rem; /** shadcn `min-w-[12rem]` di MenubarContent. Lebih lebar dari menu tombol (8rem) karena menu bilah biasanya memuat shortcut di sisi kanan item. Di luar skala spacing project (berhenti di space-24 = 6rem), jadi masuk tier component. Preseden: dropdown-menu.json. */
  --menubar-align-offset: -4px; /** shadcn memberi MenubarContent alignOffset -4: panel digeser sedikit ke kiri triggernya supaya padding bilah ikut terhitung dan teks item sejajar dengan teks trigger. Nilai negatif, jadi tidak ada token spacing yang bisa dipakai — skala spacing project semuanya positif. position.js membacanya lewat --pz-align-offset. Catatan: kurung kurawal tidak boleh muncul di comment, Style Dictionary membacanya sebagai referensi token dan build langsung mati. */
  --menubar-sub-min-width: 8rem; /** shadcn `min-w-[8rem]` di MenubarSubContent. Submenu lebih sempit dari panel induknya, persis seperti sumbernya. Sengaja tidak mereferensi token Dropdown Menu walau nilainya kebetulan sama: token component milik satu komponen saja. */
  --navigation-menu-highlight: color-mix(in oklch, var(--color-accent) 50%, transparent); /** shadcn `bg-accent/50` untuk trigger yang panelnya sedang terbuka dan untuk tautan yang menandai halaman sekarang. Setengah tekanan dari sorotan hover, supaya 'sedang terbuka' tidak terbaca sama kuatnya dengan 'sedang disentuh kursor'. Persentase di dalam color-mix tidak bisa memakai token opacity — color-mix menuntut persen, sedangkan --opacity-50 bernilai 0.5. */
  --navigation-menu-open-delay: 150ms; /** Jeda sebelum kursor yang melintas membuka panel. Jeda perilaku, bukan durasi animasi, jadi skala motion core tidak berlaku — sama seperti hover-card-open-delay dan tooltip-delay. Tanpa jeda, menyapu kursor melewati bilah membuka dan menutup tiap panel beruntun. */
  --navigation-menu-close-delay: 300ms; /** Jeda sebelum panel tertutup setelah kursor pergi. Lebih panjang dari jeda buka supaya kursor yang menyeberang dari trigger ke isi panel — dan sesaat melewati celah di antaranya — tidak menutup panel yang sedang dituju. */
  --popover-width: 18rem; /** shadcn `w-72` di PopoverContent. Skala spacing project berhenti di space-24 (6rem), jadi lebar ini di luar skala manapun. Nilai default — konsumen boleh menimpanya lewat inline style. */
  --progress-indeterminate-width: 40%;
  --progress-indeterminate-duration: 1400ms;
  --select-min-width: 8rem; /** shadcn `min-w-[8rem]` di SelectContent. Nilai sama dengan dropdown-menu, tapi tokennya sendiri: tier component tidak boleh saling mereferensi, dan menumpang token komponen lain bikin dua komponen terikat tanpa alasan. */
  --select-trigger-hover: var(--color-field); /** Latar trigger saat kursor di atasnya. Di light mode shadcn tidak mengubah apa pun (nilainya sama dengan latar field), perubahan hover cuma ada di dark mode. */
  --sheet-max-width: 24rem; /** shadcn `sm:max-w-sm` di SheetContent sisi kiri dan kanan. Skala spacing project berhenti di space-24 (6rem), jadi lebar maksimum panel tepi di luar skala manapun. Preseden: dialog.json, popover.json. */
  --sidebar-width: 16rem; /** Lebar panel saat terbentang. Di sumbernya konstanta SIDEBAR_WIDTH = '16rem'. Skala spacing project berhenti di space-24 (6rem), jadi lebar panel navigasi memang di luar skala manapun — preseden: sheet.json, dialog.json. Dipakai di lima tempat sekaligus (lebar panel, lebar pengganjal, jarak geser saat tersembunyi, dan dua kali di posisi tertutup kiri/kanan), persis alasan ia jadi variabel di sumbernya. */
  --sidebar-width-icon: var(--space-12); /** Lebar panel saat menyusut jadi deretan ikon. Di sumbernya SIDEBAR_WIDTH_ICON = '3rem', kebetulan tepat space-12. Tetap ditokenkan walau ada di skala, karena ia sepasang dengan --sidebar-width: kalau salah satu diubah tanpa yang lain, panel ikon jadi lebih lebar dari panel terbentang tanpa ada yang menyadarinya. */
  --sidebar-width-mobile: 18rem; /** Lebar panel saat ia berpindah jadi sheet di layar sempit. Di sumbernya SIDEBAR_WIDTH_MOBILE = '18rem' — sengaja LEBIH LEBAR dari versi desktop, karena di layar sempit panel ini menutupi halaman dan tidak perlu berbagi ruang dengan apa pun. */
  --sidebar-label: color-mix(in oklch, var(--color-sidebar-foreground) 70%, transparent); /** Warna judul kelompok di dalam panel. Di sumbernya text-sidebar-foreground/70 — diredupkan supaya judul kelompok tidak terbaca sekuat item menunya sendiri. Persentase di dalam color-mix tidak bisa memakai token opacity: color-mix menuntut persen, sedangkan --opacity-70 bernilai 0.7. Catatan yang sama sudah ada di navigation-menu.json. */
  --sidebar-rail: var(--space-4); /** Lebar pita tipis di tepi panel yang bisa diklik untuk membuka-tutup. Di sumbernya w-4. */
  --skeleton-pulse-duration: 2000ms;
  --skeleton-pulse-easing: cubic-bezier(0.4, 0, 0.6, 1);
  --slider-vertical-length: 11rem;
  --switch-track-height: 1.15rem;
  --switch-track-off: var(--color-input); /** Warna rel saat mati. Turun jadi 80% di dark mode, mengikuti sumbernya. */
  --switch-thumb-on: var(--color-background); /** Warna bulatan saat menyala. Di light mode sama dengan latar halaman; di dark mode shadcn menggantinya ke primary-foreground supaya bulatan tetap terbaca di atas rel biru. */
  --switch-thumb-off: var(--color-background); /** Warna bulatan saat mati. Di dark mode jadi foreground — rel yang gelap butuh bulatan terang, bukan bulatan sewarna latar. */
  --table-row-hover: color-mix(in oklch, var(--color-muted) 50%, transparent); /** shadcn `bg-muted/50` untuk baris yang disorot kursor dan untuk latar kaki tabel. Persentase di dalam color-mix tidak bisa memakai token opacity — color-mix menuntut persen, sedangkan --opacity-50 bernilai 0.5. Ditokenkan supaya tidak menambah literal baru di CSS komponen, mengikuti pola alert-destructive-description. */
  --tabs-list-padding: 3px; /** shadcn `p-[3px]` di TabsList. Nilai arbitrary yang tidak ada di skala spacing manapun — space-1 (4px) bakal membuat tab aktif tidak lagi sejajar dengan hitungan tinggi h-9. Presedennya switch.json: dimensi di luar skala masuk tier component, bukan ditulis mentah di CSS. */
  --tabs-trigger-inactive: color-mix(in oklch, var(--color-foreground) 60%, transparent); /** Warna teks tab yang tidak aktif. shadcn memakai `text-foreground/60` di light dan `dark:text-muted-foreground` di dark — dua warna yang berbeda sumber, jadi wajib jadi token supaya CSS komponen tidak perlu bercabang per tema (RULES §Tema). */
  --tabs-trigger-active-bg: var(--color-background); /** Latar tab aktif. Di light mode tab aktif naik ke warna halaman supaya terbaca terangkat dari alas list yang muted. Di dark mode alasnya sudah gelap, jadi shadcn justru memakai film field (`dark:bg-input/30`) — perbedaan itu tinggal di token dark. */
  --tabs-trigger-active-border: transparent; /** Garis tepi tab aktif. Light mode tidak butuh garis karena beda latar sudah cukup; dark mode memakai --color-input karena beda latarnya tipis. */
  --toast-width: 356px; /** Lebar satu kartu toast. Nilai TOAST_WIDTH di sonner, library yang dipakai shadcn — dan sonner memang menulisnya dalam piksel, bukan rem, karena lebar kartu pemberitahuan tidak boleh ikut membesar saat pengguna memperbesar font. Di luar skala spacing manapun. */
  --toast-gap: var(--space-3-5); /** Jarak antar kartu saat tumpukan mekar. GAP = 14 di sonner, tepat space-3.5. Dipakai di tiga tempat: jarak mekar, jarak geser tiap kartu di tumpukan rapat, dan tinggi jembatan tak terlihat yang menjaga kursor tetap dianggap berada di atas tumpukan saat melintasi celah antar kartu. */
  --toast-offset: var(--space-6); /** Jarak tumpukan dari tepi layar. VIEWPORT_OFFSET = '24px' di sonner, tepat space-6. */
  --toast-duration: 4000ms; /** Umur satu toast sebelum menutup sendiri. Durasi PERILAKU, bukan durasi animasi, jadi skala motion core tidak berlaku — preseden: navigation-menu-close-delay, tooltip-delay. Nilai bawaan sonner; toast bertipe loading sengaja tidak memakainya sama sekali karena yang ditunggunya belum selesai. */
  --toast-swipe-threshold: 20px; /** Sejauh apa kartu harus diseret sebelum dianggap dibuang. Di bawah nilai ini kartu kembali ke tempatnya. Sonner memakai 20px, dan menambahkan jalan kedua lewat kecepatan lepas — seretan pendek tapi cepat tetap membuang, sama seperti Drawer di Batch 12. */
  --toast-swipe-velocity: 0.11; /** Kecepatan lepas (piksel per milidetik) yang sudah cukup membuang kartu walau seretannya belum melewati ambang jarak. Tanpa jalan kedua ini, sentakan cepat terasa tidak direspons. */
  --toast-stack-scale: 0.05; /** Seberapa kecil tiap kartu di belakang, per tingkat. Kartu kedua 95%, ketiga 90%. Nilai sonner. Bukan ukuran dan bukan warna — ia pengali, jadi tidak ada tier token yang bisa jadi sumbernya. */
  --toast-stack-visible: 3; /** Berapa kartu yang terlihat di tumpukan rapat. VISIBLE_TOASTS_AMOUNT di sonner. Sisanya tetap ada dan tetap dihitung mundur, cuma tidak digambar — kalau dibuang begitu saja, toast keempat tidak akan pernah terbaca. */
  --tooltip-delay: 0ms; /** shadcn menyetel delayDuration nol di TooltipProvider — tooltip muncul seketika saat kursor masuk. Ditokenkan supaya bisa diubah satu tempat kalau nanti dirasa terlalu cepat; skala motion core cuma berisi durasi animasi, bukan jeda perilaku. CATATAN: jangan tulis kurung kurawal di komentar token — Style Dictionary membacanya sebagai referensi token dan build gagal. */
}

/* Dark mode.

   Dua blok, bukan satu, dan urutannya disengaja:

   1. `.dark` — saklar eksplisit. Dipasang di <html> oleh aplikasi yang punya
      tombol tema sendiri.
   2. Blok media — mengikuti setelan sistem, tapi hanya kalau halaman tidak
      menyatakan tema secara eksplisit. `:not(.light)` itu yang membuat
      pilihan pengguna selalu menang atas setelan sistem.

   Halaman yang tidak memasang class apa pun tetap mendapat dark mode saat
   sistem pemakainya gelap. Yang memasang `.light` tetap terang, walau
   sistemnya gelap. */
.dark {
  --color-background: var(--color-slate-950);
  --color-foreground: var(--color-slate-50);
  --color-card: var(--color-slate-900); /** Di light mode kartu sewarna halaman; di dark mode dinaikkan satu tingkat supaya permukaannya terbaca terangkat. Inilah alasan --color-card dibuat terpisah sejak Batch 1 M3, walau saat itu nilainya identik. */
  --color-card-foreground: var(--color-slate-50);
  --color-popover: var(--color-slate-900);
  --color-popover-foreground: var(--color-slate-50);
  --color-overlay: oklch(0 0 0 / 50%); /** Sama dengan light mode. Kelam modal tidak ikut membalik saat tema gelap — halaman di belakangnya tetap harus mundur, dan di tema gelap kelam putih justru membuatnya maju. */
  --color-primary: var(--color-blue-500); /** Satu langkah lebih terang dari light mode (blue-600). Warna aksi harus naik terang di latar gelap, bukan turun. */
  --color-primary-foreground: var(--color-slate-950);
  --color-secondary: var(--color-slate-800);
  --color-secondary-foreground: var(--color-slate-50);
  --color-muted: var(--color-slate-800);
  --color-muted-foreground: var(--color-slate-400);
  --color-accent: var(--color-slate-800);
  --color-accent-foreground: var(--color-slate-50);
  --color-destructive: var(--color-red-400); /** red-400 (L 0.704) — angka lightness yang sama dengan destructive dark shadcn. Dipakai red-500 dulu dan teks di tombol destructive cuma 2,33:1, karena latarnya masih diturunkan lagi jadi 60%. */
  --color-destructive-foreground: var(--color-slate-950); /** Teks gelap di atas merah terang, kebalikan dari light mode. shadcn tetap memakai teks putih di dark dan hasilnya 1,8:1 — tidak diikuti. PRD §6.4 menyebut warna sebagai satu dari dua pengecualian Fidelity Constraint, jadi ini penyimpangan yang memang diizinkan. */
  --color-success: var(--color-green-500);
  --color-success-foreground: var(--color-slate-950);
  --color-warning: var(--color-amber-400);
  --color-warning-foreground: var(--color-slate-950);
  --color-border: oklch(1 0 0 / 10%); /** Putih beralpha, bukan abu pekat. Garis di latar gelap harus ikut warna permukaan di bawahnya — abu tetap akan terlihat sebagai garis kotor di atas kartu yang lebih terang dari halaman. Sama seperti sumbernya. */
  --color-input: oklch(1 0 0 / 40%); /** Putih 40%, bukan 15% seperti shadcn. Alasan sama seperti light mode: ini batas kontrol, bukan garis dekoratif. --color-border tetap 10%. */
  --color-ring: var(--color-blue-400); /** Satu langkah lebih terang dari light mode. Ring fokus harus menang terang di latar gelap. */
  --color-field: color-mix(in oklch, var(--color-input) 30%, transparent); /** Film tipis di dalam field. Karena --color-input di dark mode sendiri sudah putih beralpha, hasilnya sekitar 4,5% putih — cekungan halus, bukan kotak abu. Persis dark:bg-input/30 di sumbernya. */
  --color-field-hover: color-mix(in oklch, var(--color-input) 50%, transparent);
  --color-accent-hover: color-mix(in oklch, var(--color-accent) 50%, transparent);
  --color-destructive-surface: var(--color-destructive); /** Latar penuh, bukan 60% seperti sumbernya. Latar yang diredupkan 60% di atas halaman gelap mendarat tepat di tengah skala terang — tidak ada warna teks yang bisa lolos ambang di atasnya. */
  --color-destructive-ring: color-mix(in oklch, var(--color-destructive) 40%, transparent);
  --color-destructive-item: color-mix(in oklch, var(--color-destructive) 20%, transparent);
  --color-sidebar: var(--color-slate-900); /** Sama dengan --color-card di dark mode, dan itu disengaja: di latar gelap yang mundur adalah yang lebih GELAP, jadi panel samping tidak bisa lagi diturunkan di bawah halaman yang sudah slate-950. Ia justru naik satu tingkat, persis seperti kartu. Arah pembedanya berbalik antar tema — itulah sebabnya ini token, bukan cabang CSS. */
  --color-sidebar-foreground: var(--color-slate-50);
  --color-sidebar-primary: var(--color-blue-600); /** Berpindah dari abu ke biru di dark mode, dan itu terpaksa: di light mode kotak lambang slate-900 menonjol di atas panel slate-50, sedangkan di dark mode panelnya SENDIRI sudah slate-900 — kotak abu di sana lenyap sama sekali. shadcn mengambil jalan yang sama (neutral di terang, berwarna di gelap), cuma hue-nya berbeda karena palet kita sendiri. */
  --color-sidebar-primary-foreground: var(--color-slate-50);
  --color-sidebar-accent: var(--color-slate-800);
  --color-sidebar-accent-foreground: var(--color-slate-50);
  --color-sidebar-border: oklch(1 0 0 / 10%); /** Putih beralpha, alasan sama seperti --color-border dark: garis di latar gelap harus ikut warna permukaan di bawahnya. */
  --color-sidebar-ring: var(--color-blue-400);
  --color-chart-1: var(--color-blue-500); /** Satu langkah lebih terang dari light mode, sama seperti --color-primary: warna deret harus naik terang di latar gelap. Ini SATU-SATUNYA slot yang nilainya berbeda antar tema. Empat lainnya sama, dan itu hasil pengukuran, bukan kemalasan — pita lightness dark (0,48-0,67) lebih sempit daripada light (0,43-0,77), dan langkah yang lolos di pita sempit hampir selalu lolos juga di pita lebar. */
  --color-chart-2: var(--color-amber-600);
  --color-chart-3: var(--color-teal-600);
  --color-chart-4: var(--color-violet-500);
  --color-chart-5: var(--color-green-600);
  --switch-track-off: color-mix(in oklch, var(--color-input) 80%, transparent);
  --switch-thumb-on: var(--color-primary-foreground);
  --switch-thumb-off: var(--color-foreground);
  --button-outline-border: oklch(1 0 0 / 15%); /** Putih 15%, nilai asli shadcn untuk tombol outline. Lebih tipis dari --color-input dark (40%) dengan alasan yang sama seperti light mode. */
  --select-trigger-hover: color-mix(in oklch, var(--color-input) 50%, transparent);
  --tabs-trigger-inactive: var(--color-muted-foreground); /** Foreground diredupkan 60% seperti di light mode tidak dipakai di sini: di latar gelap hasilnya abu kotor yang mendekati alas list. shadcn juga berpindah ke muted-foreground di dark. */
  --tabs-trigger-active-bg: var(--color-field); /** Padanan `dark:data-[state=active]:bg-input/30`. Tab aktif tidak dinaikkan ke warna halaman — di dark mode halaman justru lebih gelap dari alas list, jadi menaikkannya malah menenggelamkan tab aktif. */
  --tabs-trigger-active-border: var(--color-input); /** Beda latar antara tab aktif dan alasnya tipis di dark mode, jadi batasnya ditegaskan garis. */
}

@media (prefers-color-scheme: dark) {
  :root:not(.light) {
    --color-background: var(--color-slate-950);
    --color-foreground: var(--color-slate-50);
    --color-card: var(--color-slate-900); /** Di light mode kartu sewarna halaman; di dark mode dinaikkan satu tingkat supaya permukaannya terbaca terangkat. Inilah alasan --color-card dibuat terpisah sejak Batch 1 M3, walau saat itu nilainya identik. */
    --color-card-foreground: var(--color-slate-50);
    --color-popover: var(--color-slate-900);
    --color-popover-foreground: var(--color-slate-50);
    --color-overlay: oklch(0 0 0 / 50%); /** Sama dengan light mode. Kelam modal tidak ikut membalik saat tema gelap — halaman di belakangnya tetap harus mundur, dan di tema gelap kelam putih justru membuatnya maju. */
    --color-primary: var(--color-blue-500); /** Satu langkah lebih terang dari light mode (blue-600). Warna aksi harus naik terang di latar gelap, bukan turun. */
    --color-primary-foreground: var(--color-slate-950);
    --color-secondary: var(--color-slate-800);
    --color-secondary-foreground: var(--color-slate-50);
    --color-muted: var(--color-slate-800);
    --color-muted-foreground: var(--color-slate-400);
    --color-accent: var(--color-slate-800);
    --color-accent-foreground: var(--color-slate-50);
    --color-destructive: var(--color-red-400); /** red-400 (L 0.704) — angka lightness yang sama dengan destructive dark shadcn. Dipakai red-500 dulu dan teks di tombol destructive cuma 2,33:1, karena latarnya masih diturunkan lagi jadi 60%. */
    --color-destructive-foreground: var(--color-slate-950); /** Teks gelap di atas merah terang, kebalikan dari light mode. shadcn tetap memakai teks putih di dark dan hasilnya 1,8:1 — tidak diikuti. PRD §6.4 menyebut warna sebagai satu dari dua pengecualian Fidelity Constraint, jadi ini penyimpangan yang memang diizinkan. */
    --color-success: var(--color-green-500);
    --color-success-foreground: var(--color-slate-950);
    --color-warning: var(--color-amber-400);
    --color-warning-foreground: var(--color-slate-950);
    --color-border: oklch(1 0 0 / 10%); /** Putih beralpha, bukan abu pekat. Garis di latar gelap harus ikut warna permukaan di bawahnya — abu tetap akan terlihat sebagai garis kotor di atas kartu yang lebih terang dari halaman. Sama seperti sumbernya. */
    --color-input: oklch(1 0 0 / 40%); /** Putih 40%, bukan 15% seperti shadcn. Alasan sama seperti light mode: ini batas kontrol, bukan garis dekoratif. --color-border tetap 10%. */
    --color-ring: var(--color-blue-400); /** Satu langkah lebih terang dari light mode. Ring fokus harus menang terang di latar gelap. */
    --color-field: color-mix(in oklch, var(--color-input) 30%, transparent); /** Film tipis di dalam field. Karena --color-input di dark mode sendiri sudah putih beralpha, hasilnya sekitar 4,5% putih — cekungan halus, bukan kotak abu. Persis dark:bg-input/30 di sumbernya. */
    --color-field-hover: color-mix(in oklch, var(--color-input) 50%, transparent);
    --color-accent-hover: color-mix(in oklch, var(--color-accent) 50%, transparent);
    --color-destructive-surface: var(--color-destructive); /** Latar penuh, bukan 60% seperti sumbernya. Latar yang diredupkan 60% di atas halaman gelap mendarat tepat di tengah skala terang — tidak ada warna teks yang bisa lolos ambang di atasnya. */
    --color-destructive-ring: color-mix(in oklch, var(--color-destructive) 40%, transparent);
    --color-destructive-item: color-mix(in oklch, var(--color-destructive) 20%, transparent);
    --color-sidebar: var(--color-slate-900); /** Sama dengan --color-card di dark mode, dan itu disengaja: di latar gelap yang mundur adalah yang lebih GELAP, jadi panel samping tidak bisa lagi diturunkan di bawah halaman yang sudah slate-950. Ia justru naik satu tingkat, persis seperti kartu. Arah pembedanya berbalik antar tema — itulah sebabnya ini token, bukan cabang CSS. */
    --color-sidebar-foreground: var(--color-slate-50);
    --color-sidebar-primary: var(--color-blue-600); /** Berpindah dari abu ke biru di dark mode, dan itu terpaksa: di light mode kotak lambang slate-900 menonjol di atas panel slate-50, sedangkan di dark mode panelnya SENDIRI sudah slate-900 — kotak abu di sana lenyap sama sekali. shadcn mengambil jalan yang sama (neutral di terang, berwarna di gelap), cuma hue-nya berbeda karena palet kita sendiri. */
    --color-sidebar-primary-foreground: var(--color-slate-50);
    --color-sidebar-accent: var(--color-slate-800);
    --color-sidebar-accent-foreground: var(--color-slate-50);
    --color-sidebar-border: oklch(1 0 0 / 10%); /** Putih beralpha, alasan sama seperti --color-border dark: garis di latar gelap harus ikut warna permukaan di bawahnya. */
    --color-sidebar-ring: var(--color-blue-400);
    --color-chart-1: var(--color-blue-500); /** Satu langkah lebih terang dari light mode, sama seperti --color-primary: warna deret harus naik terang di latar gelap. Ini SATU-SATUNYA slot yang nilainya berbeda antar tema. Empat lainnya sama, dan itu hasil pengukuran, bukan kemalasan — pita lightness dark (0,48-0,67) lebih sempit daripada light (0,43-0,77), dan langkah yang lolos di pita sempit hampir selalu lolos juga di pita lebar. */
    --color-chart-2: var(--color-amber-600);
    --color-chart-3: var(--color-teal-600);
    --color-chart-4: var(--color-violet-500);
    --color-chart-5: var(--color-green-600);
    --switch-track-off: color-mix(in oklch, var(--color-input) 80%, transparent);
    --switch-thumb-on: var(--color-primary-foreground);
    --switch-thumb-off: var(--color-foreground);
    --button-outline-border: oklch(1 0 0 / 15%); /** Putih 15%, nilai asli shadcn untuk tombol outline. Lebih tipis dari --color-input dark (40%) dengan alasan yang sama seperti light mode. */
    --select-trigger-hover: color-mix(in oklch, var(--color-input) 50%, transparent);
    --tabs-trigger-inactive: var(--color-muted-foreground); /** Foreground diredupkan 60% seperti di light mode tidak dipakai di sini: di latar gelap hasilnya abu kotor yang mendekati alas list. shadcn juga berpindah ke muted-foreground di dark. */
    --tabs-trigger-active-bg: var(--color-field); /** Padanan `dark:data-[state=active]:bg-input/30`. Tab aktif tidak dinaikkan ke warna halaman — di dark mode halaman justru lebih gelap dari alas list, jadi menaikkannya malah menenggelamkan tab aktif. */
    --tabs-trigger-active-border: var(--color-input); /** Beda latar antara tab aktif dan alasnya tipis di dark mode, jadi batasnya ditegaskan garis. */
  }
}

/* Base. Komponen ditulis dengan asumsi border-box; lihat build-tokens.mjs. */
* { box-sizing: border-box; }
/* Teks khusus pembaca layar: tidak terlihat, tetap dibacakan. */
.sr-only { position: absolute; width: var(--border-1); height: var(--border-1); overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
