/* Edith Camera — app web bersatu. Token warna HARUS sama persis dengan
   edith_kamera/lib/theme/app_colors.dart — jangan mengarang ulang angka di
   sini, salin dari sana kalau berubah. */

/* ---------- font self-hosted (BUKAN CDN — lihat catatan sw.js) ----------
   Roboto = font default Flutter (ThemeData tanpa fontFamily custom jatuh
   ke Roboto Android / San Francisco iOS lewat Flutter sendiri; supaya web
   & app terasa sama di kedua platform, web dipaksa pakai Roboto eksplisit,
   bukan ikut font sistem browser). Tiga berkas STATIS terpisah (400/500/
   700, subset latin) — bukan satu file "variable" yang digantung ke 3
   deklarasi weight: file variable-nya diperiksa dan TIDAK punya tabel
   fvar/wght sungguhan, jadi kalau dipakai begitu, teks w500/w700 akan
   dirender pakai outline Reguler (kurang tebal dari yang seharusnya). */
@font-face {
  font-family: 'Roboto';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/roboto-400.woff2') format('woff2');
}
@font-face {
  font-family: 'Roboto';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/roboto-500.woff2') format('woff2');
}
@font-face {
  font-family: 'Roboto';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/fonts/roboto-700.woff2') format('woff2');
}
/* Subset "latin" Google TIDAK menyertakan blok panah (teks panduan
   "Kiri 90° → Kiri 45°"/info Bandingkan) atau bentuk geometris (●◖◗◓ —
   penanda sisi di sides-data.js, sama seperti capture.html) — tanpa ini,
   karakter itu jatuh ke font sistem sementara sisanya Roboto, ganjil
   walau kecil. Satu berkas 2.2KB, satu unicode-range, berlaku ke ketiga
   weight sekaligus. */
@font-face {
  font-family: 'Roboto';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/fonts/roboto-extras.woff2') format('woff2');
  unicode-range: U+2192, U+21C4, U+25CF, U+25D3, U+25D6-25D7;
}

/* Material Symbols Rounded = padanan Icons.xxx_rounded Flutter. Variable
   font utuh (~5.3MB, sekali unduh, di-cache service worker) — lingkungan
   dev tidak punya alat pemotong font (fonttools/pyftsubset) untuk subset
   kecil, dan ini dipilih sadar ketimbang gantung ke CDN Google Fonts. */
@font-face {
  font-family: 'Material Symbols Rounded';
  font-style: normal;
  font-weight: 100 700;
  font-display: block;
  src: url('/fonts/material-symbols-rounded.woff2') format('woff2');
}
.material-symbols-rounded {
  font-family: 'Material Symbols Rounded';
  font-weight: normal;
  font-style: normal;
  font-size: 24px;
  line-height: 1;
  letter-spacing: normal;
  text-transform: none;
  display: inline-block;
  white-space: nowrap;
  word-wrap: normal;
  direction: ltr;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  vertical-align: middle;
  /* FILL 0 = outline (default) — dipatok FILL 1 langsung di elemen lewat
     style="font-variation-settings:'FILL' 1" untuk ikon yang di Flutter
     tampil solid (badge, tombol shutter, dst — lihat pemetaan per ikon). */
  font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
}

:root {
  --primary: #B08A80;
  --primary-dark: #8C6A61;
  --accent: #D9B8AE;
  --bg: #FFFFFF;
  --surface: #FFFFFF;
  --border: #EFE7E4;
  --ink: #3D2F2B;
  --muted: #7A6660;
  --success: #7D9471;
  --warning: #C89B5A;
  --danger: #B5605A;
  --warning-bg: #F7F0E6;
  --danger-bg: #F4E7E6;
  /* Layar kamera & pratinjau/koreksi foto SENGAJA tidak ikut palet terang —
     lihat catatan di app_colors.dart. */
  --dark: #1B1C1E;
  --dark2: #2A2C2F;
  --shadow: 0 3px 16px rgba(61, 47, 43, 0.04);
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body { margin: 0; padding: 0; overscroll-behavior: none; }
body {
  background: var(--bg);
  color: var(--ink);
  /* Roboto dulu (self-hosted, lihat @font-face di atas) — fallback sistem
     cuma jaga-jaga sepersekian detik sebelum font ter-render / kalau
     berkas font gagal total, BUKAN dipakai sengaja. */
  font: 16px/1.5 'Roboto', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, system-ui, sans-serif;
  -webkit-user-select: none;
  user-select: none;
}
input, textarea { -webkit-user-select: text; user-select: text; }
.hide { display: none !important; }
button, input, select, textarea { font-family: inherit; }

/* Onboarding SELALU jadi lapisan penuh di atas apa pun yang ada di
   belakangnya — dipakai baik sebagai gerbang awal (sebelum shell ada)
   maupun mode pratinjau dari Pengaturan (menutupi shell yang sudah aktif). */
#screenOnboarding { position: fixed; inset: 0; background: var(--bg); z-index: 90; overflow-y: auto; }

/* ---------- kartu & garis tepi ----------
   Latar layar dan permukaan kartu sama-sama putih — kartu dibedakan lewat
   border tipis + shadow sangat halus, BUKAN abu-abu (lihat AppTheme.softShadow
   Flutter, angka disamakan). */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  box-shadow: var(--shadow);
}

/* ---------- top bar ---------- */
.topbar {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  padding: calc(env(safe-area-inset-top) + 14px) 18px 14px;
  display: flex;
  align-items: center;
  gap: 14px;
  position: sticky;
  top: 0;
  z-index: 20;
}
.topbar h1 { font-size: 21px; font-weight: 800; margin: 0; letter-spacing: -.2px; flex: 1; color: var(--ink); }
.topbar button.icn {
  font-size: 21px; line-height: 1; background: none; border: none; color: var(--primary-dark);
  padding: 4px; cursor: pointer;
}
.topbar button.back { font-size: 24px; color: var(--ink); }

.pad { padding: 18px 16px calc(env(safe-area-inset-bottom) + 96px); max-width: 640px; margin: 0 auto; }

.brand {
  display: flex; align-items: center;
  padding: calc(env(safe-area-inset-top) + 18px) 18px 6px;
  max-width: 640px; margin: 0 auto;
}
.brand .logo { font-weight: 900; font-size: 15px; letter-spacing: 1.5px; color: var(--primary); line-height: 1.1; }
.brand .logo small { display: block; font-size: 9px; letter-spacing: .5px; color: var(--muted); font-weight: 600; }
.brand .sp { margin-left: auto; display: flex; gap: 18px; }
.brand button { background: none; border: none; font-size: 21px; color: var(--primary-dark); padding: 4px; cursor: pointer; }

/* = AppTheme.judulLayar (headlineMedium): 34/bold(700). */
h2.big { font-size: 34px; font-weight: 700; line-height: 1.16; margin: 10px 0 6px; letter-spacing: -.5px; color: var(--ink); }
/* = AppTheme.teksSekunder (bodySmall): 14.5/muted. */
p.sub { color: var(--muted); font-size: 14.5px; margin: 0 0 20px; }

/* ---------- login ---------- */
.login-wrap { padding: 12vh 24px 24px; max-width: 380px; margin: 0 auto; }
.login-mark { text-align: center; margin-bottom: 26px; }
.login-mark img { height: 64px; }

/* ---------- aksi besar (beranda) ---------- */
.act {
  display: flex; align-items: center; gap: 14px;
  background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow);
  border-radius: 16px; padding: 15px; margin-bottom: 12px; cursor: pointer;
  width: 100%; text-align: left; font: inherit; color: inherit;
}
.act .ic { width: 50px; height: 50px; border-radius: 13px; background: var(--accent); display: flex;
  align-items: center; justify-content: center; font-size: 22px; flex: 0 0 auto; }
.act .tx { flex: 1; min-width: 0; }
/* = ListTileCard Flutter: judul AppTheme.judulItemDaftar (titleMedium)
   19/w600, subjudul teksSekunder (bodySmall) 14.5/muted. */
.act .tx b { display: block; font-size: 19px; font-weight: 600; color: var(--ink); }
.act .tx span { color: var(--muted); font-size: 14.5px; }
.act .ch { color: var(--muted); font-size: 22px; }

/* ---------- tombol ----------
   = ElevatedButtonThemeData Flutter: padding 16v/20h, radius radiusTombol
   (13, sudah), textStyle 16/w600. */
.btn {
  background: var(--primary); color: #fff; border: none; border-radius: 13px; padding: 16px 20px;
  font: inherit; font-weight: 600; font-size: 16px; cursor: pointer; display: flex;
  align-items: center; justify-content: center; gap: 10px; width: 100%;
}
.btn.out { background: var(--surface); color: var(--primary-dark); border: 1.5px solid var(--primary); }
.btn.gray { background: var(--surface); color: var(--ink); border: 1px solid var(--border); }
.btn:disabled { opacity: .45; }
.btn + .btn { margin-top: 10px; }

/* ---------- daftar item ---------- */
.item {
  display: flex; align-items: center; gap: 13px;
  background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow);
  border-radius: 15px; padding: 13px; margin-bottom: 10px; cursor: pointer;
}
.item .th {
  width: 50px; height: 50px; border-radius: 12px; background: var(--accent); overflow: hidden; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center; font-size: 19px; color: var(--primary-dark);
}
.item .th img { width: 100%; height: 100%; object-fit: cover; }
.item .tx { flex: 1; min-width: 0; }
/* = ListTileCard Flutter: judul AppTheme.judulItemDaftar 19/w600, subjudul
   teksSekunder 14.5/muted. */
.item .tx b { display: block; font-size: 19px; font-weight: 600; letter-spacing: -.2px; color: var(--ink); }
.item .tx span { color: var(--muted); font-size: 14.5px; display: block; }
.item .ch { color: var(--muted); font-size: 22px; }

/* ---------- form ---------- */
label.lb { display: block; font-size: 12px; font-weight: 700; color: var(--muted);
  margin: 0 0 6px; text-transform: uppercase; letter-spacing: .6px; }
input, select {
  font: inherit; width: 100%; border-radius: 13px; border: 1.5px solid var(--border);
  background: var(--surface); color: var(--ink); padding: 14px; margin-bottom: 14px;
}
input:focus, select:focus { outline: none; border-color: var(--primary); }
.search-wrap { position: relative; }
.search-wrap .material-symbols-rounded {
  position: absolute; left: 14px; top: 50%; transform: translateY(-50%);
  color: var(--muted); font-size: 20px; pointer-events: none;
}
.search-wrap input { padding-left: 42px; }
.note { background: var(--accent); background: color-mix(in srgb, var(--accent) 35%, var(--surface)); border-radius: 14px; padding: 14px 16px; margin-bottom: 14px; border: 1px solid var(--border); }
.note ul { margin: 0; padding-left: 20px; font-size: 14px; } .note li { margin-bottom: 5px; }
/* = AppTheme.teksSekunder (bodySmall): 14.5/muted. */
.muted { color: var(--muted); font-size: 14.5px; }

.alert { border-radius: 13px; padding: 13px 15px; font-size: 14.5px; margin-bottom: 14px; }
.alert.e { background: var(--danger-bg); border: 1px solid var(--danger); color: var(--danger); }
.alert.w { background: var(--warning-bg); border: 1px solid var(--warning); color: #7A5510; }
.alert.s { background: #E9F1E6; border: 1px solid var(--success); color: #3F5A34; }
/* Penanda unduhan tanpa watermark (peran MARKETING) — lihat download.js. */
.penanda-tanpa-wm { font-size: 13px; padding: 9px 12px; margin: 10px 0; display: flex; gap: 6px; align-items: center; }

.chips { display: flex; gap: 8px; margin-bottom: 14px; flex-wrap: wrap; }
.chips button {
  background: var(--surface); border: 1px solid var(--border); color: var(--muted);
  border-radius: 20px; padding: 8px 15px; font: inherit; font-size: 14px; font-weight: 600; cursor: pointer;
}
.chips button.on { background: var(--primary); border-color: var(--primary); color: #fff; }

/* ---------- tab bar bawah ---------- */
.tabbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
  background: var(--surface); border-top: 1px solid var(--border);
  display: flex; padding: 8px 6px calc(env(safe-area-inset-bottom) + 8px);
  box-shadow: 0 -2px 16px rgba(61, 47, 43, 0.05);
}
.tabbar button {
  flex: 1; background: none; border: none; cursor: pointer; font: inherit;
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 6px 2px; color: var(--muted); font-size: 11px; font-weight: 600;
}
.tabbar button .ic { font-size: 21px; line-height: 1; }
.tabbar button.on { color: var(--primary); }
.tabbar button.on .ic { font-variation-settings: 'FILL' 1, 'wght' 500, 'GRAD' 0, 'opsz' 24; }

/* ---------- pencarian (ikon di dalam field, bukan placeholder teks —
   Material Symbols tidak bisa dirender di dalam atribut placeholder). */
.search-wrap { position: relative; }
.search-wrap > .material-symbols-rounded {
  position: absolute; left: 15px; top: 50%; transform: translateY(-50%);
  color: var(--muted); font-size: 20px; pointer-events: none;
}
.search-wrap input { padding-left: 46px; }

/* ══════════ layar kamera (gelap, terpisah dari palet terang) ══════════
   Latar terang di sekitar foto klinis mengubah persepsi warna kulit pasien
   — SENGAJA tidak ikut palet terang di atas, sama seperti darkBg/darkCard
   di app_colors.dart Flutter. */
#screenCapture { background: var(--bg); min-height: 100vh; }
#capShoot { background: var(--dark); min-height: 100vh; color: #fff; }
#capShoot .pad { padding: calc(env(safe-area-inset-top) + 12px) 14px calc(env(safe-area-inset-bottom) + 24px); max-width: 640px; }
.dots { display: flex; gap: 5px; margin-bottom: 10px; }
.dots div { flex: 1; height: 5px; border-radius: 3px; background: #3A3E41; }
.dots div.done { background: var(--success); } .dots div.now { background: var(--primary); }
/* "menunggu terkirim" — antrean offline, BUKAN tersimpan sungguhan, jadi
   warna beda dari .done (sukses server) — lihat catatan capture-flow.js. */
.dots div.pending { background: var(--warning); }
.strip { display: flex; gap: 5px; margin-bottom: 12px; }
.strip div { flex: 1; aspect-ratio: 3/4; border-radius: 8px; background: var(--dark2); overflow: hidden; position: relative; border: 1px solid #3A3E41; }
.strip img { width: 100%; height: 100%; object-fit: cover; }
.strip span { position: absolute; bottom: 1px; left: 0; right: 0; text-align: center; font-size: 9px; color: #9BA3A7; }
.strip .pendingDot { position: absolute; top: 3px; right: 3px; color: var(--warning); background: rgba(0,0,0,.55);
  border-radius: 50%; width: 16px; height: 16px; display: flex; align-items: center; justify-content: center; }
.segs { display: flex; background: var(--dark2); border-radius: 12px; padding: 4px; margin-bottom: 12px; }
.segs button { flex: 1; background: none; border: none; color: #9BA3A7; font: inherit; font-weight: 700; font-size: 13px; padding: 11px 6px; border-radius: 9px; cursor: pointer; line-height: 1.25; }
.segs button.on { background: var(--primary); color: #fff; }
.checks { background: var(--dark2); border-radius: 14px; padding: 12px 14px; margin-bottom: 12px; }
.checks .r { display: flex; align-items: center; gap: 10px; padding: 4px 0; font-size: 15px; }
.checks .r i { width: 20px; height: 20px; border-radius: 50%; flex: 0 0 auto; display: flex; align-items: center; justify-content: center; font-size: 12px; font-style: normal; border: 2px solid #5A6165; color: transparent; }
.checks .r.p i { background: var(--success); border-color: var(--success); color: #fff; }
.checks .r.f { color: #C9CFD2; }
.checks .r em { margin-left: auto; font-style: normal; color: #8A9296; font-size: 13px; font-variant-numeric: tabular-nums; }
.checks .r.p em { color: #A9D19A; }
.frameLbl { background: #000; color: #fff; font-size: 14px; font-weight: 700; text-align: center; padding: 8px; border-radius: 11px 11px 0 0; }
.frame { border: 3px solid #fff; border-radius: 15px; overflow: hidden; position: relative; aspect-ratio: 3/4; background: #0E0E10; display: flex; align-items: center; justify-content: center; }
.frame video, .frame img.shot { width: 100%; height: 100%; object-fit: cover; display: block; }
.frame .gh { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; pointer-events: none; mix-blend-mode: screen; }
.frame canvas.overlay { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.frame .tag { position: absolute; top: 10px; left: 10px; background: rgba(0,0,0,.62); padding: 6px 12px; border-radius: 18px; font-weight: 800; font-size: 12.5px; letter-spacing: .8px; }
.verdict { text-align: center; padding: 13px; border-radius: 13px; font-weight: 800; margin: 12px 0; font-size: 16px; line-height: 1.3; }
.verdict.go { background: #1B7D50; color: #EAFFF4; }
.verdict.no { background: var(--dark2); color: #E3B675; }
.shutter { display: flex; align-items: center; justify-content: center; gap: 32px; margin-top: 4px; }
.shutter .sm { background: none; border: none; color: #fff; font-size: 25px; cursor: pointer; padding: 8px; }
.shutter .big { width: 76px; height: 76px; border-radius: 50%; background: var(--primary); border: 4px solid #fff; cursor: pointer; font-size: 28px; color: #fff; }
.shutter .big:disabled { background: #4A4E51; border-color: #6C7275; }
.dbg { background: #101113; border: 1px solid #33373a; border-radius: 12px; padding: 10px 13px; margin-bottom: 12px; font-size: 12.5px; color: #9BA3A7; font-variant-numeric: tabular-nums; }
.dbg b { color: #e9eaee; font-weight: 600; }

.slot { display: flex; align-items: center; gap: 12px; background: var(--dark2); border-radius: 13px; padding: 11px; margin-bottom: 9px; }
.slot .pv { width: 56px; height: 75px; border-radius: 9px; background: #101113; overflow: hidden; flex: 0 0 auto; display: flex; align-items: center; justify-content: center; font-size: 11px; color: #6B7276; text-align: center; }
.slot .pv img { width: 100%; height: 100%; object-fit: cover; }
.slot .tx { flex: 1; min-width: 0; }
.slot .tx b { display: block; font-size: 15px; }
.slot .tx span { font-size: 12.5px; color: #9BA3A7; display: block; line-height: 1.4; }
.slot .tx span.ok { color: #7FD3A8; } .slot .tx span.bad { color: #E3B675; }
.slot .pick { background: var(--primary); color: #fff; border: none; border-radius: 9px; padding: 9px 13px; font: inherit; font-size: 13.5px; font-weight: 700; cursor: pointer; }
.slot.dragover { outline: 2px dashed var(--primary); outline-offset: 2px; }
.slot .pv[draggable="true"] { cursor: grab; }

.mutedLabel { font-size: 12px; font-weight: 700; color: #9BA3A7; text-transform: uppercase; letter-spacing: .4px; margin: 4px 0 8px; }

.rotBtns { display: flex; gap: 4px; margin-top: 4px; }
.rotBtn { background: rgba(255,255,255,.08); border: none; border-radius: 7px; color: #C9CFD2; width: 26px; height: 26px;
  font-size: 16px; line-height: 1; display: flex; align-items: center; justify-content: center; cursor: pointer; }
.rotBtn:hover { background: rgba(255,255,255,.16); }

/* Baki foto galeri yang belum tertempat ke slot manapun — lihat
   gambarBelumTertempat() di capture-flow.js. */
#kandidatBelumTertempat { background: var(--dark2); border-radius: 13px; padding: 11px; margin-bottom: 12px; }
.trayRow { display: flex; gap: 10px; overflow-x: auto; padding-bottom: 2px; }
.trayItem { flex: 0 0 auto; width: 64px; text-align: center; cursor: grab; }
.trayItem img { width: 64px; height: 84px; border-radius: 9px; object-fit: cover; display: block; background: #101113; }
.trayItem span { font-size: 11px; color: #9BA3A7; display: block; margin-top: 3px; }
.trayItem .rotBtns { justify-content: center; }

/* ---------- riwayat & grid sesi (tab Foto, Bandingkan) ---------- */
.riwayat-hdr { font-size: 12px; font-weight: 700; color: var(--muted); text-transform: uppercase;
  letter-spacing: .5px; margin: 18px 0 8px; }
.riwayat-hdr:first-child { margin-top: 0; }
.tag { display: inline-block; font-size: 11px; font-weight: 700; padding: 4px 10px; border-radius: 999px; }

.grid6 { display: flex; flex-direction: column; gap: 14px; }
/* Satu baris tata letak (lihat MONTASE_LAYOUT) — biasanya 2 sel
   berdampingan (L45/R45, L90/R90), tapi baris F cuma 1 sel. justify-
   content:center + basis 50% tetap supaya sel F TIDAK melebar penuh
   (dulu jadi pita horizontal krn object-fit:cover di kotak yang terlalu
   lebar) — lebarnya dipatok SAMA dengan sel di baris berpasangan,
   dirata-tengah dgn ruang kosong kiri-kanan. flex-wrap krn baris "Sisi
   Lama" bisa berisi >2 sel sekaligus. */
.gRow { display: flex; flex-wrap: wrap; justify-content: center; gap: 14px; }
.gRow > div { flex: 0 0 calc(50% - 7px); max-width: calc(50% - 7px); }
.growLbl { font-size: 12px; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: .4px; margin-bottom: 6px;
  display: flex; align-items: center; gap: 8px; }
/* Tombol jelas utk buka penggeser before/after layar penuh — label teks
   sendiri gampang terlewat (bukan kelihatan seperti tombol), jadi ini
   pemicu UTAMA, label tetap bisa diklik sbg jalan kedua. */
.growSliderBtn { margin-left: auto; width: 24px; height: 24px; border-radius: 7px; border: none; background: var(--dark2);
  color: #fff; display: flex; align-items: center; justify-content: center; cursor: pointer; padding: 0; flex: none; }
.growSliderBtn:hover { background: rgba(255,255,255,.18); }
.growImgs { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.gcell { position: relative; aspect-ratio: 3/4; background: var(--dark2); border-radius: 12px; overflow: hidden;
  display: flex; align-items: center; justify-content: center; cursor: pointer; }
.gcell img { width: 100%; height: 100%; object-fit: cover; display: block; }
.gcell .empty { color: #8A9296; font-size: 12px; }
.gBadge { position: absolute; top: 6px; right: 6px; font-size: 12px; line-height: 1; background: rgba(0,0,0,.65);
  border-radius: 8px; padding: 4px 6px; z-index: 2; }
.gBadge.warn { color: var(--warning); } .gBadge.ok { color: #9fe0bd; }
/* Badge ⚠ = TOMBOL (bukan cuma tanda) — ditekan langsung membuka mode
   Atur untuk foto itu, supaya staff tidak perlu menebak foto mana yang
   deteksinya gagal. Badge "manual" tetap penanda pasif. */
button.gBadge { font: inherit; font-size: 12px; border: none; cursor: pointer; display: inline-flex;
  align-items: center; gap: 3px; }
button.gBadge:hover, button.gBadge:focus-visible { background: rgba(0,0,0,.88); outline: 1px solid var(--warning); }
/* Sel yang ditunjuk dari badge saat penggeser tidak bisa dibuka (pasangan
   sesi tidak lengkap) — berkedip sekali supaya jelas mana yang dimaksud. */
@keyframes tuneSorot { 0%, 100% { box-shadow: none; } 40% { box-shadow: 0 0 0 3px var(--warning); } }
.gcell.sorot { animation: tuneSorot 1.1s ease-in-out 2; }
.gTune { position: absolute; bottom: 6px; right: 6px; font-size: 13px; background: rgba(0,0,0,.65); color: #fff;
  border: none; border-radius: 8px; padding: 5px 9px; cursor: pointer; z-index: 2; }
.gTune:hover { background: rgba(0,0,0,.85); }

/* ---------- koreksi posisi inline, LANGSUNG di sel grid (inline-tune.js)
   — ganti alur lama "ketuk ikon kunci pas → modal layar penuh" (masih
   dipakai viewer.html/.gTune di atas, TIDAK disentuh). Gaya Canva: TIDAK
   ada "mode" — sel SELALU bisa digeser/dicubit (.gcellTune, touch-action
   dimatikan lewat gesture.js sendiri), garis bantu SELALU tampil
   (.tuneGarisWrap), cuma SATU tombol selalu-ada (.tuneReset) — tidak ada
   Simpan/Batal, tersimpan sendiri lewat debounce di JS. */
.gcell .tuneImgAktif { user-select: none; }
.tuneGarisWrap { position: absolute; inset: 0; pointer-events: none; z-index: 4; }
.tuneGaris { position: absolute; left: 0; right: 0; height: 0; border-top: 1.5px dashed rgba(255,255,255,.9); }
.tuneGaris span { position: absolute; left: 4px; top: 2px; font-size: 8.5px; font-weight: 700; color: rgba(255,255,255,.9);
  background: rgba(0,0,0,.55); padding: 1px 5px; border-radius: 4px; text-transform: uppercase; letter-spacing: .3px; }

/* Garis bantu yang BISA DISERET (cuma mode "Atur Sebelum/Sesudah", lihat
   siapkanAturSlider) — garisnya sendiri tetap setipis semula, yang
   menangkap jari adalah pita transparan .tuneGrab setinggi 26px di
   sekelilingnya (garis 0px mustahil disentuh di HP), dengan gagang putih
   kecil di tepi kanan sbg petunjuk visual bahwa ini bisa ditarik. */
.tuneGarisWrap.seret .tuneGaris { border-top-style: solid; border-top-color: var(--accent, #4FC3A1); }
.tuneGrab { position: absolute; left: 0; right: 0; top: -13px; height: 26px; pointer-events: auto;
  cursor: ns-resize; touch-action: none; }
.tuneGrab:after { content: ""; position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  width: 30px; height: 13px; border-radius: 7px; background: rgba(255,255,255,.92);
  box-shadow: 0 1px 4px rgba(0,0,0,.55); }
/* Nilai zoom sbg ANGKA — tidak boleh menangkap jari, sel di bawahnya harus
   tetap bisa digeser lewat titik ini. */
.tuneZoom { position: absolute; bottom: 6px; left: 6px; font-size: 10px; font-weight: 700; letter-spacing: .2px;
  color: rgba(255,255,255,.92); background: rgba(0,0,0,.6); padding: 2px 6px; border-radius: 6px;
  pointer-events: none; z-index: 6; }
.tuneReset, .tuneSamakan { position: absolute; bottom: 5px; width: 25px; height: 25px; border-radius: 7px; border: none;
  background: rgba(0,0,0,.6); color: #fff; display: flex; align-items: center; justify-content: center; cursor: pointer;
  padding: 0; z-index: 7; }
.tuneReset { right: 5px; }
.tuneSamakan { right: 34px; }
.tuneReset:hover, .tuneSamakan:hover { background: rgba(0,0,0,.85); }
.tuneErr { position: absolute; top: 5px; left: 5px; right: 5px; background: var(--danger-bg); color: var(--danger);
  font-size: 10px; padding: 4px 6px; border-radius: 6px; z-index: 7; line-height: 1.3; }

.cmp { position: relative; width: 100%; aspect-ratio: 3/4; background: #000; border-radius: 14px; overflow: hidden;
  user-select: none; touch-action: none; }
.cmp img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.cmp .after { clip-path: inset(0 0 0 50%); }
.cmp .handle { position: absolute; top: 0; bottom: 0; width: 2px; background: #fff; left: 50%; box-shadow: 0 0 12px rgba(0,0,0,.7); }
.cmp .handle:after { content: "compare"; font-family: 'Material Symbols Rounded'; -webkit-font-feature-settings: 'liga'; font-feature-settings: 'liga';
  position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%);
  background: #fff; color: #111; width: 36px; height: 36px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 19px; }
.cmp .lbl { position: absolute; top: 10px; background: rgba(0,0,0,.65); padding: 5px 12px; border-radius: 18px; font-size: 12px; font-weight: 600; color: #fff; }
.cmp .lbl.l { left: 10px; } .cmp .lbl.r { right: 10px; }

/* Chip "Atur Sebelum/Sesudah" di atas penggeser (.cmp) — begitu salah
   satu aktif, geser/cubit di dalam .cmp mengatur POSISI foto itu (lewat
   siapkanAturSlider/pasangGesturLangsung), dan penggeser pembanding
   sendiri dimatikan sementara (lihat sedangAturFoto di tabs-pasien.js)
   supaya dua gestur satu-jari itu tidak tabrakan. */
.cmpAturChips { display: flex; flex-direction: column; gap: 8px; margin-bottom: 8px; }
.cmpAturRow { display: flex; gap: 8px; }
.cmpAturChips button { flex: 1; display: flex; align-items: center; justify-content: center; gap: 6px; font-size: 12px;
  font-weight: 600; padding: 7px 10px; border-radius: 10px; border: 1px solid var(--border); background: var(--dark2);
  color: #fff; cursor: pointer; }
.cmpAturChips button.on { background: var(--accent); border-color: var(--accent); color: #fff; }
/* Bar bawah (muncul HANYA selagi salah satu foto sedang diatur).
   Baris 1: angka zoom + STATUS SIMPAN + tombol Simpan.
   Baris 2: kunci skala dari garis panduan + batal koreksi.
   Status simpan sengaja BERUPA TEKS, bukan cuma warna — staff harus bisa
   memastikan kalibrasinya masuk tanpa menutup & membuka panel lagi. */
.cmpAturBar, .cmpAturBar2 { display: flex; gap: 8px; align-items: center; }
.cmpAturBar2 button { flex: 1; font-size: 11.5px; padding: 7px 8px; }
.cmpSimpanStatus { flex: 1; font-size: 11.5px; font-weight: 700; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
.cmpSimpanStatus[data-st="bersih"] { color: #9fe0bd; }
.cmpSimpanStatus[data-st="kotor"] { color: var(--warning); }
.cmpSimpanStatus[data-st="menyimpan"] { color: var(--muted); }
.cmpAturBar button[data-aksi="simpan"] { flex: 0 0 auto; font-size: 12px; padding: 8px 16px; }
.cmpAturChips button.utama { background: var(--accent); border-color: var(--accent); }
.cmpAturChips button.utama:disabled { background: var(--dark2); border-color: var(--border);
  color: var(--muted); cursor: default; }
.cmpZoom { flex: 0 0 auto; font-size: 12px; font-weight: 800; color: #fff; background: var(--dark2);
  border: 1px solid var(--border); border-radius: 10px; padding: 7px 10px; min-width: 54px; text-align: center; }
.cmpAturHint { margin: 0; font-size: 11px; line-height: 1.45; color: var(--muted); }
.cmpAturHint b { color: #fff; }
/* Pesan singkat "Tersimpan"/"Gagal menyimpan" (toast.js) — mengambang di
   atas bilah navigasi bawah, tidak pernah menangkap ketukan. */
.toast { position: fixed; left: 50%; bottom: calc(76px + env(safe-area-inset-bottom, 0px));
  transform: translate(-50%, 12px); z-index: 200; pointer-events: none;
  background: rgba(20,21,23,.95); color: #fff; font-size: 13px; font-weight: 600;
  padding: 10px 18px; border-radius: 22px; box-shadow: 0 6px 20px rgba(0,0,0,.45);
  border: 1px solid var(--border); opacity: 0; transition: opacity .18s ease, transform .18s ease;
  max-width: calc(100vw - 32px); text-align: center; }
.toast.tampil { opacity: 1; transform: translate(-50%, 0); }
.toast.ok { border-color: #2f6b53; }
.toast.gagal { border-color: var(--danger); color: #ffd9d9; }
@media (prefers-reduced-motion: reduce) { .toast { transition: none; } }

.sbs { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.sbs figure { margin: 0; } .sbs img { width: 100%; border-radius: 12px; display: block; background: #000; }
.sbs figcaption { font-size: 11.5px; color: var(--muted); padding: 6px 2px; }

/* ---------- modal (koreksi manual, penampil foto) — gelap, sama seperti
   layar kamera/pratinjau, lihat catatan darkBg/darkCard di app_colors.dart ---------- */
.modal-ov { position: fixed; inset: 0; background: rgba(27,28,30,.82); z-index: 80;
  display: flex; align-items: center; justify-content: center; padding: 18px; }
.modal-box { background: var(--dark2); border-radius: 16px; padding: 16px; max-width: 480px; width: 100%;
  max-height: 92vh; overflow: auto; color: #fff; }
.modal-hd { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; gap: 10px; }
.modal-hd b { font-size: 15px; }
.modal-hd button { background: none; border: none; color: #C9CFD2; font: inherit; font-size: 14px; cursor: pointer; padding: 4px; }

.tuneStage { position: relative; width: 100%; aspect-ratio: 3/4; background: #000; border-radius: 12px;
  overflow: hidden; cursor: grab; }
.tuneStage:active { cursor: grabbing; }
.tuneStage img { position: absolute; top: 50%; left: 50%; max-width: none; user-select: none; pointer-events: none; }
.tuneStage .guide { position: absolute; left: 0; right: 0; pointer-events: none; }
.tuneStage .guide .ln { height: 1.5px; background: rgba(255,255,255,.85); }
.tuneStage .guide .lb { margin: 3px 0 0 6px; display: inline-block; background: rgba(0,0,0,.55); color: rgba(255,255,255,.7);
  font-size: 10px; font-weight: 600; padding: 2px 6px; border-radius: 4px; }
/* Spanduk "koreksi masih memakai render lama" (v:1) di layar Konteks.
   Sengaja TENANG, bukan merah menyala: gambarnya tetap tampil dan masih
   berguna — yang ditawarkan cuma perbaikan sekali klik, bukan peringatan
   bahaya. Lihat koreksiLawas()/perbaruiKoreksiKeV2() di komplain.js. */
.kkLawas { display: flex; align-items: center; justify-content: center; gap: 10px; flex-wrap: wrap;
  margin-top: 8px; padding: 8px 10px; border-radius: 10px; font-size: 11.5px; line-height: 1.45;
  color: var(--muted); background: color-mix(in srgb, var(--warning) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--warning) 28%, transparent); }
.kkLawas span { flex: 1 1 200px; text-align: left; }
.kkLawas button { flex: 0 0 auto; padding: 6px 12px; font: inherit; font-weight: 600; cursor: pointer;
  color: #fff; background: var(--dark); border: 1px solid #3A3E41; border-radius: 8px; }
.kkLawas button:disabled { opacity: .6; cursor: default; }

.tuneCtrl { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.tuneCtrl button { flex: 1; min-width: 90px; padding: 9px; background: var(--dark); color: #fff; border: 1px solid #3A3E41;
  border-radius: 10px; font: inherit; font-size: 13.5px; font-weight: 600; cursor: pointer; }

/* ---------- Detail Pasien: garis waktu gabungan (sesi + LAPORAN KELUHAN) ----------
   Keluhan TIDAK boleh terbaca seperti sesi foto klinik biasa — beda warna
   tepi, tag mencolok, dan (di dalam) label peringatan di tiap foto. */
.item.komplain { border-left: 4px solid var(--warning);
  background: color-mix(in srgb, var(--warning) 7%, var(--surface)); }
.komplainTag { display: inline-flex; align-items: center; gap: 4px; font-size: 10.5px; font-weight: 800;
  letter-spacing: .3px; text-transform: uppercase; color: #7A5510; background: var(--warning-bg);
  padding: 3px 9px; border-radius: 999px; margin-left: 8px; white-space: nowrap; }
.statusPill { display: inline-flex; align-items: center; font-size: 11.5px; font-weight: 700;
  padding: 4px 10px; border-radius: 999px; flex: 0 0 auto; }

.komplainDetail .catatan { font-size: 15px; line-height: 1.5; color: var(--ink); white-space: pre-wrap; }
.komplainGrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin: 12px 0; }
.komplainCell { display: flex; flex-direction: column; gap: 4px; }
.komplainThumb { position: relative; aspect-ratio: 3/4; border-radius: 10px; overflow: hidden;
  background: var(--dark2); cursor: pointer; }
.komplainThumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.komplainThumb .rm { position: absolute; top: 4px; right: 4px; background: rgba(0,0,0,.65); color: #fff;
  border: none; border-radius: 7px; width: 22px; height: 22px; display: flex; align-items: center;
  justify-content: center; cursor: pointer; z-index: 2; }
.komplainThumb .sisiBtn { position: absolute; bottom: 4px; left: 4px; background: rgba(0,0,0,.65); color: #fff;
  border: none; border-radius: 7px; width: 22px; height: 22px; display: flex; align-items: center;
  justify-content: center; cursor: pointer; z-index: 2; }
/* Label sisi di bawah tiap thumbnail — supaya terlihat mana yang sudah
   diberi label dan mana yang belum tanpa harus membuka fotonya. */
.komplainSisiCaption { font-size: 10.5px; color: var(--muted); text-align: center; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }

/* Label mencolok dalam modal penampil — "Foto dari pasien, pencahayaan dan
   sudut tidak terkontrol" — supaya tidak pernah dibaca seperti foto klinik. */
.komplainWarn { background: var(--warning); color: #2B1E00; font-size: 12px; font-weight: 700;
  line-height: 1.4; padding: 8px 10px; border-radius: 10px; margin-bottom: 10px; text-align: center; }

/* Konteks berdampingan (keluhan vs sesi klinik terakhir) — TIDAK BOLEH
   penggeser before/after seperti Bandingkan, itu menyiratkan kesetaraan
   yang tidak ada (lihat sbs di atas untuk versi klinik). */
.komplainSbs { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.komplainSbs figure { margin: 0; } .komplainSbs img { width: 100%; border-radius: 12px; display: block; background: #000; }
.komplainSbs figcaption { font-size: 11px; color: var(--muted); padding: 6px 2px; text-align: center; }
.tuneCtrl button.primary { background: var(--primary); border-color: var(--primary); }

/* ══════════════════════════════════════════════════════════════════════
   TATA LETAK LEBAR — tablet (768–1199px) & laptop/desktop (≥1200px).
   Di bawah 768px TIDAK ADA aturan apa pun di sini yang berlaku — tampilan
   HP (staff, dipakai sehari-hari) sama persis dengan sebelumnya.

   Semua lewat media query di atas markup/JS yang SAMA — TIDAK ADA elemen
   baru untuk sidebar (nav.tabbar yang sama, cuma diposisikan ulang lewat
   CSS: karena hanya SATU .tabpanel yang tidak .hide dalam satu waktu,
   begitu #shell jadi flex row, tabpanel yang aktif otomatis jadi SATU-
   SATUNYA "isi" di sebelah .tabbar, tidak perlu wrapper tambahan).

   Pengecualian: Detail Pasien (tabs-pasien.js#bukaDetail) BUTUH 2 kolom
   yang temanya beda (data+aksi vs riwayat) dari elemen-elemen yang
   sebelumnya cuma tumpukan flat — itu TIDAK bisa dipisah lewat CSS murni
   tanpa penanda apa pun, jadi ditambahkan 2 <div class="pdCol"> pembungkus
   (lihat komentar di tabs-pasien.js). display:contents di bawah 768px
   membuat pembungkus itu "menghilang" dari pohon kotak — HTML yang
   dirender tampilan HP identik dengan sebelum pembungkus ini ada.
   ══════════════════════════════════════════════════════════════════════ */
/* Aturan dasar (BUKAN di dalam media query) — pembungkus 2-kolom Detail
   Pasien "menghilang" dari pohon kotak secara default, dioverride jadi
   kolom sungguhan HANYA di ≥768px di bawah. Jadi mobile TIDAK PERNAH
   melihat efek apa pun dari pembungkus ini, di breakpoint mana pun. */
.pdGrid, .pdCol { display: contents; }

@media (min-width: 768px) {
  #shell { display: flex; align-items: stretch; min-height: 100vh; }
  .tabpanel { flex: 1 1 auto; min-width: 0; }

  /* nav.tabbar: dari bar bawah (row, flex:1 rata per tombol) jadi sidebar
     kiri tetap (column, lebar tetap ~220px, ikon+label sejajar per baris
     seperti nav sidebar pada umumnya, bukan ikon-di-atas-label ala tab HP). */
  .tabbar {
    order: -1;
    position: sticky; top: 0; left: auto; right: auto; bottom: auto;
    flex: 0 0 220px; width: 220px; height: 100vh;
    flex-direction: column; align-items: stretch; justify-content: flex-start;
    gap: 3px;
    padding: calc(env(safe-area-inset-top) + 22px) 12px 16px;
    border-top: none; border-right: 1px solid var(--border);
    box-shadow: none;
  }
  .tabbar button {
    flex: 0 0 auto; flex-direction: row; justify-content: flex-start;
    gap: 13px; padding: 11px 13px; border-radius: 11px; font-size: 14.5px;
  }
  .tabbar button .ic { font-size: 22px; }
  .tabbar button.on { background: var(--accent); }

  /* Lebar isi dibatasi & di tengah SISA ruang setelah sidebar — bukan
     ditarik sampai tepi layar (mis. maksimum 1100px). */
  .pad, .brand { max-width: 1100px; padding-left: 30px; padding-right: 30px; }
  /* 96px bawah tadinya jarak aman dari tab bar bawah yang fixed — sidebar
     tidak menutupi bagian bawah layar lagi, tidak perlu ruang sebesar itu. */
  .pad { padding-bottom: 40px; }
  .topbar { padding-left: 30px; padding-right: 30px; }

  /* Daftar Pasien & riwayat sesi (tab Foto) — grid 2 kolom alih-alih satu
     kolom memanjang; kartu .item yang sama, cuma wadahnya beda. */
  #plist, #rlist { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; align-content: start; }
  #plist .item, #rlist .item { margin-bottom: 0; }

  /* Detail Pasien 2 kolom — lihat komentar besar di atas & tabs-pasien.js. */
  .pdGrid { display: grid; grid-template-columns: minmax(260px, 1fr) minmax(320px, 1.4fr); gap: 28px; align-items: start; }
  .pdCol { display: block; min-width: 0; }
}

@media (min-width: 1200px) {
  /* Tablet (768–1199) tetap 2 kolom drpd 3 — di lebar itu 3 kolom kartu
     pasien jadi sempit & padat. 3 kolom baru masuk akal mulai desktop. */
  #plist, #rlist { grid-template-columns: repeat(3, 1fr); }

  /* Layar PALING penting untuk dokter memeriksa foto — grid 5 sisi
     (Detail Sesi, tab Foto) & Bandingkan sengaja TIDAK dipatok 1100px
     yang sama seperti layar isi umum di atas: sel .gcell/.cmp/.sbs skalanya
     relatif (%, aspect-ratio) terhadap .pad, jadi wadah lebih lebar disini
     otomatis berarti foto ditampilkan lebih besar, bukan cuma dikelilingi
     ruang kosong ekstra. */
  #fotoSesiDetail .pad, #pasienCompare .pad { max-width: 1500px; }
}


/* ===========================================================
   KOMPARASI BEBAS (js/komparasi-bebas.js)
   Layar kerja di tab Beranda. Memakai variabel palet yang SUDAH ada
   (--border/--surface/--ink/--muted/--primary/--danger/--warning)
   supaya ikut tema terang aplikasi, bukan palet kedua.
   =========================================================== */
#kbebasSub { margin: -4px 0 16px; font-size: 13px; color: var(--muted); }

.kbBlok {
  border: 1px solid var(--border); border-radius: 12px;
  padding: 12px; margin-bottom: 14px; background: var(--surface);
}
.kbBlokHead { display: flex; align-items: baseline; gap: 8px; margin-bottom: 10px; }
.kbBlokHead h3 { margin: 0; font-size: 15px; color: var(--ink); }
.kbHitung { font-size: 12px; color: var(--muted); margin-left: auto; }

/* Daftar VERTIKAL, bukan kisi: urutan menentukan posisi di hasil render,
   dan urutan atas-ke-bawah jauh lebih jelas dibaca daripada kisi yang
   mengalir. Tombol panah bekerja pada urutan yang sama. */
.kbList { display: flex; flex-direction: column; gap: 8px; }
.kbItem {
  display: flex; align-items: stretch; gap: 10px;
  border: 1px solid var(--border); border-radius: 10px; overflow: hidden;
}
/* Latar abu saat src belum terisi: thumbnail dimuat asinkron lewat blobUrl
   (butuh header auth), jadi <img> sempat tanpa src beberapa ratus milidetik.
   Tanpa latar, yang terlihat staf adalah kotak kosong berkedip. */
.kbThumb {
  width: 66px; aspect-ratio: 3 / 4; object-fit: cover; display: block;
  flex: none; background: var(--border);
}
.kbItemBar { display: flex; align-items: center; gap: 8px; padding: 6px 8px 6px 0; flex: 1; }
.kbNo {
  min-width: 22px; height: 22px; border-radius: 999px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--primary); color: #fff; font-size: 12px; font-weight: 600;
}
.kbSisi { font-size: 12px; color: var(--muted); margin-right: auto; }
.kbIcn {
  width: auto; min-width: 30px; padding: 5px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--bg); color: var(--ink);
  /* line-height 1 (bukan 0): dua tombol urutan berisi karakter panah teks,
     bukan glyph ikon, jadi barisnya harus punya tinggi. */
  font-size: 15px; line-height: 1;
}
.kbIcn[disabled] { opacity: .35; }
.kbIcn.danger { color: var(--danger); }

.kbKosong { margin: 0; font-size: 12.5px; color: var(--muted); line-height: 1.5; }

.kbUnggahBar { display: flex; align-items: center; gap: 8px; margin-top: 10px; }
.kbSisiPilih { width: auto; margin: 0; padding: 8px 8px; font-size: 13px; flex: none; }
.kbUnggahBar .btn { width: auto; flex: 1; padding: 10px 12px; }

.kbItemAtas { display: flex; align-items: stretch; gap: 10px; }
.kbItem.buka { border-color: var(--primary); }

/* Panel setel posisi. Tombol saja, TIDAK ada gesture cubit — staf melaporkan
   pinch di layar koreksi yang ada tidak jalan, jadi jalur yang pasti bekerja
   yang dipakai di sini, bukan mewarisi mekanisme yang sedang dikeluhkan. */
.kbAtur {
  border-top: 1px dashed var(--border); margin-top: 8px; padding: 9px 8px 4px;
}
.kbAturGrid { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.kbAturKolom { display: inline-flex; flex-direction: column; gap: 4px; }
.kbAturSela { flex: 1; }
.kbAturInfo {
  display: block; margin-top: 7px; font-size: 11.5px;
  color: var(--muted); font-variant-numeric: tabular-nums;
}
.kbIcn.on { border-color: var(--primary); color: var(--primary); }

.kbPreview {
  display: block; width: 100%; height: auto; border-radius: 10px;
  border: 1px solid var(--border); margin: 4px 0 2px;
}

.kbHasil {
  margin-top: 14px; padding: 12px; border-radius: 12px;
  border: 1px solid var(--border); background: var(--surface);
  font-size: 13px; color: var(--ink);
}
.kbHasil code { word-break: break-all; }
.kbHasil .btn { width: auto; margin-top: 10px; padding: 9px 16px; }
.kbWarn {
  display: flex; align-items: center; gap: 6px; margin: 8px 0 0;
  color: var(--warning); background: var(--warning-bg);
  padding: 7px 9px; border-radius: 8px; line-height: 1.4;
}

/* ---------- penanda status jaringan (penanda-jaringan.js) ----------
   Satu penanda kecil & tetap: tersambung / offline / berapa foto menunggu
   terkirim. position:fixed dan pointer-events:none SENGAJA — penanda ini
   ditempel ke <body> dan TIDAK BOLEH menggeser satu piksel pun tata letak
   yang sudah ada, tidak boleh mencuri ketukan, dan tidak boleh menutupi
   dialog. Gaya pilnya sama bahasa dengan .toast supaya terbaca di layar
   terang (Beranda/Pasien) MAUPUN di layar gelap (motret/koreksi). */
.penanda-jaringan {
  position: fixed; z-index: 25; pointer-events: none; -webkit-user-select: none; user-select: none;
  top: calc(env(safe-area-inset-top, 0px) + 8px); right: 10px;
  display: flex; align-items: center; gap: 4px;
  background: rgba(20, 21, 23, .82); color: #E6EAEC;
  font-size: 11px; font-weight: 700; line-height: 1;
  padding: 5px 9px; border-radius: 20px;
  border: 1px solid rgba(255, 255, 255, .14);
}
.penanda-jaringan.ok { border-color: #2f6b53; }
.penanda-jaringan.luring { border-color: var(--warning); color: #F0DCBC; }
.penanda-jaringan.antre { border-color: var(--warning); background: rgba(20, 21, 23, .9); color: #FFE0B2; }
/* Di layar motret, sudut kanan ATAS dipakai bar kemajuan enam sisi (.dots) —
   penanda pindah ke bawah supaya tidak menutupinya. Pakai selektor sibling,
   bukan kelas dari JS: alur motret tidak boleh disentuh sama sekali. */
#screenCapture:not(.hide) ~ .penanda-jaringan {
  top: auto; bottom: calc(env(safe-area-inset-bottom, 0px) + 10px); right: 10px;
}
