:root {
  --app-max: 1360px;
  --sidebar-width: 240px;
  --header-height: 72px;
  --type-title: clamp(26px, 3.2vw, 36px);
  --type-section: 20px;
  --type-body: 15px;
  /* Wash lama hanya tersisa untuk permukaan publik (drawer galeri, galat masuk);
     layar login memakai triad --tag-* dari tags.css. */
  --green-wash: rgba(16, 185, 129, 0.12);
  --red-wash: rgba(245, 54, 94, 0.10);
  --ease-spring: ease-out;
  --ease-smooth: cubic-bezier(0.4, 0, 0.2, 1);
}

*, *::before, *::after {
  box-sizing: border-box;
}

body {
  min-height: 100dvh;
  margin: 0;
  background: var(--bg-app);
  color: var(--text-body);
  font-family: var(--font-body, system-ui, -apple-system, sans-serif);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Accessible skip link */
.skip-link {
  position: fixed;
  left: 16px;
  top: -100px;
  z-index: 100;
  padding: 12px 18px;
  background: var(--bg-ink);
  color: var(--text-on-dark);
  border-radius: var(--radius-xs);
  font-weight: 600;
  text-decoration: none;
  box-shadow: var(--shadow-modal);
  transition: top 0.2s ease;
}
.skip-link:focus {
  top: 16px;
}
/* Tersembunyi di atas layar, bayangannya tetap terlihat sebagai noda abu di
   tepi atas halaman tamu. Bayangan hanya perlu saat tautan ini tampil. */
.skip-link:not(:focus) {
  box-shadow: none;
}

/* App Main Layout */
.page-main {
  min-height: 100dvh;
  margin-left: var(--sidebar-width);
  padding: var(--space-9) clamp(var(--space-6), 4vw, 56px) var(--space-12);
}
.page-main--public {
  min-height: calc(100dvh - var(--header-height));
  margin-left: 0;
  padding: 0;
}
.page-main > * {
  max-width: var(--app-max);
  margin-inline: auto;
}

/* Public Topbar */
.public-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: var(--header-height);
  padding: 0 clamp(20px, 4vw, 56px);
  background: var(--surface-0);
  border-bottom: 1px solid var(--border-default);
  position: sticky;
  top: 0;
  z-index: 30;
}
.public-topbar > * {
  max-width: var(--app-max);
}

/* Wordmark & Brand Elements */
.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-display, var(--font-body));
  font-weight: 800;
  font-size: 17px;
  letter-spacing: -0.02em;
  color: var(--text-strong);
  text-decoration: none;
  transition: opacity 0.18s ease;
}
.wordmark:hover {
  opacity: 0.88;
}
.wordmark-mark {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  background: var(--vs-yellow);
  color: var(--vs-black);
  font-size: 15px;
  font-weight: 900;
  border-radius: 0;
  box-shadow: none;
  overflow: hidden;
}
.wordmark-mark img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}
/* Tautan beranda: lockup-nya 29px, jadi kotak sentuhnya dinaikkan ke ambang
   44px. Margin atas dipangkas agar jarak ke kicker tetap seperti semula. */
.wordmark--sidebar {
  color: var(--text-strong);
  min-height: var(--field-h);
  margin: var(--space-0) var(--space-5) var(--space-7);
}
.wordmark--sidebar .wordmark-mark {
  background: var(--vs-yellow);
}
.wordmark-name {
  display: grid;
  line-height: 1.05;
}
.wordmark-by {
  font: 600 8.5px/1.3 var(--font-body);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  /* 8.5px butuh kontras teks penuh; --text-subtle hanya 4.14:1 di kanvas putih. */
  color: var(--text-muted);
}
.wordmark--sidebar .wordmark-by {
  color: var(--text-muted);
}
.wordmark-logo {
  display: block;
  height: 32px;
  width: auto;
  max-width: 190px;
  object-fit: contain;
}

/* App Sidebar (Platform Console & Workspace) */
/* Sidebar putih (keputusan owner 22 Sep 2026). Item aktif = isian tinta penuh,
   bukan garis warna di pinggir; kuning tinggal di logo mark saja. */
.app-sidebar {
  position: fixed;
  inset: 0 auto 0 0;
  z-index: 25;
  width: var(--sidebar-width);
  padding: var(--space-8) var(--space-4) var(--space-6);
  display: flex;
  flex-direction: column;
  /* 10 tautan super admin + 3 kicker ~800px: tanpa gulir, Status Sistem dan
     tautan Akun tak terjangkau di laptop 768px dan ponsel. */
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--surface-0);
  color: var(--text-body);
  border-right: 1px solid var(--border-default);
}
.sidebar-kicker {
  padding: 0 var(--space-4);
  margin: 0 0 var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--text-muted);
}
.side-nav {
  display: grid;
  gap: var(--space-1);
}
.side-link {
  min-height: var(--field-h);
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: 0 var(--space-4);
  border-radius: 0;
  color: var(--text-body);
  font-size: var(--text-sm);
  font-weight: var(--fw-medium);
  text-decoration: none;
  transition: background 0.15s ease, color 0.15s ease;
}
.side-link vs-icon {
  flex: 0 0 auto;
  color: var(--text-subtle);
}
.side-link:hover {
  color: var(--text-strong);
  background: var(--bg-inset);
}
.side-link:hover vs-icon {
  color: var(--text-strong);
}
.side-link.is-active {
  color: var(--primary-contrast);
  background: var(--primary);
  font-weight: var(--fw-semibold);
}
.side-link.is-active vs-icon {
  color: var(--primary-contrast);
}
.side-link.is-active:hover {
  background: var(--primary-hover);
  color: var(--primary-contrast);
}
.side-divider {
  flex: 0 0 auto;
  height: 1px;
  margin: var(--space-6) var(--space-4) var(--space-5);
  background: var(--border-default);
}
.sidebar-account {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-3) 0;
  margin-top: auto;
  border-top: 1px solid var(--border-default);
}
.sidebar-account__copy {
  display: grid;
  gap: var(--space-1);
  min-width: 0;
  flex: 1;
}
.sidebar-account__copy strong {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--text-xs);
  font-weight: var(--fw-semibold);
  color: var(--text-strong);
}
.sidebar-account__copy span {
  font-size: var(--text-2xs);
  color: var(--text-muted);
}
.sidebar-account .icon-btn {
  color: var(--text-muted);
  border-radius: var(--radius-xs);
}
.sidebar-account .icon-btn:hover {
  color: var(--text-strong);
  background: var(--bg-inset);
}
/* Halaman Akun tidak punya tautan di daftar menu; ikon pengaturan yang menandainya aktif. */
.sidebar-account .icon-btn[aria-current="page"] {
  color: var(--primary-contrast);
  background: var(--primary);
}

.mobile-topbar, .bottom-nav {
  display: none;
}

/* Avatar & Badges */
.avatar {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  border-radius: 50%;
  background: var(--primary);
  color: var(--primary-contrast);
  font-family: var(--font-display);
  font-weight: var(--fw-bold);
}
.avatar--sm {
  width: 34px;
  height: 34px;
  font-size: var(--text-xs);
}

.icon-btn {
  min-width: 44px;
  min-height: 44px;
  display: inline-grid;
  place-items: center;
  border: 1px solid transparent;
  background: transparent;
  color: inherit;
  border-radius: var(--radius-xs);
  cursor: pointer;
  text-decoration: none;
  transition: background 0.15s ease, color 0.15s ease;
}
.icon-btn:hover {
  background: rgba(0, 0, 0, 0.05);
}
.icon-btn:active {
  background: var(--surface-1);
}

/* Page Header & Typography Scale */
.page-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-6);
  margin: 0 auto var(--space-9);
}
.page-header__copy {
  display: grid;
  gap: var(--space-3);
}
.page-header__copy p {
  margin: 0;
  color: var(--text-muted);
  font-size: var(--text-sm);
  line-height: 1.5;
}
.page-title {
  margin: 0;
  font-family: var(--font-display, inherit);
  font-size: var(--type-title);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-display);
  line-height: 1.1;
  color: var(--text-strong);
}
.eyebrow {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-subtle);
}
.section-heading {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
  margin: var(--space-10) 0 var(--space-5);
}
.section-heading h2 {
  margin: 0;
  font-size: var(--text-h2);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-display);
  color: var(--text-strong);
}
.section-heading a {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--fw-semibold);
  color: var(--text-muted);
  text-decoration: none;
  transition: color 0.15s ease;
}
.section-heading a:hover {
  color: var(--text-strong);
}

.text-muted { color: var(--text-muted); }
.text-subtle { color: var(--text-subtle); }
.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.tabular { font-variant-numeric: tabular-nums; }
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Grid & Layout Utilities */
.stack { display: grid; gap: 20px; }
.stack--sm { gap: 12px; }
.stack--tight { gap: 8px; }
.cluster { display: flex; align-items: center; flex-wrap: wrap; gap: 12px; }
.split { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.split--wrap { flex-wrap: wrap; gap: 16px; }
.grid { display: grid; gap: 20px; }
.grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

/* Buttons */
.vs-btn {
  min-height: var(--field-h);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 0 20px;
  border: 1px solid transparent;
  border-radius: 0;
  font: 600 13.5px var(--font-body);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.vs-btn:hover {
  transform: none;
}
.vs-btn:active {
  transform: none;
}
.vs-btn--sm {
  min-height: 36px;
  padding-inline: 14px;
  font-size: 12.5px;
}
.vs-btn--lg {
  min-height: 52px;
  padding-inline: 26px;
  font-size: 15px;
  font-weight: 700;
}
.vs-btn--primary {
  background: var(--primary);
  color: var(--primary-contrast);
}
.vs-btn--primary:hover {
  background: var(--primary-hover);
}
.vs-btn--brand {
  background: var(--brand);
  color: var(--brand-ink);
  font-weight: 700;
}
/* Dipakai hanya di halaman tamu (client.php). Nilai lama dipertahankan supaya
   sesi tema putih tidak mengubah permukaan publik. Hover-nya memang nyaris tak
   terlihat (#fff833 di atas #FFF700 = 1,01:1); perbaikannya milik owner. */
.vs-btn--brand:hover {
  background: #fff833;
}
.vs-btn--secondary {
  background: var(--surface-0);
  color: var(--text-strong);
  border-color: var(--border-default);
}
.vs-btn--secondary:hover {
  background: var(--surface-1);
  border-color: var(--border-strong);
}
.vs-btn--ghost {
  color: var(--text-strong);
  background: transparent;
}
.vs-btn--ghost:hover {
  background: rgba(0, 0, 0, 0.05);
}
.vs-btn:disabled,
.vs-btn[aria-disabled="true"] {
  cursor: not-allowed;
}
.vs-btn--block {
  width: 100%;
  white-space: normal;
  text-align: center;
  line-height: 1.35;
  padding-block: 11px;
  height: auto;
}
.button-link {
  color: var(--text-strong);
  text-decoration: underline;
  text-underline-offset: 3px;
  font-size: 13px;
}

/* Cards & Surfaces */
.stat-card, .surface-card {
  background: var(--surface-0);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
  box-shadow: none;
}
/* Kartu angka tidak bisa diklik, jadi tanpa efek hover: garis kuning yang
   menyala saat disorot dulu menjanjikan aksi yang tidak ada. */
.stat-card {
  min-height: 140px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: var(--space-6);
  position: relative;
  overflow: hidden;
}
.stat-card__label {
  font: var(--fw-semibold) var(--text-2xs) var(--font-mono);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--text-muted);
}
.stat-card__value {
  font: var(--fw-bold) clamp(32px, 4.2vw, 46px)/1 var(--font-display, inherit);
  letter-spacing: var(--ls-display);
  color: var(--text-strong);
  margin-block: var(--space-2);
}
.stat-card__meta {
  font-size: 12px;
  color: var(--text-muted);
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
/* Status Sistem: nada status di baris keterangan (teks + ikon), bukan di angka. */
.stat-card__meta.is-ok { color: var(--tag-success-text); }
.stat-card__meta.is-warn { color: var(--tag-warning-text); }
.stat-card__meta.is-fail { color: var(--tag-danger-text); }

/* Editorial metric bands: numbers are grouped by rules, not floating cards. */
.dashboard-kpis,
.admin-overview-kpis {
  gap: 0;
  border-top: 1px solid var(--border-default);
  border-left: 1px solid var(--border-default);
}
.dashboard-kpis .stat-card,
.admin-overview-kpis .stat-card {
  min-height: 132px;
  border-width: 0 1px 1px 0;
  border-radius: 0;
}

.surface-card {
  padding: var(--space-7);
}
.surface-card__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-5);
  margin-bottom: var(--space-6);
}
.surface-card__header h2, .surface-card__header h3 {
  margin: 0;
  font-size: var(--text-lg);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-display);
  color: var(--text-strong);
}
.surface-card__header p {
  margin: 5px 0 0;
  color: var(--text-muted);
  font-size: 13px;
  line-height: 1.45;
}
.surface-card__body {
  min-width: 0;
}

/* Hairline Lists & Activity Rows */
.hairline-list {
  display: grid;
}
.hairline-list > * {
  padding: 16px 0;
  border-top: 1px solid var(--border-faint);
}
.hairline-list > *:first-child {
  border-top: 0;
  padding-top: 0;
}
.hairline-list > *:last-child {
  padding-bottom: 0;
}

.activity-row, .health-row {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 14px 0;
}
.activity-row__copy, .health-row__copy {
  display: grid;
  gap: 3px;
  min-width: 0;
  flex: 1;
}
.activity-row__copy strong, .health-row__copy strong {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-strong);
}
/* Anak langsung saja: .tag dan tautan album di dalam baris memakai warnanya sendiri. */
.activity-row__copy > span, .health-row__copy > span {
  font-size: var(--text-xs);
  color: var(--text-muted);
  overflow-wrap: anywhere;
}
.activity-row__meta {
  font-size: var(--text-2xs);
  color: var(--text-muted);
  word-break: break-word;
}
.activity-row time {
  font-size: 12px;
  color: var(--text-muted);
  font-family: var(--font-mono);
  white-space: nowrap;
}
.health-row__value {
  font-size: 12px;
  max-width: 34ch;
  overflow-wrap: anywhere;
  color: var(--text-muted);
}
.health-row--fail .health-row__copy strong {
  color: var(--tag-danger-text);
}

/* Empty States */
.empty-state {
  min-height: 260px;
  display: grid;
  align-content: center;
  justify-items: start;
  gap: var(--space-4);
  padding: var(--space-9);
  background: var(--surface-0);
  border: 1px dashed var(--border-default);
  border-radius: var(--radius-card);
}
/* Di dalam .surface-card: kartu sudah jadi wadahnya, jadi tanpa kotak kedua. */
.empty-state--inline {
  min-height: 0;
  padding: var(--space-3) 0 0;
  background: transparent;
  border: 0;
}
.empty-state h2, .empty-state h3 {
  margin: 0;
  font-size: var(--text-h2);
  font-weight: var(--fw-bold);
  color: var(--text-strong);
}
.empty-state--inline h2, .empty-state--inline h3 {
  font-size: var(--text-h3);
}
.empty-state p {
  margin: 0;
  max-width: 46ch;
  color: var(--text-muted);
  font-size: 14px;
  line-height: 1.55;
}
.empty-state__mark {
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  background: var(--bg-inset);
  color: var(--text-strong);
  border-radius: 0;
  box-shadow: none;
}

/* Status Badges & Tags */
.status-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 26px;
  padding: 0 10px;
  border-radius: var(--radius-pill);
  background: var(--bg-subtle);
  color: var(--text-muted);
  font: 600 10.5px var(--font-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}
.status-badge::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--text-subtle);
}
.status-badge--live, .status-badge--processed {
  background: var(--green-wash);
  color: var(--accent-mint);
}
.status-badge--live::before, .status-badge--processed::before {
  background: var(--accent-mint);
}
.status-badge--submitted {
  background: var(--tag-warning-bg);
  color: var(--tag-warning-text);
}
.status-badge--submitted::before {
  background: var(--tag-warning-text);
}
.status-badge--danger {
  background: var(--red-wash);
  color: var(--accent-red);
}
.status-badge--danger::before {
  background: var(--accent-red);
}

.tag {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  padding: 0 9px;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-pill);
  background: var(--surface-0);
  color: var(--text-muted);
  font-size: 11.5px;
  font-weight: 500;
}
.tag--filter {
  background: var(--surface-1);
}

/* Album Grid & Album Card */
.album-grid {
  display: grid;
  /* Fluid tanpa breakpoint: kartu minimal 192 px, kolom bertambah mengikuti lebar; HP tetap 2 kolom. */
  grid-template-columns: repeat(auto-fill, minmax(min(calc(var(--space-12) * 2 + var(--space-8)), calc((100% - var(--space-5)) / 2)), 1fr));
  gap: var(--space-5);
}
.album-card {
  display: flex;
  flex-direction: column;
  min-width: 0;
  overflow: hidden;
  background: var(--surface-0);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
  box-shadow: none;
  transition: border-color 0.2s ease;
}
.album-card:hover {
  border-color: var(--border-strong);
}
.album-card__cover {
  position: relative;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  background: var(--bg-inset);
  text-decoration: none;
}
.album-card__cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.album-card__cover--empty {
  display: grid;
  place-items: center;
  color: var(--text-subtle);
  background: var(--bg-inset);
}
/* Badge di atas foto sampul: isiannya pekat (triad --tag-*), jadi kontrasnya
   tidak bergantung pada terang-gelapnya foto. */
/* Di kiri bawah sampul supaya tidak bertabrakan dengan kotak centang di kanan atas. */
.album-card__status {
  position: absolute;
  bottom: var(--space-3);
  left: var(--space-3);
  max-width: calc(100% - 2 * var(--space-3));
  border: 1px solid var(--border-default);
}
.album-card__body {
  display: grid;
  gap: var(--space-2);
  padding: var(--space-4);
}
.album-card__body h3 {
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--text-h4);
  font-weight: 700;
  color: var(--text-strong);
}
.album-card__body h3 a {
  color: inherit;
  text-decoration: none;
}
.album-card__body h3 a:hover {
  text-decoration: underline;
}
.album-card__meta {
  display: grid;
  gap: var(--space-1);
  font-size: var(--text-xs);
  color: var(--text-muted);
}
.album-card__meta > * { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.album-card__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: var(--space-3) var(--space-4);
  border-top: 1px solid var(--border-faint);
}
.album-card__footer time {
  font: 11.5px var(--font-mono);
  color: var(--text-muted);
}

/* Forms & Fields */
.form-shell {
  width: min(100%, 640px);
  margin: 4vh auto 0;
}
.form-shell--narrow {
  max-width: 480px;
}
.form-shell__header {
  display: grid;
  gap: 10px;
  margin-bottom: 28px;
}
.form-shell__header h1 {
  margin: 0;
  font-family: var(--font-display, inherit);
  font-size: clamp(28px, 4.5vw, 40px);
  font-weight: 800;
  letter-spacing: -0.04em;
  color: var(--text-strong);
}
.form-shell__header p {
  margin: 0;
  color: var(--text-muted);
  font-size: 14.5px;
  line-height: 1.5;
}
.form-card {
  padding: clamp(24px, 4.5vw, 40px);
  background: var(--surface-0);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
}
.field {
  display: grid;
  gap: 7px;
}
.field label {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-strong);
}
.field label span {
  color: var(--text-subtle);
  font-weight: 400;
  font-size: 12px;
}
.field input, .field textarea, .field select {
  width: 100%;
  min-height: var(--field-h);
  padding: 0 14px;
  border: 1px solid var(--border-input);
  border-radius: var(--radius-xs);
  background: var(--surface-0);
  color: var(--text-strong);
  font: 14px var(--font-body);
  transition: border-color 0.18s ease, box-shadow 0.18s ease;
}
.field textarea {
  min-height: 104px;
  padding-block: 12px;
  resize: vertical;
  line-height: 1.5;
}
.field select {
  appearance: auto;
}
.field input::placeholder, .field textarea::placeholder {
  color: var(--text-disabled);
}
.field input:focus, .field textarea:focus, .field select:focus {
  outline: 0;
  border-color: var(--border-strong);
  box-shadow: var(--shadow-focus);
}
/* Aturan .field input di atas menimpa tampilan nonaktif bawaan peramban;
   tanpa ini email terdaftar di Akun tampak bisa disunting. */
.field input:disabled, .field textarea:disabled, .field select:disabled {
  background: var(--bg-inset);
  color: var(--text-muted);
  border-color: var(--border-default);
  cursor: not-allowed;
}
.field small {
  color: var(--text-subtle);
  font-size: 12px;
  line-height: 1.4;
}
.form-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px;
}
.form-grid > .field--full {
  grid-column: 1 / -1;
}
.form-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding-top: 10px;
  margin-top: 6px;
}
.form-footer p {
  margin: 0;
  color: var(--text-muted);
  font-size: 13px;
}
.form-footer--end {
  justify-content: flex-end;
}
.auth-side-note {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 14px 16px;
  margin-top: 18px;
  background: var(--bg-inset);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-xs);
  color: var(--text-muted);
  font-size: 12.5px;
  line-height: 1.45;
}
.auth-side-note vs-icon {
  flex: 0 0 auto;
  color: var(--accent-mint);
  margin-top: 1px;
}
/* Dipakai juga di halaman tamu: nilai lamanya dibiarkan. Layar login memakai
   triad --tag-danger lewat override body.is-app di blok tema putih. */
.inline-error {
  padding: 12px 16px;
  background: var(--red-wash);
  border: 1px solid rgba(245, 54, 94, 0.25);
  border-radius: var(--radius-xs);
  color: var(--accent-red);
  font-size: 13px;
  font-weight: 500;
}

/* Filter Bar & Search */
.filter-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin: 0 auto 24px;
}
.filter-tabs {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  padding-bottom: 2px;
  -webkit-overflow-scrolling: touch;
}
.filter-tab {
  min-height: 44px;
  padding: 0 12px;
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  background: transparent;
  color: var(--text-muted);
  font: 600 12.5px var(--font-body);
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
.filter-tab:hover, .filter-tab.is-active {
  color: var(--text-strong);
  border-bottom-color: var(--text-strong);
}
.search-field {
  position: relative;
  width: min(290px, 100%);
}
.search-field vs-icon {
  position: absolute;
  left: 14px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-subtle);
  pointer-events: none;
}
.search-field input {
  width: 100%;
  min-height: 44px;
  padding: 0 14px 0 40px;
  border: 1px solid var(--border-input);
  border-radius: 0;
  background: var(--surface-0);
  font: 13px var(--font-body);
  transition: border-color 0.18s ease, box-shadow 0.18s ease;
}
.search-field input:focus {
  outline: 0;
  border-color: var(--border-strong);
  box-shadow: var(--shadow-focus);
}

/* =========================================================================
   PUBLIC PORTAL / CLIENT NATIVE-APP EXPERIENCE
   ========================================================================= */

.gallery-shell {
  --gallery-gap: 16px;
  margin: 0 auto;
  max-width: 1600px;
  padding: 0 clamp(16px, 3.5vw, 48px);
}

/* One quiet album appbar, direct card actions, and a solid action dock keep
   the public selection flow feeling like an app on narrow screens. */
body.is-album-public .page-main--public {
  background: var(--bg-app);
}
body.is-album-public .gallery-shell {
  /* --dock-h diukur ResizeObserver di app.js. Angka mati 128px sebelumnya jebol
     setiap kali dock membungkus (<=359px) atau chip kuota bertambah, dan itulah
     yang membuat baris foto terakhir tertutup dock. Dipasang di shell, bukan di
     grid, supaya sentinel dan empty-state ikut terlindungi. */
  padding-bottom: calc(var(--dock-h, 96px) + 24px + env(safe-area-inset-bottom, 0px));
}

/* Sticky Gallery Appbar */
.gallery-topbar {
  position: sticky;
  top: 0;
  z-index: 35;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 68px;
  padding: 14px 0 0;
  background: var(--surface-0);
  border-bottom: 1px solid var(--border-default);
}
.gallery-topbar__copy {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}
.gallery-topbar__copy h1 {
  font-size: 18px;
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  margin: 0;
  letter-spacing: -0.02em;
}
.gallery-topbar__sub {
  font-size: 12px;
  color: var(--text-muted);
}
.gallery-filters {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 1 1 100%;
  width: 100%;
  border-top: 1px solid var(--border-faint);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* Direct category guidance: the choice lives on each photo card. */
.gallery-guidance {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 12px 0;
  border-bottom: 1px solid var(--border-faint);
  color: var(--text-muted);
  font-size: 12px;
}
.gallery-guidance__copy {
  flex: 0 1 auto;
}
.gallery-guidance__quota {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  flex-wrap: wrap;
}
.gallery-quota {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 8px;
  border: 1px solid var(--border-default);
  border-radius: 0;
  background: transparent;
  white-space: nowrap;
}
.gallery-quota__icon { flex: 0 0 auto; color: var(--text-strong); }
.gallery-quota__name { color: var(--text-muted); }
.gallery-quota__count { color: var(--text-strong); font-size: 11px; font-variant-numeric: tabular-nums; }
/* app.js sudah men-toggle .is-full sejak dulu — ke ruang hampa, kelas ini tidak
   pernah punya satu pun aturan. Inilah rupanya. */
.gallery-quota.is-full {
  border-color: var(--ink-950);
  background: var(--ink-950);
}
.gallery-quota.is-full .gallery-quota__icon,
.gallery-quota.is-full .gallery-quota__name,
.gallery-quota.is-full .gallery-quota__count { color: #FFFFFF; }
@keyframes quotaFlash {
  0%, 100% { transform: none; }
  30% { transform: translateX(-3px); }
  60% { transform: translateX(3px); }
}
.gallery-quota.is-flash { animation: quotaFlash .32s ease-in-out; }

/* Fluid Photo Grid (Apple / Google Photos Native Vibe) */
.gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: var(--gallery-gap);
  /* Cadangan ruang untuk dock TIDAK dipasang di sini: grid bukan elemen terakhir
     dalam alur (sesudahnya masih ada empty-state dan #gallery-sentinel berisi
     tombol "Muat foto berikutnya"). Cadangannya ada di .gallery-shell. */
  padding: 20px 0 8px;
}
@media (max-width: 479px) {
  .gallery-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    --gallery-gap: 12px;
  }
}
@media (min-width: 480px) and (max-width: 767px) {
  .gallery-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    --gallery-gap: 12px;
  }
}
@media (min-width: 768px) and (max-width: 1023px) {
  .gallery-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.photo-card {
  position: relative;
  display: grid;
  grid-template-rows: auto auto auto;
  min-width: 0;
  overflow: visible;
  background: transparent;
  border: 0;
  user-select: none;
  transition: opacity 0.15s ease;
  cursor: pointer;
}
.photo-card:hover {
  opacity: .96;
}
.photo-card.is-selected {
  border-color: transparent;
}
.photo-card.is-selected .photo-card__visual img {
  filter: none;
}

.photo-card__visual {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 1;
  height: auto;
  overflow: hidden;
  display: block;
  border: 1px solid var(--border-default);
  border-bottom: 0;                 /* baris aksi yang menggambar garis bawahnya */
  outline: 0;
}
/* Kartu tanpa baris aksi (album tanpa kategori) tetap butuh garis bawahnya. */
.photo-card:not(:has(.photo-card__actions)) .photo-card__visual {
  border-bottom: 1px solid var(--border-default);
}
.photo-card__skeleton {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: block;
  background: var(--surface-1);
  opacity: 0;
  pointer-events: none;
}
.photo-card__visual.is-loading .photo-card__skeleton {
  opacity: 1;
  animation: skeletonPulse 1.15s ease-in-out infinite;
}
.photo-card__visual.is-loading img {
  opacity: 0;
}
@keyframes skeletonPulse {
  0%, 100% { opacity: 0.58; }
  50% { opacity: 1; }
}
.photo-card__visual img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: none;
}

/* ---------------------------------------------------------------------------
   Baris aksi ADAPTIF.

   Versi lama memakai grid-template-columns: repeat(2, …) — angka mati. Album
   dengan satu kategori memberi tombolnya setengah lebar kartu, sementara
   labelnya white-space: nowrap di dalam kartu yang overflow: visible, jadi teks
   "Edit Foto Retouch" keluar dari kartu dan menimpa kartu tetangga.

   Sekarang jumlah kolom = jumlah anak (grid-auto-flow: column), dan setiap sel
   MENGGUNTING isinya (overflow: hidden + ellipsis pada label). Nama kategori
   sepanjang apa pun tidak akan pernah lagi menyentuh layout kartu.
   --------------------------------------------------------------------------- */
.photo-card__actions {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: 0;
  min-width: 0;
  border: 1px solid var(--border-default);
  border-top: 0;                    /* pasangan dari .photo-card__visual { border-bottom: 0 } */
}
.photo-card__rule {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: 0;
  min-height: 44px;
  padding: 0 8px;
  overflow: hidden;                 /* kunci anti-luber: sel tidak pernah bocor */
  border: 0;
  border-left: 1px solid var(--border-default);
  border-radius: 0;
  background: var(--surface-0);
  color: var(--text-muted);
  font: 600 11.5px/1 var(--font-body);
  letter-spacing: -.01em;
  cursor: pointer;
  transition: background .15s ease, color .15s ease, opacity .15s ease;
}
.photo-card__rule:first-child { border-left: 0; }
.photo-card__rule:hover { background: var(--surface-1); color: var(--text-strong); }
.photo-card__rule.is-selected {
  background: var(--brand);
  color: var(--brand-ink);
}
.photo-card__rule-icon { flex: 0 0 auto; }
.photo-card__rule-label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 3 kategori atau lebih: sel terlalu sempit untuk kata. Label tetap hidup untuk
   pembaca layar; legenda di atas grid dan tombol lightbox yang mengajarkan ikon. */
.photo-card__actions:not([data-rules-count="1"]):not([data-rules-count="2"]) .photo-card__rule-label {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Kuota kategori penuh. Tombol TIDAK dipasangi atribut disabled: tombol disabled
   tidak memicu click, jadi ketukan ke-11 akan senyap lagi — persis bug yang
   sedang diperbaiki. Ia tetap bisa diklik supaya bisa menjawab dengan pesan. */
.photo-card__rule.is-locked {
  /* JANGAN memakai opacity pada seluruh tombol: ia ikut memudarkan teks dan ikon
     sampai ~1,8:1 — padahal tombol ini SENGAJA tetap bisa diklik dan difokuskan,
     jadi ia tidak mendapat pengecualian "kontrol nonaktif" dari WCAG. Yang boleh
     diredupkan hanya ikonnya, yang memang dekoratif (aria-hidden). */
  background: var(--surface-1);
  color: var(--text-muted);
  cursor: not-allowed;
}
.photo-card__rule.is-locked .photo-card__rule-icon { opacity: .5; }
.photo-card__rule.is-locked:hover { background: var(--surface-1); color: var(--text-muted); }

/* Penanda terpilih digambar DI ATAS gambar.
   ::after, bukan border pada elemennya: border 2px pada 162 kartu = grid melompat
   2px di bawah jari klien. box-shadow inset juga tidak bisa — tergambar di bawah
   <img>. Hairline gelap di dalam ring menjaga kuning tetap terbaca di foto terang. */
.photo-card.is-selected .photo-card__visual::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  /* Bingkainya HITAM, bukan kuning. Baris aksi yang menyala kuning sudah
     menjadi penanda utama; ring kuning di atasnya membuat setiap kartu
     terpilih jadi blok kuning penuh dan kuning berhenti berarti "penting".
     Hairline putih di dalamnya menjaga bingkai tetap terbaca di foto gelap. */
  border: 2px solid var(--ink-950);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .65);
}

/* Badge ikon di sudut gambar. Versi lama mencetak nama kategori penuh dan
   menutup 63% lebar foto tepat di sepertiga atas — tempat wajah dan produk. */
.photo-card__badges {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 5;
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  max-width: 100%;
  pointer-events: none;
}
.photo-card__badge {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 0;
  background: var(--brand);
  color: var(--brand-ink);
}

.photo-card__filename {
  display: block;
  min-width: 0;
  padding: 8px 0 0;
  font: 10.5px var(--font-mono);
  color: var(--text-muted);
  pointer-events: none;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.photo-card.is-broken {
  display: grid;
  background: transparent;
  color: var(--text-subtle);
}
.photo-card.is-broken .photo-card__visual {
  display: grid;
  place-items: center;
  min-height: 120px;
  background: var(--surface-1);
}
.photo-card.is-broken .photo-card__visual::before {
  content: 'Pratinjau tidak tersedia';
  padding: 12px;
  color: var(--text-muted);
  font: 600 11px/1.35 var(--font-body);
  text-align: center;
}
.photo-card[hidden] {
  display: none;
}

/* Sentinel Loader */
.gallery-sentinel {
  padding: 20px 0 60px;
  text-align: center;
}
.gallery-loader {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: 13.5px;
  color: var(--text-muted);
}
.gallery-loader__spinner {
  width: 20px;
  height: 20px;
  border: 2px solid var(--border-default);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}
@keyframes spin {
  to { transform: rotate(360deg); }
}

/* Full-width bottom action dock */
.gallery-progress {
  position: fixed;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 40;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 68px;
  padding: 10px max(16px, 4vw) calc(10px + env(safe-area-inset-bottom, 0px));
  background: var(--ink-950);
  color: #FFFFFF;
  border-top: 1px solid rgba(255, 255, 255, 0.18);
  animation: dockIn 0.18s ease-out;
}
@keyframes dockIn {
  from { opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}
.gallery-progress__copy {
  display: grid;
  gap: 2px;
  min-width: 0;
}
.gallery-progress__headline {
  display: flex;
  align-items: center;
  gap: 8px;
}
.gallery-progress__headline strong {
  font-size: 14.5px;
  font-weight: 700;
  color: #FFFFFF;
}
.gallery-progress__status {
  font-size: 11.5px;
  color: rgba(255, 255, 255, 0.65);
}
.gallery-progress__hint {
  font-size: 12px;
  color: var(--brand);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.gallery-progress__cta {
  flex: 0 0 auto;
  border-radius: 0;
  padding-inline: 20px;
  font-weight: 700;
  min-height: 42px;
}

/* Fullscreen Lightbox Gesture Viewer (OLED Deep Black) */
.viewer {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  background: var(--ink-950);
  user-select: none;
}
.viewer[hidden] {
  display: none !important;
}
.viewer__backdrop {
  position: absolute;
  inset: 0;
  z-index: 1;
}
.viewer__topbar {
  position: relative;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 24px;
  color: #FFFFFF;
}
.viewer__counter {
  font-size: 13.5px;
  color: rgba(255, 255, 255, 0.75);
  letter-spacing: 0.04em;
}
.viewer__top-actions {
  display: flex;
  align-items: center;
  gap: 12px;
}
.viewer__top-actions .icon-btn {
  color: #FFFFFF;
  background: rgba(255, 255, 255, 0.10);
  border-radius: 0;
}
.viewer__top-actions .icon-btn:hover {
  background: rgba(255, 255, 255, 0.22);
}
.viewer__stage {
  position: relative;
  z-index: 4;
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  padding: 0 12px;
  touch-action: pan-y pinch-zoom;
}
.viewer__nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 6;
  color: #FFFFFF;
  width: 52px;
  height: 52px;
  border-radius: 0;
  background: rgba(255, 255, 255, 0.12);
  transition: background 0.18s ease;
}
.viewer__nav:hover {
  background: rgba(255, 255, 255, 0.28);
}
.viewer__nav--prev { left: 20px; }
.viewer__nav--next { right: 20px; }
.viewer__image-wrapper {
  max-width: 95vw;
  max-height: calc(100vh - 150px);
  display: flex;
  align-items: center;
  justify-content: center;
}
.viewer__image {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: 0;
  box-shadow: none;
  transition: transform 0.2s ease-out;
}
.viewer.is-zoomed .viewer__image-wrapper {
  overflow: auto;
  max-width: 100vw;
  width: 100%;
  height: 100%;
  max-height: none;
  align-items: flex-start;
  justify-content: flex-start;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-x pan-y;
  cursor: grab;
}
.viewer.is-zoomed .viewer__image {
  flex: 0 0 auto;
  max-width: none;
  max-height: none;
  width: 220%;
  height: auto;
  border-radius: 0;
}
.viewer.is-zoomed .viewer__nav {
  opacity: 0.35;
}
.viewer.is-zoomed [data-viewer-zoom] {
  background: rgba(255, 255, 255, 0.3);
}

.viewer__bottombar {
  position: relative;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 16px 28px 24px;
  color: #FFFFFF;
  background: var(--ink-950);
}
.viewer__info {
  min-width: 0;
}
.viewer__filename {
  font-size: 13px;
  color: rgba(255, 255, 255, 0.85);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.viewer__toggle-btn {
  border-radius: 0;
  font-weight: 700;
}

/* Review Slide-Over Sheet / Drawer */
.review-drawer {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: flex;
  justify-content: flex-end;
}
.review-drawer[hidden] {
  display: none !important;
}
.review-drawer__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.65);
}
.review-drawer__panel {
  position: relative;
  z-index: 2;
  width: min(100%, 480px);
  height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--surface-0);
  box-shadow: -12px 0 40px rgba(0, 0, 0, 0.18);
  animation: drawerSlideIn 0.28s var(--ease-spring);
}
@keyframes drawerSlideIn {
  from { transform: translateX(100%); }
  to { transform: translateX(0); }
}
.review-drawer__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 22px 26px;
  border-bottom: 1px solid var(--border-default);
}
.review-drawer__header h2 {
  font-size: 20px;
  font-weight: 700;
  margin: 0;
  color: var(--text-strong);
}
.review-drawer__header p {
  font-size: 12.5px;
  color: var(--text-muted);
  margin: 3px 0 0;
}
.review-drawer__body {
  flex: 1;
  overflow-y: auto;
  padding: 22px 26px;
  display: grid;
  gap: 20px;
}
.review-group {
  display: grid;
  gap: 12px;
  padding: 16px;
  background: var(--bg-inset);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
}
.review-group__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.review-group__head strong {
  font-size: 14.5px;
  color: var(--text-strong);
}
.review-mini-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
  gap: 8px;
}
.review-thumb {
  position: relative;
  aspect-ratio: 1 / 1;
  border-radius: 6px;
  overflow: hidden;
  background: var(--surface-0);
  border: 1px solid var(--border-default);
}
.review-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.review-thumb__remove {
  position: absolute;
  top: 3px;
  right: 3px;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.75);
  border: 0;
  color: #FFFFFF;
  display: grid;
  place-items: center;
  cursor: pointer;
  padding: 0;
  transition: background 0.15s ease;
}
.review-thumb__remove:hover {
  background: var(--accent-red);
}
.review-drawer__footer {
  padding: 20px 26px 28px;
  border-top: 1px solid var(--border-default);
  background: var(--surface-0);
  display: grid;
  gap: 12px;
}
.review-drawer__handoff-note {
  margin: 0;
  color: var(--text-muted);
  font-size: 12px;
  line-height: 1.45;
}

/* Landing Pages & Authentication */
.gallery-landing {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(280px, 0.58fr);
  gap: clamp(32px, 7vw, 90px);
  align-items: center;
  width: min(100%, 1120px);
  min-height: calc(100dvh - var(--header-height));
  padding: 64px 24px;
  margin-inline: auto;
}
body.is-album-public .gallery-landing {
  min-height: 100dvh;
}
.gallery-landing__copy {
  display: grid;
  gap: 24px;
}
.client-entry-brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--text-strong);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.client-entry-brand img {
  width: 30px;
  height: 30px;
  padding: 5px;
  border-radius: 0;
  background: var(--vs-yellow);
  object-fit: contain;
}
.client-entry-brand small {
  display: block;
  margin-top: 2px;
  color: var(--text-subtle);
  font: 600 9px/1 var(--font-mono);
  letter-spacing: .1em;
  text-transform: uppercase;
}
.gallery-landing__copy h1 {
  margin: 0;
  font-family: var(--font-display, inherit);
  font-size: clamp(34px, 5.6vw, 58px);
  letter-spacing: -0.04em;
  line-height: 1.04;
  font-weight: 700;
  color: var(--text-strong);
}
.gallery-landing__copy p {
  margin: 0;
  max-width: 46ch;
  color: var(--text-muted);
  font-size: 16px;
  line-height: 1.6;
}
.gallery-landing__rules {
  display: grid;
  gap: 10px;
}
.landing-rule {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 14px 0;
  border-top: 1px solid var(--border-default);
}
.landing-rule strong {
  font-size: 14.5px;
  font-weight: 600;
  color: var(--text-strong);
}
.landing-rule span {
  font: 600 12px var(--font-mono);
  color: var(--text-muted);
}
.gallery-landing__visual {
  position: relative;
  min-height: 520px;
  background: var(--ink-950);
  border-radius: 0;
  overflow: hidden;
  border: 1px solid var(--ink-950);
}
.gallery-landing__skeleton {
  position: absolute;
  inset: 0;
  display: block;
  background: var(--ink-800);
  opacity: 0;
  pointer-events: none;
}
.gallery-landing__visual.is-loading .gallery-landing__skeleton {
  opacity: 1;
  animation: skeletonPulse 1.15s ease-in-out infinite;
}
.gallery-landing__visual.is-loading img { opacity: 0; }
.gallery-landing__visual img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.88;
}

.client-ident {
  width: min(100%, 450px);
  margin: 8vh auto 0;
  padding-inline: 20px;
}
.client-ident h1 {
  font-size: 30px;
  font-weight: 700;
  letter-spacing: -0.03em;
  margin: 8px 0 0;
}
.client-ident > p {
  margin-top: 8px;
  color: var(--text-muted);
  font-size: 14.5px;
  line-height: 1.5;
}
.client-ident .form-card {
  margin-top: 24px;
  padding: 24px 0 0;
  border: 0;
  border-top: 1px solid var(--border-default);
  border-radius: 0;
  background: transparent;
  box-shadow: none;
}
.client-pin-input {
  font-size: 20px !important;
  letter-spacing: 0.2em;
  text-align: center;
  font-weight: 700 !important;
}
.submitted-id { font-weight: 700; }
.submitted-thanks {
  margin-top: 16px;
}

/* Toast Notifications */
.toast {
  position: fixed;
  top: 24px;
  right: 24px;
  z-index: 80;
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: min(400px, calc(100vw - 48px));
  padding: 14px 18px;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-xs);
  background: var(--surface-0);
  box-shadow: var(--shadow-pop);
  font-size: 13.5px;
  font-weight: 500;
  animation: toastSlide 0.25s var(--ease-spring);
}
@keyframes toastSlide {
  from { transform: translateY(-16px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}
/* Nada dibawa warna teks + garis penuh. Garis warna di satu sisi dilarang
   (aturan owner), termasuk di permukaan tamu yang tidak ikut tema putih. */
.toast--success {
  color: var(--accent-mint);
  border-color: var(--accent-mint);
}
.toast--error {
  color: var(--accent-red);
  border-color: var(--accent-red);
}
/* Tombol tutup tetap 44x44 sebagai target sentuh tanpa menebalkan toast. */
.toast__close {
  margin: -10px -12px -10px auto;
}
.toast__close:focus-visible {
  outline: 2px solid var(--ink-950);
  outline-offset: -2px;
  box-shadow: none;
}
/* Di layar sempit toast bertumpuk dengan tombol menu di topbar; toast galat
   tidak hilang sendiri, jadi menunya akan tertutup selamanya. */
@media (max-width: 899px) {
  body.is-app .toast {
    top: calc(62px + var(--space-3) + env(safe-area-inset-top, 0px));
    left: var(--space-5);
    right: var(--space-5);
    max-width: none;
  }
}

/* Error Page */
.error-page {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: 24px;
  background: var(--bg-app);
}
.error-card {
  width: min(100%, 520px);
  display: grid;
  gap: 16px;
  padding: 40px;
  background: var(--surface-0);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
}
.error-card h1 {
  margin: 0;
  font-size: 28px;
  font-weight: 800;
}
.error-card p {
  margin: 0;
  color: var(--text-muted);
  font-size: 14.5px;
  line-height: 1.55;
}

/* Google Auth Block */
.google-auth-block {
  margin-bottom: 22px;
}
/* Hanya berlaku saat ADA dua tombol masuk pihak ketiga (VS OS + Google).
   Bentuk sibling-nya membuat aturan ini tidak berpengaruh sama sekali saat
   hanya satu tombol yang dirender. */
.google-auth-block .google-btn + .google-btn { margin-top: 10px; }
.google-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  min-height: 46px;
  font-weight: 600;
  border-radius: var(--radius-xs);
}
.google-icon {
  flex: 0 0 18px;
}
.auth-divider {
  position: relative;
  margin: 22px 0;
  text-align: center;
}
.auth-divider::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--border-default);
}
.auth-divider span {
  position: relative;
  background: var(--surface-0);
  padding: 0 14px;
  font-size: 12.5px;
  color: var(--text-subtle);
}

/* Workspace Tabs & Sections */
.workspace-tabs {
  display: flex;
  gap: 24px;
  overflow-x: auto;
  /* Margin negatif dibuang: ia menarik strip menembus padding-bawah hero dan
     garisnya, sehingga tab menempel ke judul. Jarak kini dimiliki .album-tabbar. */
  margin: 0;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.workspace-tabs::-webkit-scrollbar { display: none; }
.workspace-tab {
  position: relative;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  padding: 0 2px;
  border: 0;
  background: transparent;
  color: var(--text-muted);
  font: 600 13.5px var(--font-body);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: color 0.15s ease;
}
.workspace-tab:hover {
  color: var(--text-strong);
}
.workspace-tab::after {
  content: '';
  position: absolute;
  right: 0;
  bottom: -1px;
  left: 0;
  height: 2px;
  background: transparent;
  transition: background 0.18s ease;
}
.workspace-tab.is-active {
  color: var(--text-strong);
  font-weight: 700;
}
.workspace-tab.is-active::after {
  background: var(--primary);
}

.workspace-hero {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
  padding: 24px 0 30px;
  border-bottom: 1px solid var(--border-default);
}
.workspace-hero__copy {
  display: grid;
  gap: 9px;
}
.workspace-hero__copy h1 {
  margin: 0;
  font-size: clamp(28px, 4vw, 42px);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-display);
}
.workspace-hero__copy p {
  margin: 0;
  color: var(--text-muted);
  font-size: 14.5px;
}
.workspace-hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.detail-stat {
  display: grid;
  gap: 6px;
  padding: 16px 0;
  border-bottom: 1px solid var(--border-faint);
}
.detail-stat:last-child {
  border-bottom: 0;
  padding-bottom: 0;
}
.detail-stat__label {
  font: var(--fw-semibold) var(--text-2xs) var(--font-mono);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--text-muted);
}
.detail-stat strong {
  font-size: 18px;
  font-weight: 700;
  color: var(--text-strong);
}
.detail-stat span {
  color: var(--text-muted);
  font-size: 12.5px;
}

.response-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 18px;
  padding: 16px 0;
  border-top: 1px solid var(--border-faint);
  text-decoration: none;
  color: inherit;
  transition: background 0.15s ease;
}
.response-row:first-child {
  border-top: 0;
  padding-top: 0;
}
.response-row__copy {
  display: grid;
  gap: 4px;
  min-width: 0;
}
.response-row__copy strong {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 14.5px;
  font-weight: 600;
  color: var(--text-strong);
}
.response-row__copy span {
  color: var(--text-muted);
  font-size: 12.5px;
}
.response-row__count {
  font: 600 12.5px var(--font-mono);
  color: var(--text-muted);
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.response-detail {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(260px, 0.6fr);
  gap: var(--space-6);
  align-items: start;
}
.selection-group {
  display: grid;
  gap: 12px;
  padding: 18px 0;
  border-top: 1px solid var(--border-faint);
}
.selection-group:first-child {
  padding-top: 0;
  border-top: 0;
}
.selection-group__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.selection-group__head h3 {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
}
.filename-list {
  display: grid;
  gap: 6px;
}
.filename {
  display: block;
  padding: 10px 12px;
  border-radius: var(--radius-xs);
  background: var(--bg-inset);
  font: 12.5px var(--font-mono);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-strong);
}

/* Blok bergaris tipis penuh. Garis warna di pinggir sebagai penanda status
   dilarang owner; keadaan dibawa isian (--warn, --ok) dan badge. */
.drive-callout {
  display: grid;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border: 1px solid var(--border-default);
  background: var(--surface-0);
}
.drive-callout .split {
  flex-wrap: wrap;
}
/* URL, token undangan, dan sandi sementara dibungkus: tombol Salin tetap
   terlihat di 360px tanpa menggulir kotak ke samping. */
.drive-callout__email {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  padding: 10px 14px;
  background: var(--surface-0);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-xs);
  font: 12.5px var(--font-mono);
}
.drive-callout__email code {
  flex: 1 1 auto;
  min-width: 0;
  align-self: center;
  white-space: normal;
  overflow-wrap: anywhere;
}
.drive-callout__email .icon-btn {
  flex: 0 0 auto;
}
.drive-callout--warn {
  margin-top: var(--space-4);
  background: var(--tag-warning-bg);
  border-color: var(--tag-warning-border);
}
.drive-callout--ok {
  background: var(--tag-success-bg);
  border-color: var(--tag-success-border);
}

/* Form buat album (create-album.php) */
.wizard {
  display: grid;
  grid-template-columns: minmax(190px, 240px) minmax(0, 1fr);
  gap: var(--space-8);
  align-items: start;
}
.wizard--single {
  grid-template-columns: minmax(0, 860px);
  justify-content: center;
}
.wizard-card {
  padding: clamp(24px, 4.5vw, 42px);
  background: var(--surface-0);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-card);
}
.wizard-card__header {
  display: grid;
  gap: var(--space-3);
  padding-bottom: var(--space-6);
  margin-bottom: var(--space-7);
  border-bottom: 1px solid var(--border-default);
}
.wizard-card__header h2 {
  margin: 0;
  font-size: 24px;
  font-weight: var(--fw-bold);
}
.wizard-card__header p {
  margin: 0;
  color: var(--text-muted);
  font-size: 14px;
}

/* Brand Settings Slot */
.brand-slot {
  display: grid;
  grid-template-columns: minmax(0, 240px) minmax(0, 1fr);
  gap: 22px;
  align-items: start;
  margin-top: 18px;
}
.brand-slot__preview {
  display: grid;
  place-items: center;
  min-height: 100px;
  padding: 18px;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
  background: var(--bg-inset);
}
.brand-slot__preview img {
  max-width: 100%;
  max-height: 150px;
  object-fit: contain;
}
.brand-slot__preview--og {
  aspect-ratio: 1200 / 630;
  min-height: 0;
  padding: 0;
  overflow: hidden;
}
.brand-slot__preview--og img {
  width: 100%;
  height: 100%;
  /* Kotaknya sudah 1200:630; batas 150px milik slot logo akan melebarkan pita
     kosong di atas dan bawah sehingga admin tidak melihat bingkai sebenarnya. */
  max-height: none;
  object-fit: cover;
}
.brand-slot__copy {
  display: grid;
  gap: 10px;
  align-content: start;
  min-width: 0;
}
.brand-slot__copy p {
  margin: 0;
  font-size: 13px;
  line-height: 1.55;
}
.brand-slot__form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}
.brand-slot__file {
  flex: 1 1 220px;
  min-width: 0;
  font-size: 12px;
  padding: 8px;
  border: 1px dashed var(--border-default);
  border-radius: var(--radius-xs);
  background: var(--surface-0);
}
.brand-slot__file::file-selector-button {
  margin-right: 10px;
  padding: 6px 12px;
  border: 0;
  border-radius: var(--radius-xs);
  background: var(--bg-subtle);
  color: var(--text-strong);
  font: 600 12px var(--font-body);
  cursor: pointer;
}
.brand-slot--dark {
  margin-top: 24px;
  padding-top: 24px;
  border-top: 1px solid var(--border-default);
}
.brand-slot__preview--dark {
  background: var(--ink-950);
  border-color: transparent;
  color: var(--text-on-dark);
}
.brand-slot__preview--dark .wordmark {
  color: var(--text-on-dark);
}
.brand-slot__preview--dark .wordmark-by {
  color: var(--text-on-dark-muted);
}
.brand-slot__copy > strong {
  font-size: var(--text-sm);
  color: var(--text-strong);
}
/* Pasangan eksplisit dari --dark: latar terang, supaya kedua pratinjau
   menyatakan latarnya sendiri alih-alih salah satunya mewarisi diam-diam. */
.brand-slot__preview--light { background: var(--surface-0); }

/* Admin WhatsApp template composer */
.admin-whatsapp-composer {
  margin-top: 24px;
}
.admin-whatsapp-composer > form {
  gap: 20px;
}
.whatsapp-composer__hint {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px 14px;
  border: 1px solid var(--border-default);
  border-radius: 0;
  background: var(--bg-subtle);
  color: var(--text-muted);
  font-size: 12px;
  line-height: 1.5;
}
.whatsapp-composer__hint strong {
  color: var(--text-strong);
  white-space: nowrap;
}
.whatsapp-composer__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
  align-items: start;
}
.whatsapp-template-card {
  display: grid;
  grid-template-columns: minmax(220px, 0.34fr) minmax(0, 1fr);
  gap: 20px;
  min-width: 0;
  padding: 22px 0;
  border-top: 1px solid var(--border-default);
  background: transparent;
}
.whatsapp-template-card:last-child {
  border-bottom: 1px solid var(--border-default);
}
.whatsapp-template-card__meta,
.whatsapp-template-card__editor {
  min-width: 0;
}
.whatsapp-template-card__editor {
  display: grid;
  align-content: start;
  gap: 10px;
}
.whatsapp-template-card__meta {
  display: grid;
  align-content: start;
  gap: 16px;
}
.whatsapp-template-card__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
}
.whatsapp-template-card__head h3 {
  margin: 6px 0 0;
  font-size: 15px;
}
.whatsapp-template-card__index {
  display: block;
  color: var(--text-muted);
  font-size: var(--text-2xs);
  letter-spacing: var(--ls-label);
}
.whatsapp-template-card__head p {
  margin: 5px 0 0;
  color: var(--text-muted);
  font-size: 12px;
  line-height: 1.45;
}
.whatsapp-template-card textarea {
  width: 100%;
  min-height: 170px;
  padding: 12px 14px;
  border: 1px solid var(--border-input);
  border-radius: var(--radius-xs);
  background: var(--surface-0);
  color: var(--text-strong);
  resize: vertical;
  font: 12.5px/1.55 var(--font-mono);
  transition: border-color 0.18s ease, box-shadow 0.18s ease;
}
.whatsapp-template-card textarea:focus {
  outline: 0;
  border-color: var(--border-strong);
  box-shadow: var(--shadow-focus);
}
.whatsapp-template-card__tokens {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}
.whatsapp-template-card__tokens code {
  padding: 3px 6px;
  border: 1px solid var(--border-default);
  border-radius: 0;
  background: var(--bg-subtle);
  color: var(--text-muted);
  font: var(--text-2xs)/1.2 var(--font-mono);
}
.whatsapp-template-card__preview {
  padding: 10px;
  border: 1px solid var(--border-default);
  border-radius: 0;
  background: var(--bg-subtle);
}
.whatsapp-template-card__preview-label {
  display: block;
  margin-bottom: var(--space-2);
  color: var(--text-muted);
  font: var(--fw-semibold) var(--text-2xs) var(--font-mono);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
}
.whatsapp-template-card__preview pre {
  max-height: 150px;
  margin: 0;
  overflow: auto;
  white-space: pre-wrap;
  color: var(--text-muted);
  font: 11px/1.5 var(--font-mono);
}
.whatsapp-template-card__reset {
  justify-self: start;
}

/* Responsive Breakpoints */
@media (max-width: 1100px) {
  .grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Tablet app shell: keep the desktop information architecture while reducing
   the rail to icon navigation so dashboard cards retain usable line length. */
@media (min-width: 900px) and (max-width: 1119px) {
  :root { --sidebar-width: 72px; }
  .app-sidebar { padding-inline: 10px; }
  .wordmark--sidebar { justify-content: center; margin-inline: 0; }
  .wordmark--sidebar .wordmark-name,
  .sidebar-kicker,
  .sidebar-account__copy { display: none; }
  .wordmark--sidebar .wordmark-mark { width: 34px; height: 34px; }
  /* Logo unggahan yang lebar dulu meluber melewati rail 72px. */
  .wordmark--sidebar .wordmark-logo { max-width: 100%; height: auto; max-height: 32px; }
  .side-link { justify-content: center; padding-inline: 0; }
  /* Label disembunyikan secara visual saja: ikon vs-icon aria-hidden, jadi
     display:none meninggalkan tautan rail tanpa nama aksesibel. */
  .side-link span {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
  /* Ikon pengaturan tetap tampil: di lebar ini ia satu-satunya jalan ke Akun & Keluar. */
  .sidebar-account { flex-direction: column; justify-content: center; padding-inline: 0; gap: var(--space-2); }
  .admin-overview-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .admin-overview-panels { align-items: start; }
  .admin-overview-panels > .surface-card { min-width: 0; }
  .whatsapp-composer__grid { grid-template-columns: 1fr; }
}

@media (max-width: 899px) {
  :root {
    --sidebar-width: 0px;
  }
  .page-main {
    margin-left: 0;
    padding: calc(78px + env(safe-area-inset-top, 0px)) max(16px, env(safe-area-inset-right, 0px)) calc(88px + env(safe-area-inset-bottom, 0px)) max(16px, env(safe-area-inset-left, 0px));
  }
  .page-main--public {
    min-height: calc(100dvh - 62px);
    padding: 0;
  }
  .whatsapp-composer__hint {
    flex-direction: column;
    gap: 4px;
  }
  .whatsapp-composer__grid { grid-template-columns: 1fr; }
  .whatsapp-template-card {
    grid-template-columns: 1fr;
    gap: 14px;
    padding: 18px 0;
  }

  /* Mobile Drawer Sidebar */
  .app-sidebar {
    width: 270px;
    /* Bilah bawah (z 30) menutupi ~60px dasar laci; ruangnya dicadangkan sama
       seperti .page-main supaya blok akun tetap terjangkau. */
    padding-bottom: calc(88px + env(safe-area-inset-bottom, 0px));
    transform: translateX(-100%);
    transition: transform 0.24s var(--ease-spring), visibility 0s linear 0.24s;
    box-shadow: var(--shadow-pop);
  }
  /* Laci tertutup keluar dari urutan Tab dan pohon aksesibilitas. */
  body:not(.nav-open) .app-sidebar {
    visibility: hidden;
  }
  body.nav-open .app-sidebar {
    transform: translateX(0);
    visibility: visible;
    transition: transform 0.24s var(--ease-spring);
  }
  .nav-scrim {
    position: fixed;
    inset: 0;
    z-index: 24;
    background: rgba(0, 0, 0, 0.55);
    border: 0;
    padding: 0;
  }
  body:not(.nav-open) .nav-scrim {
    display: none;
  }

  .mobile-topbar {
    position: fixed;
    inset: 0 0 auto 0;
    z-index: 22;
    display: flex;
    align-items: center;
    justify-content: space-between;
    min-height: calc(62px + env(safe-area-inset-top, 0px));
    padding: env(safe-area-inset-top, 0px) max(16px, env(safe-area-inset-right, 0px)) 0 max(16px, env(safe-area-inset-left, 0px));
    background: var(--surface-0);
    color: var(--text-strong);
    border-bottom: 1px solid var(--border-default);
  }
  .mobile-topbar .icon-btn,
  .mobile-topbar .wordmark {
    color: var(--text-strong);
  }
  /* Target sentuh 44px seperti wordmark sidebar; tinggi bilah 62px sudah memberi ruangnya. */
  .mobile-topbar .wordmark {
    min-height: 44px;
  }
  .mobile-topbar .wordmark-by {
    color: var(--text-muted);
  }

  /* Bilah atas (62px) dan bilah bawah (~60px) sama-sama fixed. Tanpa cadangan ini
     peramban menggulir kontrol yang difokus Tab hanya sampai tepi viewport, yaitu
     tepat di bawah bilah. scroll-padding dibaca dari elemen akar, bukan <body>. */
  html:has(body.is-app) {
    scroll-padding-top: calc(62px + env(safe-area-inset-top, 0px) + 8px);
    scroll-padding-bottom: calc(60px + env(safe-area-inset-bottom, 0px) + 16px);
  }

  /* Mobile Bottom Navigation Bar */
  .bottom-nav {
    position: fixed;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 30;
    display: grid;
    /* Kolom mengikuti jumlah item agar tetap satu baris pada semua perangkat;
       5 item creator (Beranda, Album, Respon, Profil, Akun) = 60.8px per item di 320px. */
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    padding: 6px max(8px, env(safe-area-inset-right, 0px)) calc(8px + env(safe-area-inset-bottom, 0px)) max(8px, env(safe-area-inset-left, 0px));
    background: var(--surface-0);
    border-top: 1px solid var(--border-default);
  }
  .bottom-nav__item {
    display: grid;
    justify-items: center;
    gap: 3px;
    min-width: 0;
    min-height: 44px;
    padding-top: 5px;
    color: var(--text-muted);
    font-size: var(--text-2xs);
    font-weight: 500;
    text-decoration: none;
    border: 0;
    background: transparent;
    font-family: var(--font-body);
    cursor: pointer;
    transition: color 0.15s ease;
  }
  .bottom-nav__item span {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  /* Ikon abu -> hitam membawa keadaan aktif; label sudah lolos AA di kedua keadaan. */
  .bottom-nav__item vs-icon {
    color: var(--text-subtle);
  }
  .bottom-nav__item.is-active {
    color: var(--text-strong);
    font-weight: 700;
  }
  .bottom-nav__item.is-active vs-icon {
    color: var(--primary);
  }

  .page-header {
    align-items: flex-start;
    flex-direction: column;
    margin-bottom: 24px;
  }
  .page-title {
    font-size: 30px;
  }
  .page-header .vs-btn {
    width: 100%;
  }
  .admin-page-header .cluster {
    width: 100%;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
  }
  .admin-page-header .cluster .vs-btn { width: auto; padding-inline: 10px; }

  .grid--2, .grid--3, .grid--4 {
    grid-template-columns: 1fr;
  }
  .admin-overview-kpis {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0;
  }
  .admin-overview-kpis .stat-card {
    min-height: 126px;
    padding: 16px;
  }
  .admin-overview-panels { align-items: start; }
  .admin-overview-panels .surface-card { padding: 20px 18px; }
  .filter-bar {
    align-items: stretch;
    flex-direction: column;
  }
  .search-field {
    width: 100%;
  }
  .form-grid {
    grid-template-columns: 1fr;
  }
  .form-grid > .field--full {
    grid-column: auto;
  }
  .form-footer {
    align-items: stretch;
    flex-direction: column;
  }
  .form-footer .vs-btn {
    width: 100%;
  }

  .wizard {
    grid-template-columns: 1fr;
    gap: 20px;
  }
  .wizard-card {
    padding: 22px 18px;
  }

  .workspace-hero {
    flex-direction: column;
  }
  .workspace-hero__actions {
    width: 100%;
  }
  .workspace-hero__actions .vs-btn {
    flex: 1;
  }

  .response-detail {
    grid-template-columns: 1fr;
  }
  .response-row {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 10px;
  }
  .response-row__count {
    grid-column: 2;
  }

  .gallery-topbar {
    flex-wrap: wrap;
    padding-inline: 0;
    min-height: 0;
    padding-top: 8px;
  }
  .gallery-topbar__copy {
    flex: 1 1 auto;
    min-width: 0;
  }
  .gallery-filters {
    flex: 1 1 100%;
    width: 100%;
    min-width: 0;
  }
  .gallery-filters .filter-tab {
    min-height: 44px;
    padding-inline: 12px;
  }
  .gallery-guidance {
    align-items: flex-start;
    flex-direction: column;
    gap: 8px;
    padding-block: 10px 12px;
  }
  .gallery-guidance__quota {
    justify-content: flex-start;
    gap: 5px;
  }
  .gallery-quota { padding: 4px 7px; }
  .gallery-progress {
    right: 0;
    bottom: 0;
    left: 0;
    max-width: none;
    border-radius: 0;
  }
  .gallery-progress__cta { min-height: 44px; }
}

@media (max-width: 359px) {
  .gallery-progress {
    flex-wrap: wrap;
    gap: 8px;
  }
  .gallery-progress__copy,
  .gallery-progress__cta { flex: 1 1 100%; }
  .gallery-progress__cta { width: 100%; }
}

@media (min-width: 360px) and (max-width: 899px) {
  .gallery-progress__copy { flex: 1 1 0; }
  .gallery-progress__cta { flex: 0 0 auto; }
}

@media (max-width: 899px) {
  .gallery-landing {
    grid-template-columns: 1fr;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    min-height: auto;
    gap: 0;
    padding: 0 0 40px;
  }
  body.is-album-public .gallery-landing { min-height: auto; }
  .gallery-landing__visual {
    order: -1;
    width: 100%;
    min-height: 38dvh;
    max-height: 52dvh;
    border-radius: 0;
  }
  .gallery-landing__copy {
    padding: 30px 20px 0;
    gap: 18px;
  }
  .gallery-landing__copy h1 {
    font-size: clamp(32px, 9vw, 44px);
  }
  .gallery-landing__copy p {
    font-size: 15px;
  }
  .gallery-landing__copy > .vs-btn,
  .gallery-landing__copy form .vs-btn { width: 100%; }
  .client-ident input,
  .client-ident textarea { font-size: 16px; }

  .surface-card {
    padding: 20px 18px;
  }
  .brand-slot {
    grid-template-columns: 1fr;
  }
  .brand-slot__form .vs-btn, .brand-slot__copy form .vs-btn {
    width: 100%;
  }

  .review-drawer {
    align-items: flex-end;
  }
  .review-drawer__panel {
    width: 100%;
    height: min(92dvh, 720px);
    max-height: calc(100dvh - env(safe-area-inset-top, 0px));
    border-radius: 4px 4px 0 0;
    animation: drawerSheetIn 0.28s var(--ease-spring);
  }
  @keyframes drawerSheetIn {
    from { transform: translateY(100%); }
    to { transform: translateY(0); }
  }
  .review-drawer__header {
    padding: 18px 18px 14px;
  }
  .review-drawer__body {
    padding: 16px 18px;
    gap: 14px;
  }
  .review-drawer__footer {
    padding: 14px 18px calc(16px + env(safe-area-inset-bottom, 0px));
  }
  .review-drawer__footer .vs-btn--lg {
    min-height: 52px;
  }
  .review-drawer input,
  .review-drawer textarea { font-size: 16px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
    transition-duration: 0.01ms !important;
  }
  .photo-card img, .album-card__cover img {
    transition: none;
  }
}

@media (min-width: 640px) and (max-width: 899px) {
  .gallery-topbar { flex-wrap: wrap; padding-top: 12px; }
  .gallery-topbar__copy { flex: 1 1 260px; }
  .gallery-filters { flex: 1 1 100%; width: 100%; max-width: none; }
  .gallery-filters .filter-tab { min-height: 44px; padding-inline: 12px; }
}

/* ---- Catatan kaki halaman masuk ----
   "Lupa kata sandi?" bukan footer aksi. .form-footer memakai
   justify-content:space-between untuk memisahkan label dari tombol, jadi dua
   potong teks di dalamnya terlempar ke dua sisi dengan ukuran huruf berbeda —
   yang kiri lalu terpaksa membungkus. Ini satu kalimat, jadi satu blok. */
.auth-help { margin: 16px 2px 0; font-size: 12.5px; line-height: 1.55; color: var(--text-subtle); }
.auth-help strong { color: var(--text-muted); font-weight: 600; }

/* =========================================================================
   Album Workspace — tab sungguhan + irama vertikal
   Spec: docs/SPEC-Album-Workspace.md
   ========================================================================= */

/* Baris kontrol: tablist di kiri, tautan keluar di kanan. Garisnya di sini,
   bukan di masing-masing tab, supaya hanya ada satu pemisah. */
.album-tabbar {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-7);
  /* Jarak atas 20px (D6, SPEC:130-131) DIPERTAHANKAN, tetapi dipecah jadi
     margin 8px + padding 12px. Alasannya: margin-atas elemen sticky tidak
     dirender lagi begitu ia menempel di top:0, jadi bila seluruh 20px ditaruh
     di margin, tab akan menyentuh tepi layar saat menempel. Padding ikut
     menempel dan itulah yang menyisakan jarak baca. Saat BELUM menempel
     geometrinya tetap 8+12 = 20px, identik dengan sebelumnya. */
  margin: var(--space-3) auto var(--space-8);
  padding-top: var(--space-4);
  border-bottom: 1px solid var(--border-default);
}
.album-tabbar .workspace-tabs { flex: 1 1 auto; min-width: 0; }

/*
 * Tabstrip menempel saat menggulir panel panjang (Kategori Brief ~1125px).
 * Spec: docs/SPEC-Album-Workspace.md:184 ("satu garis, sticky di desktop lebar")
 * dan :190 ("scroll dimiliki dokumen, bukan panel") — karena itu solusinya sticky
 * pada dokumen, BUKAN memberi panel overflow sendiri.
 *
 * Rantai leluhurnya bersih, dan itulah sebabnya ini bekerja:
 *     .album-tabbar -> main.page-main -> body -> html
 * tidak satu pun punya overflow / transform / filter / contain. Satu-satunya
 * overflow di sekitar sini ada pada .workspace-tabs — itu ANAK strip, bukan
 * leluhurnya. Karena itu yang di-sticky-kan HARUS wadah .album-tabbar; men-sticky
 * .workspace-tabs akan menjadikannya scroll container sendiri dan tautan keluar
 * "Respon Klien" tertinggal.
 *
 * .app-sidebar tidak ikut campur: ia position:fixed dan SAUDARA <main>, bukan
 * leluhur — ruangnya dibuat lewat .page-main{margin-left}, di luar mekanisme sticky.
 *
 * background WAJIB, bukan pemanis: tanpa itu isi panel menggulir tembus teks tab.
 * z-index 20 = di atas isi panel, di bawah seluruh overlay/modal (terendah 30).
 *
 * <900px sengaja TETAP statis: di sana .album-tabbar menumpuk jadi dua baris
 * dan .mobile-topbar yang fixed menuntut offset
 * yang belum bertoken.
 */
@media (min-width: 900px) {
  .album-tabbar {
    position: sticky;
    top: 0;
    z-index: 20;
    background: var(--bg-app);
  }
}

/* "Respon Klien" berpindah HALAMAN, jadi ia tidak boleh tampak seperti tab.
   Bentuknya sengaja berbeda: tautan dengan panah, bukan tab bergaris bawah. */
.album-tabbar__exit {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: var(--field-h);
  padding: 0 2px;
  color: var(--text-muted);
  font: 600 13px var(--font-body);
  text-decoration: none;
  white-space: nowrap;
}
.album-tabbar__exit:hover { color: var(--text-strong); }

/*
 * Penyembunyian panel HANYA berlaku setelah JavaScript menyalakan .is-tabbed.
 * Tanpa penjaga ini, JS yang gagal dimuat akan menyembunyikan hampir seluruh
 * isi halaman ini secara permanen.
 */
.album-panels.is-tabbed > .album-panel { display: none; }
.album-panels.is-tabbed > .album-panel.is-active { display: block; }
.album-panel > :first-child { margin-top: 0; }

/* Kartu menentukan tingginya sendiri. Grid yang meregang membuat kartu terpendek
   ("Tautan Privat Klien") berongga 269px di bawah isinya. Dibatasi pada panel
   album supaya grid Dashboard dan Admin tidak ikut berubah. */
.album-panel .grid { align-items: start; }

/* Kelas ini dipakai di 6 tempat pada album.php dan di /admin/settings, tetapi
   selama ini TIDAK punya aturan sama sekali — jarak antar-section terukur 0px
   sementara jarak antar-kartu di dalam grid 20px. Antar-blok harus lebih besar
   daripada di dalam blok, kalau tidak pengelompokannya tidak terbaca. */
.album-section { margin-top: var(--space-7); }
.album-panels:not(.is-tabbed) > .album-panel + .album-panel { margin-top: var(--space-7); }

/* Publikasi & arsip adalah tindakan tingkat-album, bukan isi sebuah tab. */
.album-page-actions {
  margin-top: var(--space-10);
  padding-top: var(--space-8);
  border-top: 1px solid var(--border-default);
}
.album-page-actions > :first-child { margin-top: 0; }
.album-page-actions:empty { display: none; }

@media (max-width: 899px) {
  .album-tabbar { flex-direction: column; align-items: stretch; gap: var(--space-3); }
  .album-tabbar__exit { justify-content: flex-end; }
  /* Gap 24px memakan lebar berharga di 375px dan membuat lebih banyak tab
     terdorong keluar layar. */
  .album-tabbar .workspace-tabs { gap: var(--space-5); }
}
@media (prefers-reduced-motion: reduce) {
  .photo-card__visual.is-loading .photo-card__skeleton { animation: none; opacity: 0.78; }
  .workspace-tab, .workspace-tab::after { transition: none; }
}

/* ---- Baris checkbox ----
   .field--check dipakai di 5 tempat (album.php, pengaturan tautan klien) tetapi
   TIDAK punya aturan sendiri: ia mewarisi .field { display:grid }, sehingga kotak
   centang dan labelnya menumpuk vertikal, dan .field input memberinya tinggi
   var(--field-h) + border + background — itulah kotak biru raksasa yang melayang
   jauh dari teksnya. */
.field--check {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: var(--field-h);
  cursor: pointer;
}
.field--check input[type="checkbox"] {
  flex: 0 0 auto;
  width: 17px;
  height: 17px;
  min-height: 0;
  margin: 0;
  padding: 0;
  border-radius: var(--radius-xs);
  accent-color: var(--primary);
  cursor: pointer;
}
.field--check span {
  font-size: 13.5px;
  font-weight: 500;
  color: var(--text-strong);
  line-height: 1.4;
}
/* Fieldset tanpa bingkai & padding bawaan UA: min-inline-size:min-content
   bawaannya membuat URL panjang mendorong halaman menggulir ke samping. */
.field-group { min-width: 0; margin: 0; padding: 0; border: 0; }
/* Fieldset identitas: baris centang berjajar rapat, bukan terpisah gap form. */
.field-group .field--check { min-height: 38px; }
.input-with-prefix { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; border: 1px solid var(--border-input); border-radius: var(--radius-xs); background: var(--surface-0); }
.input-with-prefix:focus-within { border-color: var(--border-strong); outline: 2px solid var(--border-strong); outline-offset: 2px; }
.input-with-prefix > span { padding-left: 10px; color: var(--text-muted); font: 500 13px var(--font-mono, monospace); }
.input-with-prefix input { min-width: 0; border: 0; background: transparent; }

/* =========================================================================
   PEMULIHAN — aturan spesifik aplikasi yang hilang dari app.css
   -------------------------------------------------------------------------
   Kelas-kelas di bawah dipakai di markup tetapi aturannya lenyap dari berkas
   ini, sehingga 6 halaman kehilangan tata letaknya: album workspace (editor
   kategori, danger zone, kartu tinta), direktori akun, detail respon, daftar
   respon, galeri klien, dan halaman branding. Nilainya dikembalikan persis
   seperti keadaan yang diketahui baik pada 22 Agustus 2026.
   Jangan hapus tanpa memindahkan aturannya ke tempat lain lebih dulu.
   ========================================================================= */

/* ---- Album workspace: editor kategori & kontrol tautan ---- */
.album-note { margin-top: 12px; font-size: 12px; overflow-wrap: anywhere; }
/* Keterangan di dalam kartu (pengganti style= inline di view): satu ukuran, satu warna. */
.card-note { margin: var(--space-3) 0 0; color: var(--text-muted); font-size: var(--text-xs); line-height: 1.5; overflow-wrap: anywhere; }
.card-note:first-child { margin-top: 0; }
.card-note strong { color: var(--text-strong); }
ol.card-note, ul.card-note { display: grid; gap: var(--space-2); padding-left: var(--space-6); }
.user-row__badges { gap: var(--space-2); }
.form-grid--compact { gap: 10px; }
.share-facts { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 14px; font-size: 12px; color: var(--text-muted); }
.share-facts span { display: inline-flex; align-items: center; gap: 6px; }
/* ---------------------------------------------------------------------------
   Kategori album = dua preset terkunci (Edit / Cetak), pengganti editor
   kategori nama-bebas.
   --------------------------------------------------------------------------- */
.rule-presets {
  display: grid;
  gap: 12px;
}
.rule-preset {
  padding: 14px 16px;
  border: 1px solid var(--border-default);
  border-radius: 0;
  background: var(--surface-1);
  transition: border-color .15s ease, background .15s ease;
}
/* Dua jalur untuk keadaan yang sama: kelas .is-on ditulis PHP (dan disegarkan
   JS saat diklik), :has() menanganinya kalau JS mati.

   SELEKTORNYA WAJIB menyebut .rule-preset__toggle. Kartu Cetak punya kotak
   centang KEDUA ("hanya dari foto Edit") di dalam blok tambahan, dan blok itu
   disembunyikan dengan display:none — yang TIDAK mengeluarkannya dari :has().
   Tanpa penyebutan itu, album yang menyimpan cermin menyala akan terlihat
   sebagai kategori aktif walau staf baru saja mematikannya. */
.rule-preset.is-on,
.rule-preset:has(.rule-preset__toggle input[type="checkbox"]:checked) {
  border-color: var(--ink-950);
  background: var(--surface-0);
}
.rule-preset__toggle {
  display: grid;
  grid-template-columns: auto auto 1fr;
  align-items: center;
  gap: 6px 10px;
  cursor: pointer;
}
.rule-preset__toggle input {
  grid-row: 1 / span 2;
  width: 20px;
  height: 20px;
  accent-color: var(--ink-950);
  cursor: pointer;
}
.rule-preset__icon { color: var(--text-strong); }
.rule-preset__name {
  font-size: 15px;
  font-weight: 700;
  color: var(--text-strong);
}
.rule-preset__hint {
  grid-column: 2 / -1;
  font-size: 12.5px;
  color: var(--text-muted);
}
.rule-preset__quota {
  margin-top: 12px;
  max-width: 360px;
}
/* Kuota hanya relevan saat kategorinya menyala; disembunyikan lewat :has()
   supaya tidak butuh JS, dan tetap terkirim apa adanya bila :has() tak didukung. */
.rule-preset:not(:has(.rule-preset__toggle input[type="checkbox"]:checked)) .rule-preset__quota {
  display: none;
}
/* Catatan mengikuti kotak centang, bukan keadaan tersimpan di database. */
.rule-preset:has(.rule-preset__toggle input[type="checkbox"]:checked) .rule-preset__note--off,
.rule-preset:not(:has(.rule-preset__toggle input[type="checkbox"]:checked)) .rule-preset__note--on {
  display: none;
}
.rule-preset__note {
  margin: 10px 0 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-muted);
}
.rule-preset__note strong { color: var(--text-strong); }

.rule-legacy {
  margin-top: 24px;
  padding-top: 20px;
  border-top: 1px solid var(--border-default);
}
.rule-legacy h3 { margin: 0 0 4px; font-size: 15px; }
.rule-legacy > p { margin: 0 0 12px; font-size: 12.5px; color: var(--text-muted); }
.rule-legacy__row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  border: 1px solid var(--border-default);
  border-radius: 0;
  background: var(--surface-1);
}
.rule-legacy__row + .rule-legacy__row { margin-top: 8px; }
.rule-legacy__name { font-weight: 600; }
.rule-legacy__quota { margin-left: auto; font-size: 11.5px; color: var(--text-muted); }

.wizard-card__section {
  margin-top: 24px;
  padding-top: 20px;
  border-top: 1px solid var(--border-default);
}
.wizard-card__section h3 { margin: 0 0 4px; font-size: 15px; }

/* Zona arsip: garis & judul bernada bahaya supaya tidak tertukar dengan kartu biasa. */
.danger-zone { border-color: var(--tag-danger-border); }
.danger-zone .surface-card__header h2 { color: var(--tag-danger-text); }
.status-note { margin: -2px 0 6px; font-size: var(--text-2xs); line-height: 1.5; color: var(--text-muted); overflow-wrap: anywhere; }

/* ---- Daftar respon ---- */
.filter-bar--single { justify-content: flex-start; gap: 14px; }

/* ---- Direktori akun & serah-terima kredensial ---- */
/* Kartu sekali-tampil (tautan undangan, kata sandi sementara) harus menonjol
   dari kartu biasa; di kanvas putih garis hairline saja tidak terbaca. */
.handoff-card { margin-bottom: 20px; border-color: var(--border-strong); }
.handoff-card__note { margin-top: 12px; font-size: 12px; }
.handoff-card__secret { font-size: 16px; letter-spacing: .06em; }
.admin-users-grid { align-items: start; }
.user-row { flex-wrap: wrap; }
.user-row__actions { display: flex; flex-wrap: wrap; gap: 8px; }
.user-row__self { font-size: 12px; }
/* Tautan dalam teks 12px: tinggi 24px memenuhi target minimum WCAG 2.5.8. */
.user-row__self a { display: inline-flex; align-items: center; min-height: 24px; text-decoration: underline; }

/* ---- Galeri klien ---- */
.submitted-summary { display: grid; gap: 8px; margin-top: 20px; }
.submitted-group { border-top: 1px solid var(--border-default); }
.submitted-group:last-child { border-bottom: 1px solid var(--border-default); }
.submitted-group__summary {
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 12px 0;
  cursor: pointer;
  font-weight: 600;
  list-style: none;
}
.submitted-group__summary::-webkit-details-marker { display: none; }
.submitted-group__summary::after {
  content: '+';
  margin-left: auto;
  color: var(--text-subtle);
  font: 700 16px/1 var(--font-mono);
}
.submitted-group[open] .submitted-group__summary::after { content: '−'; }
.submitted-group .filename-list { margin: 0 0 12px; }
.viewer__actions { display: flex; align-items: center; gap: 10px; }
.viewer__close { margin-left: auto; }
.review-drawer__validation { margin: 0; }
.review-drawer__validation[hidden] { display: none; }

@media (max-width: 899px) {
  .user-row__actions { width: 100%; }
  .user-row__actions form, .user-row__actions .vs-btn { width: 100%; }
}

/* ===========================================================================
   GALERI KLIEN — PEMBARUAN SELEKSI (redesign 2 Sep 2026)

   Blok ini melanjutkan perbaikan di dalam blok .photo-card di atas. Aturan di
   sini SENGAJA tidak mengandung satu pun deklarasi `display` pada
   `.photo-card.<class>`: `.photo-card[hidden] { display: none }` menang atas
   `.photo-card.is-broken` hanya karena urutan penulisan, dan satu aturan
   display baru di bawahnya akan mematikan SELURUH filter tanpa pesan galat.
   =========================================================================== */

/* Overlay tidak boleh ikut dipotong lebar halaman. `.page-main > *` memberi
   max-width: var(--app-max) kepada SEMUA anak langsung — termasuk elemen fixed
   seperti lightbox dan drawer, yang lalu berhenti di 1360px dengan pita hitam
   di kiri-kanan pada layar lebar. */
.page-main > .viewer,
.page-main > .review-drawer {
  max-width: none;
  margin-inline: 0;
}

/* Judul album panjang membuat halaman bisa digulir ke samping: h1 sudah punya
   ellipsis, tapi pembungkusnya di dalam flex tidak boleh menyusut tanpa
   min-width: 0. Luapan itu juga yang membuat dock ikut melebar melewati layar. */
.gallery-topbar__copy > div {
  min-width: 0;
}
.gallery-topbar__sub {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* left/right sudah menentukan lebarnya; width: 100% hanya menambah satu sumber
   kesalahan saat halaman punya luapan horizontal. */
.gallery-progress {
  width: auto;
}

/* Cadangan ruang untuk dock juga dipakai saat menggulir ke elemen ber-anchor. */
/* scroll-padding hanya berlaku pada scroll container. Di halaman ini scroll
   container-nya adalah viewport, yang membaca propertinya dari elemen AKAR —
   memasangnya di <body> tidak berpengaruh apa pun. */
html:has(body.is-album-public) {
  scroll-padding-bottom: calc(var(--dock-h, 96px) + 16px);
}

/* Album tanpa foto: sebelumnya galeri kosong tanpa satu kata pun. */
.gallery-empty {
  display: grid;
  justify-items: center;
  gap: 8px;
  padding: 56px 24px;
  border: 1px solid var(--border-default);
  color: var(--text-muted);
  text-align: center;
}
.gallery-empty strong { color: var(--text-strong); font-size: 15px; }
.gallery-empty span { font-size: 13px; max-width: 34ch; }

/* Atribut `hidden` KALAH dari display eksplisit. Ketiga elemen ini disembunyikan
   lewat el.hidden = true di app.js, jadi tanpa aturan di bawah ini mereka tetap
   tampil — termasuk toast yang seharusnya menghilang sendiri setelah 3,4 detik. */
.toast[hidden],
.gallery-empty[hidden],
.gallery-loader[hidden],
.gallery-sentinel__retry[hidden],
.gallery-sentinel__manual[hidden] {
  display: none !important;
}

/* Sentinel: pesan gagal-muat dan tombol muat manual belum pernah punya gaya. */
.gallery-sentinel__retry,
.gallery-sentinel__manual {
  display: grid;
  justify-items: center;
  gap: 10px;
  padding: 18px 16px;
  border: 1px solid var(--border-default);
  background: var(--surface-0);
}
.gallery-sentinel__manual span {
  font-size: 12.5px;
  color: var(--text-muted);
}

/* Cincin fokus khusus permukaan klien.
   Cincin bawaan base.css memakai --shadow-focus yang hanya 1.37:1 di putih
   (gagal SC 1.4.11), jadi permukaan klien memasang cincinnya sendiri.
   Outline INSET dipakai karena wadah kartu ber-overflow hidden akan memotong
   cincin di luar tepi. */
/* Cincin dipilih menurut LATAR yang ditimpanya, bukan satu warna untuk semua:
   kuning di atas tombol yang sudah kuning (.is-selected, CTA dock) menghasilkan
   1,0:1 — cincin yang secara harfiah tidak ada. */
body.is-album-public .photo-card__rule:focus-visible,
body.is-album-public .filter-tab:focus-visible,
body.is-album-public .gallery-progress__cta:focus-visible {
  outline: 2px solid var(--ink-950);
  outline-offset: -2px;
}
/* Di lightbox latarnya hitam, jadi di sanalah kuning justru paling terbaca —
   kecuali pada tombol yang sudah terpilih (kuning), yang kembali ke hitam. */
body.is-album-public .viewer__rule-btn:focus-visible,
body.is-album-public .viewer .icon-btn:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: -2px;
}
body.is-album-public .viewer__rule-btn.is-selected:focus-visible {
  outline-color: var(--ink-950);
}
body.is-album-public .icon-btn:focus-visible {
  outline: 2px solid var(--ink-950);
  outline-offset: -2px;
}
/* Ubin foto: cincinnya digambar lewat ::after, BUKAN box-shadow inset — inset
   dilukis di bawah anak elemen, jadi <img> yang mengisi penuh kotak akan
   menutupinya sepenuhnya (jebakan yang sama yang membuat penanda "terpilih"
   lama tidak pernah terlihat). */
body.is-album-public .photo-card__visual:focus-visible {
  outline: none;
}
body.is-album-public .photo-card__visual:focus-visible::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 6;
  pointer-events: none;
  border: 3px solid var(--brand);
  box-shadow: inset 0 0 0 2px rgba(2, 2, 2, .9), 0 0 0 1px rgba(2, 2, 2, .9) inset;
}

/* Ketukan di iOS tidak perlu kotak abu besar di atas foto. */
body.is-album-public .photo-card__visual,
body.is-album-public .photo-card__rule {
  -webkit-tap-highlight-color: transparent;
}

/* Toast galeri: muncul DI ATAS dock, bukan di pojok kanan atas yang tidak
   terlihat saat jempol sedang bekerja di bagian bawah layar. */
.toast--gallery {
  top: auto;
  right: max(16px, 4vw);
  left: max(16px, 4vw);
  bottom: calc(var(--dock-h, 96px) + 12px);
  /* Di atas lightbox (z-index 60) dan drawer (70), dan TIDAK menangkap ketukan:
     sebagai overlay selebar layar selama 3,4 detik ia akan menelan ketukan pada
     kartu di bawahnya. */
  z-index: 90;
  pointer-events: none;
  max-width: none;
  /* Tanpa garis kuning di pinggir (aturan owner); latar gelap sudah cukup
     membedakan toast ini dari kartu foto di belakangnya. */
  border: 1px solid var(--ink-950);
  background: var(--ink-950);
  color: #FFFFFF;
  font-size: 13px;
  animation: toastRise .18s ease-out;
}
@keyframes toastRise {
  from { transform: translateY(10px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

/* ------------------------------- LIGHTBOX -------------------------------- */

/* 100vh membuat gambar terpotong ketika bilah URL Safari muncul; dvh mengikuti
   tinggi yang benar-benar terlihat. */
.viewer__image-wrapper {
  max-height: calc(100dvh - 196px);
}
.viewer__bottombar {
  gap: 12px;
  padding-bottom: calc(24px + env(safe-area-inset-bottom, 0px));
}
.viewer__info {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
}
.viewer__actions {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 8px;
}
/* Kelas ini sebelumnya dipakai di markup tanpa satu pun aturan CSS, dan
   .vs-btn--sm yang menggantikannya hanya 36px — di bawah minimum sentuh. */
.viewer__rule-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 16px;
  border: 1px solid rgba(255, 255, 255, 0.38);
  border-radius: 0;
  background: transparent;
  color: #FFFFFF;
  font: 600 13px/1 var(--font-body);
  cursor: pointer;
  transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.viewer__rule-btn:hover { background: rgba(255, 255, 255, 0.14); }
/* Satu kosakata warna: "terpilih" itu kuning brand di grid MAUPUN di lightbox.
   Sebelumnya lightbox memakai .vs-btn--primary yang hitam. */
.viewer__rule-btn.is-selected {
  border-color: var(--brand);
  background: var(--brand);
  color: var(--brand-ink);
}
/* Gambar berikutnya belum tentu selesai diunduh saat counter sudah berpindah;
   tanpa penanda ini klien melihat foto SEBELUMNYA sambil membaca nomor baru. */
.viewer__image-wrapper.is-loading .viewer__image { opacity: .25; }
.viewer__image { transition: opacity .12s ease; }

@media (max-width: 767px) {
  .viewer__bottombar {
    flex-wrap: wrap;
    padding: 12px 16px calc(16px + env(safe-area-inset-bottom, 0px));
  }
  .viewer__info { flex: 1 1 100%; }
  .viewer__actions { flex: 1 1 100%; justify-content: stretch; }
  .viewer__rule-btn { flex: 1 1 0; min-width: 0; }
  .viewer__rule-btn span {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  /* Panah 52px di kiri-kanan menutup 29% lebar foto di HP; geser sudah jadi
     gestur utamanya. */
  .viewer__nav { width: 44px; height: 44px; background: rgba(255, 255, 255, 0.10); }
  .viewer__nav--prev { left: 4px; }
  .viewer__nav--next { right: 4px; }
  .viewer__image-wrapper { max-height: calc(100dvh - 230px); }
}

/* =========================================================================
   CETAK — turunan Edit + ukuran cetak (10 Sep 2026)
   -------------------------------------------------------------------------
   Dua permukaan:
     1. composer di halaman staf (.rule-preset__extra, .rule-sizes)
     2. lembar ukuran di galeri klien (.size-sheet)
   Konvensi berkas ini diikuti apa adanya: warna/radius/bayangan lewat token,
   jarak dan ukuran huruf px seperti tetangganya. Jangan "membetulkan" salah
   satunya sendirian — hasilnya blok ini jadi satu-satunya yang berbeda.
   ========================================================================= */

/* Blok tambahan mengikuti kotak centang kategorinya, persis seperti kolom
   kuota. Dua jalur lagi: .is-on ditulis PHP/JS, :has() menanganinya tanpa JS. */
.rule-preset:not(:has(.rule-preset__toggle input[type="checkbox"]:checked)) .rule-preset__extra {
  display: none;
}
.rule-preset__extra {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--border-default);
  display: grid;
  gap: 14px;
}

/* Baris centang dua baris: judul tebal + penjelasan. .field--check tidak dipakai
   karena ia memaksa satu baris (align-items:center + min-height field). */
.rule-preset__check {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: 10px;
  cursor: pointer;
}
.rule-preset__check input[type="checkbox"] {
  width: 17px;
  height: 17px;
  margin: 2px 0 0;
  border-radius: var(--radius-xs);
  accent-color: var(--primary);
  cursor: pointer;
}
.rule-preset__check strong {
  display: block;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text-strong);
}
.rule-preset__check small {
  display: block;
  margin-top: 3px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-muted);
}

.rule-sizes {
  display: grid;
  gap: 10px;
}
.rule-sizes__head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: 8px;
  color: var(--text-strong);
}
.rule-sizes__head strong {
  display: block;
  font-size: 13.5px;
  font-weight: 600;
}
.rule-sizes__head small {
  display: block;
  margin-top: 3px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-muted);
}
.rule-sizes__list {
  display: grid;
  gap: 8px;
}
.rule-sizes__list:empty {
  display: none;
}
/* Baris komposit: nama melar, dua kolom angka tetap, tombol hapus tetap.
   minmax(0,1fr) — bukan 1fr — supaya nama panjang memendek, bukan mendorong
   kolom angka keluar kartu. Baris dipisah garis rambut, bukan kotak ketiga
   di dalam kartu preset di dalam kartu halaman. */
.rule-size {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 84px 84px auto;
  align-items: end;
  gap: 8px;
  padding: 10px 0;
  border: 0;
  border-top: 1px solid var(--border-default);
  border-radius: 0;
  background: transparent;
}
.rule-size .field { gap: 5px; }
.rule-size .field label {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-muted);
}
.rule-size__remove {
  align-self: end;
  width: var(--field-h);
  height: var(--field-h);
  color: var(--text-muted);
}
.rule-size__remove:hover {
  color: var(--accent-red);
}
.rule-size__note {
  grid-column: 1 / -1;
  margin: 2px 0 0;
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--text-muted);
}
.rule-size__note strong { color: var(--text-strong); }
.rule-sizes__empty {
  margin: 0;
  font-size: 12px;
  color: var(--text-muted);
}
.rule-sizes__add { justify-self: start; }

@media (max-width: 720px) {
  /* Dua kolom angka 84px + tombol tidak muat berdampingan dengan nama di
     layar sempit; namanya naik ke barisnya sendiri. */
  .rule-size {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
  }
  .rule-size__label { grid-column: 1 / -1; }
}

/* ---- Galeri klien: penanda ukuran di atas foto ---- */
/* Ukuran dibedakan dengan TEKS, bukan ikon. Ikon 14px tidak bisa membedakan
   "36R" dari "16RS", dan itu satu-satunya hal yang perlu dibaca klien di sini. */
.photo-card__badge--text {
  width: auto;
  min-width: 24px;
  padding: 0 5px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .02em;
  line-height: 24px;
}

/* Tombol kategori yang terkunci karena fotonya belum dipilih di Edit.
   Bentuknya SAMA dengan kunci kuota (.is-locked) supaya klien tidak perlu
   belajar dua bahasa visual untuk satu arti: "belum bisa sekarang". */
.photo-card__rule.is-blocked,
.viewer__rule-btn.is-blocked {
  opacity: .45;
  cursor: not-allowed;
}

/* ---- Lembar ukuran cetak ---- */
.size-sheet {
  position: fixed;
  inset: 0;
  /* Di atas lightbox (60) dan drawer ringkasan (70), di bawah toast (80) —
     pesan "kuota penuh" harus tetap terbaca di atas lembar ini. */
  z-index: 75;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}
.size-sheet[hidden] { display: none !important; }
.size-sheet__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.65);
}
.size-sheet__panel {
  position: relative;
  z-index: 2;
  width: min(100%, 460px);
  max-height: min(86dvh, 680px);
  display: flex;
  flex-direction: column;
  background: var(--surface-0);
  border-radius: var(--radius-md) var(--radius-md) 0 0;
  box-shadow: var(--shadow-modal);
  animation: sizeSheetIn 0.24s var(--ease-spring);
}
@keyframes sizeSheetIn {
  from { transform: translateY(100%); }
  to { transform: translateY(0); }
}
.size-sheet__header {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  gap: 12px;
  padding: 18px 18px 14px;
  border-bottom: 1px solid var(--border-default);
}
.size-sheet__header h2 {
  margin: 0;
  font-size: 17px;
  font-weight: 700;
  color: var(--text-strong);
}
.size-sheet__filename {
  display: block;
  margin-top: 3px;
  font-size: 12px;
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.size-sheet__body {
  padding: 12px 18px 16px;
  overflow-y: auto;
  display: grid;
  gap: 8px;
}
.size-sheet__note {
  margin: 0 0 4px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-muted);
}
/* Baris ukuran: penanda pilih | nama + kuota | jumlah. */
.size-option {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 12px 14px;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sm);
  background: var(--surface-1);
  color: var(--text-body);
  text-align: left;
  cursor: pointer;
}
.size-option:hover { background: var(--surface-0); }
.size-option.is-selected {
  border-color: var(--border-strong);
  background: var(--brand-soft);
  color: var(--text-strong);
}
.size-option.is-locked {
  opacity: .5;
  cursor: not-allowed;
}
.size-option__mark {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border: 1px solid var(--border-input);
  border-radius: var(--radius-xs);
  background: var(--surface-0);
  color: transparent;
}
.size-option.is-selected .size-option__mark {
  border-color: var(--border-strong);
  background: var(--primary);
  color: var(--primary-contrast);
}
.size-option__name {
  display: block;
  font-size: 14px;
  font-weight: 600;
  color: var(--text-strong);
  overflow-wrap: anywhere;
}
.size-option__hint {
  display: block;
  margin-top: 2px;
  font-size: 11.5px;
  color: var(--text-muted);
}
.size-option__count {
  font-size: 12px;
  font-weight: 700;
  color: var(--text-muted);
  white-space: nowrap;
}
.size-option.is-selected .size-option__count { color: var(--text-strong); }
.size-sheet__footer {
  padding: 12px 18px calc(16px + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--border-default);
}

/* Catatan "jatah induk tidak dipakai" duduk tepat di bawah kolom kuota yang
   sedang dinonaktifkan, bukan di antara blok-blok berikutnya. */
.rule-preset__quota-note {
  margin-top: 8px;
}
/* Ikut sembunyi bersama kolom kuota yang dijelaskannya. */
.rule-preset:not(:has(.rule-preset__toggle input[type="checkbox"]:checked)) .rule-preset__quota-note {
  display: none;
}

/* Ukuran cetak di halaman awal klien: baris anak dari kategori di atasnya.
   Menjorok + garis pemisah lebih samar, supaya terbaca sebagai rincian jatah
   kategori induknya dan bukan sebagai kategori keempat yang berdiri sendiri. */
.landing-rule--child {
  padding: 10px 0 10px 18px;
  border-top-color: var(--border-faint);
}
.landing-rule--child strong {
  font-size: 13px;
  font-weight: 500;
  color: var(--text-body);
}

/* Peringatan yang menuntut keputusan staf, bukan sekadar keterangan. Warna
   hanya di isian dan garisnya — bukan garis warna di pinggir baris. Nada
   peringatan yang sama dengan .drive-callout--warn; kuning tinggal di logo. */
.rule-preset__note--warn {
  padding: 10px 12px;
  border: 1px solid var(--tag-warning-border);
  border-radius: 0;
  background: var(--tag-warning-bg);
  color: var(--text-body);
}

/* ========================================================================
   VPLUS ALBUM EXPERIENCE — FRONTEND PHASE
   White editorial surface, deliberate photo-first hierarchy, no new runtime
   dependency. These selectors are scoped to the new public preview and
   onboarding surfaces so the existing selection state machine stays intact.
   ======================================================================== */

body.is-public,
body.is-album-public {
  background: var(--vs-white);
  color: var(--text-body);
}

body.is-public .public-topbar {
  min-height: 72px;
  padding-inline: clamp(20px, 5vw, 64px);
  background: var(--vs-white);
  border-bottom: 1px solid var(--line-100);
}

.onboarding-strip {
  display: grid;
  grid-template-columns: minmax(210px, .75fr) minmax(0, 1.75fr);
  gap: 32px;
  margin: 0 0 36px;
  padding: 24px 0 28px;
  border-top: 1px solid var(--border-default);
  border-bottom: 1px solid var(--border-default);
}

.onboarding-strip__intro { display: grid; align-content: start; gap: 8px; }
.onboarding-strip__intro h2 { font-size: 22px; letter-spacing: -.03em; }
.onboarding-strip__intro p { max-width: 30ch; color: var(--text-muted); font-size: 13px; line-height: 1.5; }
.onboarding-strip__steps { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0; margin: 0; padding: 0; list-style: none; }
.onboarding-strip__steps li { min-width: 0; border-left: 1px solid var(--border-default); }
.onboarding-strip__steps a { display: grid; gap: 9px; min-height: 112px; padding: 0 16px; color: inherit; transition: background .18s ease; }
.onboarding-strip__steps a:hover { background: var(--bg-subtle); }
.onboarding-strip__steps span { color: var(--text-muted); font: 600 11px var(--font-mono); }
.onboarding-strip__steps strong { color: var(--text-strong); font-size: 13px; }
.onboarding-strip__steps small { color: var(--text-muted); font-size: 12px; line-height: 1.45; }

/* Client entry */
body.is-album-public .page-main--public { background: var(--vs-white); }
body.is-album-public .gallery-landing { width: min(100%, 1240px); gap: clamp(36px, 8vw, 120px); padding: clamp(40px, 7vw, 96px) clamp(20px, 5vw, 64px) 72px; }
body.is-album-public .gallery-landing__copy { gap: 18px; }
.client-entry-byline { color: var(--text-subtle); font: 500 11px var(--font-mono); letter-spacing: .04em; text-transform: uppercase; }
body.is-album-public .gallery-landing__copy h1 { max-width: 11ch; font-size: clamp(42px, 7vw, 78px); line-height: .98; letter-spacing: -.055em; }
body.is-album-public .gallery-landing__copy p { max-width: 50ch; font-size: 16px; }
body.is-album-public .gallery-landing__visual { min-height: 0; aspect-ratio: 4 / 5; max-height: 700px; border: 0; background: var(--surface-1); }
body.is-album-public .gallery-landing__visual img { opacity: 1; object-position: center; }
.client-entry-actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.client-entry-actions form { margin: 0; }
.client-entry-actions .vs-btn { min-width: 150px; }
/* The existing selection state machine remains intact; the visual hierarchy is
   changed here without changing its data attributes or request behavior. */
body.is-album-public .gallery-shell { --gallery-gap: 12px; background: var(--vs-white); }
body.is-album-public .gallery-topbar { padding-top: 12px; background: rgba(255,255,255,.96); border-bottom-color: var(--line-200); }
body.is-album-public .gallery-guidance { background: var(--vs-white); }
body.is-album-public .gallery-grid { grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: var(--gallery-gap); padding-top: 18px; }
body.is-album-public .photo-card__visual { border-color: var(--line-200); background: var(--surface-1); }
body.is-album-public .photo-card__actions { background: var(--vs-white); border-color: var(--line-200); }
body.is-album-public .photo-card__rule { min-height: 44px; border-color: var(--line-100); border-radius: 0; }
body.is-album-public .photo-card__filename { padding-top: 8px; color: var(--text-subtle); font-size: 10px; }

@media (max-width: 1023px) {
  .onboarding-strip { grid-template-columns: 1fr; gap: 24px; }
}

@media (max-width: 767px) {
  .onboarding-strip { margin-bottom: 28px; }
  .onboarding-strip__steps { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px 0; }
  .onboarding-strip__steps li:nth-child(odd) { border-left: 0; }
  .onboarding-strip__steps a { padding: 0 12px; }
  .onboarding-strip__steps li:nth-child(even) a { padding-right: 0; }
  body.is-album-public .gallery-landing { padding-top: 0; padding-inline: 0; }
  body.is-album-public .gallery-landing__visual { order: -1; width: 100%; aspect-ratio: 4 / 3; max-height: none; }
  body.is-album-public .gallery-landing__copy { padding: 30px 20px 42px; }
  body.is-album-public .gallery-landing__copy h1 { max-width: 9ch; font-size: clamp(42px, 13vw, 64px); }
  .client-entry-actions { display: grid; grid-template-columns: 1fr 1fr; }
  .client-entry-actions form, .client-entry-actions .vs-btn { width: 100%; min-width: 0; }
  body.is-album-public .gallery-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
}

@media (max-width: 479px) {
  .onboarding-strip__steps a { min-height: 128px; padding-inline: 0 10px; }
  .onboarding-strip__steps li:nth-child(even) a { padding-left: 10px; }
  .client-entry-actions { grid-template-columns: 1fr; }
  .client-entry-actions .vs-btn { min-height: 48px; }
}


/* ===== Album Experience: form creator (jenis album, panel Tampilan, identitas studio) ===== */
.purpose-choice { display: grid; gap: var(--space-3); margin: 0 0 var(--space-7); padding: 0; border: 0; }
.purpose-choice legend, .look-group legend { padding: 0; margin-bottom: var(--space-3); color: var(--text-strong); font: 600 14px var(--font-body); }
.purpose-choice legend span { color: var(--text-muted); font-weight: 400; }
.purpose-option, .look-option { display: flex; align-items: flex-start; gap: var(--space-4); min-height: 44px; padding: var(--space-4) var(--space-5); border: 1px solid var(--border-default); cursor: pointer; }
.purpose-option:has(input:checked), .look-option:has(input:checked) { border-color: var(--text-strong); background: var(--bg-subtle); }
.purpose-option:focus-within, .look-option:focus-within, .look-tile label:focus-within { outline: 2px solid var(--text-strong); outline-offset: 2px; }
.purpose-option input, .look-option input { margin-top: 3px; flex-shrink: 0; }
.purpose-option strong, .look-option strong { display: block; color: var(--text-strong); font-size: 14px; }
.purpose-option small, .look-option small, .look-layout small { display: block; margin-top: 2px; color: var(--text-muted); font-size: 13px; line-height: 1.5; }
.purpose-choice__note, .look-help { margin: 0; color: var(--text-muted); font-size: 13px; line-height: 1.55; }
.look-group { display: grid; gap: var(--space-4); margin: 0; padding: var(--space-6) 0 0; border: 0; border-top: 1px solid var(--border-default); min-width: 0; }
.look-options { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--space-3); }
/* Padding >= cincin fokus (2px + offset 2px) supaya outline ubin tidak terpotong tepi gulir. */
.look-picker { display: grid; grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); gap: var(--space-3); max-height: 520px; padding: var(--space-3); overflow-y: auto; border: 1px solid var(--border-default); }
.look-tile label:has(input:disabled) { color: var(--text-disabled); cursor: not-allowed; }
.look-tile { display: grid; gap: 0; min-width: 0; border: 1px solid var(--border-default); }
.look-tile:has([data-hero-check]:checked), .look-tile:has(input[type=radio]:checked) { border-color: var(--text-strong); }
.look-tile img { display: block; width: 100%; aspect-ratio: 1; object-fit: cover; background: var(--bg-subtle); }
.look-tile label, .look-inline { display: flex; align-items: center; gap: var(--space-3); min-height: 44px; padding: 0 var(--space-3); font-size: 13px; cursor: pointer; }
.look-tile label + label { border-top: 1px solid var(--border-default); }
.hero-order { display: grid; gap: var(--space-2); margin: 0; padding: 0; list-style: none; counter-reset: hero; }
.hero-order:empty { display: none; }
.hero-order__item { display: grid; grid-template-columns: auto 56px minmax(0, 1fr) 44px 44px; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-3); border: 1px solid var(--border-default); background: var(--bg-subtle); cursor: grab; counter-increment: hero; }
.hero-order__item::before { content: counter(hero); width: 20px; color: var(--text-muted); font: 600 12px var(--font-mono); text-align: center; }
.hero-order__item img { width: 56px; height: 56px; object-fit: cover; }
.hero-order__name { overflow: hidden; font: 500 12px var(--font-mono); text-overflow: ellipsis; white-space: nowrap; }
.look-layouts { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--space-3); }
.look-layout { display: grid; gap: var(--space-2); padding: var(--space-4) var(--space-5); border: 1px solid var(--border-default); }
.look-layout label { display: flex; align-items: center; gap: var(--space-3); min-height: 44px; font-size: 14px; cursor: pointer; }
.brand-logo-preview { display: inline-grid; place-items: center; width: fit-content; max-width: 100%; padding: var(--space-4); border: 1px solid var(--border-default); background: var(--vs-white); }
.brand-logo-preview img { max-width: 220px; max-height: 72px; object-fit: contain; }
.onboarding-strip__steps li.is-done strong { color: var(--text-muted); text-decoration: line-through; }

/* =========================================================================
   LAYAR LOGIN: TEMA PUTIH (22 Sep 2026)
   Token putihnya ada di colors.css (body.is-app). Aturan di bawah memindahkan
   komponen bersama ke nada yang lolos AA di atas putih. Semuanya di-scope
   body.is-app, jadi halaman tamu (body.is-public) tidak berubah.
   ========================================================================= */

/* --text-subtle #777D88 = 4.14:1 di putih, gagal untuk teks kecil. Teks
   sekunder memakai --text-muted; --text-subtle tinggal untuk ikon. */
body.is-app .eyebrow,
body.is-app .vs-kicker {
  font-size: var(--text-2xs);
  letter-spacing: var(--ls-label);
  color: var(--text-muted);
}
body.is-app .field label span,
body.is-app .field small,
body.is-app .text-subtle {
  color: var(--text-muted);
}
/* Tanda buka/tutup grup respons: 16px tebal belum masuk "teks besar" (18,66px),
   jadi ikut ambang 4,5:1. --text-subtle #777D88 hanya 4,14:1 di putih. */
body.is-app .submitted-group__summary::after {
  color: var(--text-muted);
}
/* Belum ada token abu yang lebih terang namun tetap >= 4.5:1; placeholder
   memakai --text-muted dan contoh diawali "Contoh:" di markup. */
body.is-app .field input::placeholder,
body.is-app .field textarea::placeholder,
body.is-app .search-field input::placeholder {
  color: var(--text-muted);
  opacity: 1;
}

/* Tautan di dalam kalimat perlu penanda selain tebal huruf. */
body.is-app .status-note a,
body.is-app .album-note a,
body.is-app .activity-row__copy a {
  color: var(--text-strong);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Tautan lewati-konten diparkir di atas layar, tapi --shadow-modal-nya masih
   merembes jadi noda abu di tepi atas tiap halaman. Layar login rata. */
body.is-app .skip-link {
  box-shadow: none;
}

/* Kontrol: satu radius (--radius-xs) untuk tombol, input, dan pencarian. */
body.is-app .vs-btn,
body.is-app .search-field input {
  border-radius: var(--radius-xs);
}
/* Batas tombol sekunder 1.23:1 dengan --border-default di putih; primitive
   Button DS memakai --border-input. Hover tetap garis tinta (boxy). */
body.is-app .vs-btn--secondary {
  border-color: var(--border-input);
}
body.is-app .vs-btn--secondary:hover {
  border-color: var(--border-strong);
}
/* Hover netral: token abu dingin, bukan hitam transparan. Di-scope supaya
   halaman tamu tetap memakai rgba(0,0,0,0.05) seperti sebelum sesi ini. */
body.is-app .icon-btn:hover,
body.is-app .vs-btn--ghost:hover {
  background: var(--bg-inset);
}
body.is-app .vs-btn:disabled,
body.is-app .icon-btn:disabled {
  color: var(--text-disabled);
  cursor: not-allowed;
}
body.is-app .vs-btn--primary:disabled {
  background: var(--bg-inset);
  border-color: var(--border-default);
}
body.is-app form[aria-busy="true"] {
  cursor: progress;
}
/* Tombol yang sedang memproses BUKAN tombol mati: labelnya ("Menyinkronkan…")
   satu-satunya tanda proses, jadi harus tetap terbaca (--text-muted #3A3D45 di
   atas --bg-inset #F2F4F7 = 9,86:1; di atas putih 10,86:1). */
body.is-app form[aria-busy="true"] .vs-btn:disabled {
  color: var(--text-muted);
  cursor: progress;
}

/* Badge status: isian triad --tag-* (teks lolos AA di atas isiannya),
   sudut --radius-xs, tanpa huruf kapital bertracking. Titik mengikuti warna teks. */
body.is-app .status-badge {
  border: 1px solid var(--tag-neutral-border);
  border-radius: var(--radius-xs);
  background: var(--tag-neutral-bg);
  color: var(--tag-neutral-text);
  font: var(--fw-semibold) var(--text-2xs) var(--font-mono);
  letter-spacing: var(--ls-normal);
  text-transform: none;
}
body.is-app .status-badge::before {
  background: currentColor;
}
body.is-app .status-badge--live,
body.is-app .status-badge--processed {
  background: var(--tag-success-bg);
  border-color: var(--tag-success-border);
  color: var(--tag-success-text);
}
body.is-app .status-badge--submitted {
  background: var(--tag-warning-bg);
  border-color: var(--tag-warning-border);
  color: var(--tag-warning-text);
}
body.is-app .status-badge--danger {
  background: var(--tag-danger-bg);
  border-color: var(--tag-danger-border);
  color: var(--tag-danger-text);
}
/* Kredensial sekali tampil (undangan, sandi sementara, tautan buka ulang). */
body.is-app .status-badge--identity {
  background: var(--tag-identity-bg);
  border-color: var(--tag-identity-border);
  color: var(--tag-identity-text);
}
body.is-app .tag {
  border-radius: var(--radius-xs);
}

/* Galat di layar login: triad bahaya (5.16:1), bukan merah aksen 3.77:1. */
body.is-app .inline-error {
  background: var(--tag-danger-bg);
  border-color: var(--tag-danger-border);
  color: var(--tag-danger-text);
}

/* Toast: nada dibawa isian + garis penuh, bukan garis warna di kiri.
   Tanpa bayangan: toast bukan lapisan di atas scrim. */
body.is-app .toast {
  border: 1px solid var(--border-strong);
  box-shadow: none;
}
body.is-app .toast--success {
  background: var(--tag-success-bg);
  border-color: var(--tag-success-border);
  color: var(--tag-success-text);
}
body.is-app .toast--error {
  background: var(--tag-danger-bg);
  border-color: var(--tag-danger-border);
  color: var(--tag-danger-text);
}

/* Pemisah baris di dalam kartu putih: --border-faint (#F0F2F5) hanya 1.12:1,
   praktis tak terlihat. --border-faint tinggal untuk sub-pemisah. */
body.is-app .hairline-list > *,
body.is-app .response-row,
body.is-app .detail-stat,
body.is-app .selection-group,
body.is-app .album-card__footer {
  border-color: var(--border-default);
}

/* Nama berkas pilihan klien dibaca utuh, tidak dipotong elipsis. */
body.is-app .filename {
  overflow: visible;
  text-overflow: clip;
  white-space: normal;
  overflow-wrap: anywhere;
}

/* ---- Modal "Pilih Folder Google Drive" (dibangun app.js) ----
   Pola .size-sheet: lapisan fixed, scrim, kartu --radius-md + --shadow-modal
   (satu-satunya bayangan yang diizinkan: lapisan di atas scrim). */
body.drive-modal-open { overflow: hidden; }
.drive-folder-modal {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: grid;
  place-items: center;
  padding: var(--space-5);
}
.drive-folder-modal__backdrop {
  position: absolute;
  inset: 0;
  /* Nilai scrim yang sama dengan .nav-scrim; token scrim menunggu keputusan owner. */
  background: rgba(0, 0, 0, 0.55);
}
.drive-folder-modal__card {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  width: min(100%, 560px);
  max-height: calc(100dvh - 32px);
  overflow: hidden;
  background: var(--surface-0);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-modal);
}
.drive-folder-modal__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-6) var(--space-6) var(--space-5);
  border-bottom: 1px solid var(--border-default);
}
.drive-folder-modal__header h2,
.drive-folder-modal__header h3 {
  font-size: var(--text-lg);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-display);
  color: var(--text-strong);
}
.drive-folder-modal__header p {
  margin-top: var(--space-2);
  color: var(--text-muted);
  font-size: var(--text-xs);
  line-height: 1.5;
}
.drive-folder-modal__header .icon-btn {
  flex: 0 0 auto;
  margin: calc(var(--space-3) * -1) calc(var(--space-3) * -1) 0 0;
}
.drive-folder-modal__search {
  padding: var(--space-4) var(--space-6);
  border-bottom: 1px solid var(--border-default);
}
.drive-folder-modal__search input {
  width: 100%;
  min-height: var(--field-h);
  padding: 0 var(--space-4);
  border: 1px solid var(--border-input);
  border-radius: var(--radius-xs);
  background: var(--surface-0);
  color: var(--text-strong);
  font: var(--text-sm) var(--font-body);
}
.drive-folder-modal__search input::placeholder {
  color: var(--text-muted);
  opacity: 1;
}
.drive-folder-modal__search input:focus {
  border-color: var(--border-strong);
}
.drive-folder-modal__list {
  min-height: 120px;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.drive-folder-modal__list > .gallery-loader {
  padding: var(--space-6);
}
.drive-folder-modal__empty {
  display: grid;
  gap: var(--space-3);
  padding: var(--space-6);
}
.drive-folder-modal__empty strong {
  color: var(--text-strong);
  font-size: var(--text-sm);
}
.drive-folder-modal__empty p {
  color: var(--text-muted);
  font-size: var(--text-xs);
  line-height: 1.5;
}
.drive-folder-modal__empty code {
  overflow-wrap: anywhere;
}
.drive-folder-modal__error {
  margin: var(--space-5) var(--space-6);
}
.drive-folder-item {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  width: 100%;
  min-height: var(--field-h);
  padding: var(--space-4) var(--space-6);
  border: 0;
  border-top: 1px solid var(--border-default);
  background: var(--surface-0);
  color: var(--text-strong);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.drive-folder-item:first-child {
  border-top: 0;
}
.drive-folder-item:hover {
  background: var(--bg-inset);
}
.drive-folder-item vs-icon {
  flex: 0 0 auto;
  color: var(--text-muted);
}
.drive-folder-item__copy {
  display: grid;
  gap: var(--space-1);
  min-width: 0;
}
.drive-folder-item__copy strong {
  font-size: var(--text-sm);
  font-weight: var(--fw-semibold);
  overflow-wrap: anywhere;
}
.drive-folder-item__copy span {
  font: var(--text-2xs) var(--font-mono);
  color: var(--text-muted);
  overflow-wrap: anywhere;
}

/* ---- Pratinjau tautan (tab Tampilan, Spec A §5.1) ----
   Tiruan netral kartu tautan pesan: datar, radius 0, garis rambut, tanpa logo
   atau warna aplikasi pesan mana pun. */
.link-preview {
  display: grid;
  width: 100%;
  max-width: 420px;
  min-width: 0;
  overflow: hidden;
  border: 1px solid var(--border-default);
  border-radius: 0;
  background: var(--bg-subtle);
}
.link-preview__kicker {
  font: var(--fw-semibold) var(--text-2xs) var(--font-mono);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--text-muted);
}
.link-preview__media {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1200 / 630;
  object-fit: cover;
  background: var(--bg-inset);
  border-bottom: 1px solid var(--border-default);
}
.link-preview__body {
  display: grid;
  gap: var(--space-1);
  min-width: 0;
  padding: var(--space-4) var(--space-5);
}
.link-preview__title {
  font-size: var(--text-sm);
  font-weight: var(--fw-semibold);
  line-height: 1.35;
  color: var(--text-strong);
  overflow-wrap: anywhere;
}
.link-preview__desc {
  font-size: var(--text-xs);
  line-height: 1.45;
  color: var(--text-muted);
  overflow-wrap: anywhere;
}
/* Spec menulis --text-subtle; di atas --bg-subtle itu 3.90:1, jadi --text-muted. */
.link-preview__domain {
  font: 12px var(--font-mono);
  color: var(--text-muted);
  overflow-wrap: anywhere;
}
/* Tanpa pembungkus __body: teks anak langsung tetap mendapat bantalan. */
.link-preview > .link-preview__title { padding: var(--space-4) var(--space-5) 0; }
.link-preview > .link-preview__desc { padding: var(--space-1) var(--space-5) 0; }
.link-preview > .link-preview__domain { padding: var(--space-2) var(--space-5) var(--space-4); }
.link-preview > :last-child:not(img) { padding-bottom: var(--space-4); }

/* ---- Tablet & ponsel (breakpoint yang sudah ada) ---- */
@media (max-width: 899px) {
  /* Tab tanpa scrollbar terlihat menyembunyikan "Kategori" dan "Tautan Klien"
     di 360px; dibungkus ke baris kedua, garis bawah tetap menandai yang aktif. */
  body.is-app .album-tabbar .workspace-tabs {
    flex-wrap: wrap;
    overflow: visible;
    column-gap: var(--space-5);
    row-gap: 0;
  }
  body.is-app .filter-tabs {
    flex-wrap: wrap;
    overflow: visible;
  }
  /* Target sentuh 44px. */
  body.is-app .vs-btn--sm {
    min-height: var(--field-h);
  }
  body.is-app .section-heading a,
  body.is-app .button-link {
    display: inline-flex;
    align-items: center;
    min-height: var(--field-h);
  }
  body.is-app .field-group .field--check {
    min-height: var(--field-h);
  }
  /* < 16px membuat Safari iOS memperbesar halaman saat fokus dan tidak kembali. */
  body.is-app .field input,
  body.is-app .field textarea,
  body.is-app .field select,
  body.is-app .search-field input,
  body.is-app .whatsapp-template-card textarea,
  .drive-folder-modal__search input {
    font-size: var(--text-md);
  }
  body.is-app .activity-row,
  body.is-app .health-row,
  body.is-app .selection-group__head {
    flex-wrap: wrap;
  }
  body.is-app .activity-row__copy,
  body.is-app .health-row__copy {
    flex: 1 1 0;
    min-width: 12ch;
  }
  body.is-app .activity-row time,
  body.is-app .health-row__value {
    order: 3;
    flex-basis: 100%;
    max-width: none;
  }
  body.is-app .dashboard-kpis {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  body.is-app .dashboard-kpis .stat-card {
    min-height: 0;
    padding: var(--space-4);
  }
  body.is-app .look-picker {
    max-height: none;
    overflow: visible;
  }
  .drive-folder-modal {
    align-items: end;
    padding: 0;
  }
  .drive-folder-modal__card {
    width: 100%;
    max-height: min(86dvh, 680px);
    padding-bottom: env(safe-area-inset-bottom, 0px);
    border-radius: var(--radius-md) var(--radius-md) 0 0;
  }
}
@media (max-width: 479px) {
  body.is-app .dashboard-kpis .stat-card__meta {
    display: none;
  }
}

/* =========================================================================
   ORGANIZER (komponen DS Space · docs/design/organizer/ORGANIZER.md)
   Satu kartu bergaris rambut: kepala alat -> kepala daftar -> isi -> catatan.
   Bobot berat hanya satu: chip/segmen aktif (tinta). Kontrol lain bergaris.
   ========================================================================= */
.org {
  display: grid;
  background: var(--surface-0);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-card);
}
.org__head {
  display: grid;
  gap: var(--space-4);
  padding: var(--space-5) var(--space-6);
  border-bottom: 1px solid var(--border-faint);
}
.org-kicker {
  padding: 0;
  font: 600 var(--text-2xs) var(--font-mono);
  letter-spacing: var(--ls-label-sm);
  text-transform: uppercase;
  color: var(--text-subtle);
}
.org-link {
  display: inline-flex;
  align-items: center;
  min-height: var(--field-h-sm);
  color: var(--text-strong);
  font-size: var(--text-xs);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Lingkup: segmented tinta (Seleksi | Showcase). */
.org-seg {
  display: inline-flex;
  justify-self: start;
  max-width: 100%;
  overflow-x: auto;
  padding: var(--space-1);
  background: var(--bg-inset);
  border-radius: var(--radius-xs);
}
.org-seg__item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--field-h-sm);
  padding: 0 var(--space-5);
  border-radius: var(--radius-xs);
  color: var(--text-muted);
  font: 600 var(--text-xs) var(--font-body);
  text-decoration: none;
  white-space: nowrap;
}
.org-seg__item:hover { color: var(--text-strong); }
.org-seg__item.is-active {
  background: var(--bg-ink);
  color: var(--text-on-dark);
}
.org-seg__count {
  font: 500 var(--text-2xs) var(--font-mono);
  opacity: 0.72;
}

/* Toolbar: cari (lentur) · Filter · jarak · Tampilan · Urutkan. */
.org__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}
.org__spacer { flex: 1 1 0; }
.org-search {
  position: relative;
  display: flex;
  align-items: center;
  flex: 1 1 280px;
  max-width: 440px;
  min-height: var(--field-h);
  border: 1px solid var(--border-input);
  border-radius: var(--radius-xs);
  background: var(--surface-0);
}
.org-search:focus-within { border-color: var(--border-strong); }
.org-search vs-icon {
  position: absolute;
  left: var(--space-4);
  color: var(--text-subtle);
  pointer-events: none;
}
.org-search input {
  flex: 1;
  min-width: 0;
  min-height: calc(var(--field-h) - 2px);
  padding: 0 var(--space-4) 0 40px;
  border: 0;
  background: transparent;
  color: var(--text-strong);
  font: var(--text-xs) var(--font-body);
}
.org-search input:focus { outline: 0; }
.org-search input::-webkit-search-cancel-button { cursor: pointer; }
.org-search__total {
  flex: none;
  padding-right: var(--space-4);
  color: var(--text-subtle);
  font-size: var(--text-2xs);
  white-space: nowrap;
}

.org-btn,
.org-sort,
.org-views__item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--field-h);
  padding: 0 var(--space-5);
  border: 1px solid var(--border-input);
  border-radius: var(--radius-xs);
  background: var(--surface-0);
  color: var(--text-strong);
  font: 600 var(--text-xs) var(--font-body);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}
.org-btn:hover,
.org-sort:hover,
.org-views__item:hover { border-color: var(--border-strong); }
.org-btn--filter { border-style: dashed; }
.org-btn--filter.is-on {
  border-style: solid;
  border-color: var(--border-strong);
}
.org-btn__badge {
  display: inline-grid;
  place-items: center;
  min-width: 20px;
  height: 20px;
  padding: 0 var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--bg-ink);
  color: var(--text-on-dark);
  font: 600 var(--text-2xs) var(--font-mono);
}

/* Popover Filter: <details> supaya tetap jalan tanpa JavaScript. */
.org-pop { position: relative; }
.org-pop > summary { list-style: none; }
.org-pop > summary::-webkit-details-marker { display: none; }
.org-pop[open] > summary { background: var(--surface-1); }
.org-pop__panel {
  position: absolute;
  top: calc(100% + var(--space-3));
  left: 0;
  z-index: 60;
  display: grid;
  gap: var(--space-5);
  width: min(320px, calc(100vw - 32px));
  max-height: min(70dvh, 520px);
  overflow-y: auto;
  padding: var(--space-5);
  background: var(--surface-0);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-pop);
}
.org-pop__group {
  display: grid;
  gap: var(--space-1);
  margin: 0;
  padding: 0;
  border: 0;
}
.org-pop__group legend { margin-bottom: var(--space-3); }
.org-option {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-4);
  min-height: var(--field-h-sm);
  color: var(--text-body);
  font-size: var(--text-xs);
  cursor: pointer;
}
.org-option input { width: 16px; height: 16px; margin: 0; accent-color: var(--bg-ink); }
.org-option__count {
  color: var(--text-subtle);
  font: 500 var(--text-2xs) var(--font-mono);
}
.org-range {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3);
  margin-top: var(--space-2);
}
.org-range[hidden] { display: none; }
.org-range label {
  display: grid;
  gap: var(--space-2);
  color: var(--text-muted);
  font-size: var(--text-2xs);
}
.org-range input {
  min-height: var(--field-h-sm);
  padding: 0 var(--space-3);
  border: 1px solid var(--border-input);
  border-radius: var(--radius-xs);
  background: var(--surface-0);
  color: var(--text-strong);
  font: var(--text-xs) var(--font-body);
}
.org-pop__foot {
  position: sticky;
  bottom: calc(var(--space-5) * -1);
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-5);
  margin: 0 calc(var(--space-5) * -1) calc(var(--space-5) * -1);
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--border-faint);
  background: var(--surface-0);
}

/* Tampilan: dua tautan (Kartu | Daftar), bukan ikon tanpa teks. */
.org-views {
  display: inline-flex;
}
.org-views__item { color: var(--text-muted); }
.org-views__item + .org-views__item { margin-left: -1px; }
.org-views__item.is-active {
  position: relative;
  border-color: var(--border-strong);
  color: var(--text-strong);
  background: var(--surface-1);
}

/* Urutkan: select asli di dalam bingkai tombol. */
.org-sort { position: relative; padding-right: 36px; }
.org-sort__label { color: var(--text-muted); font-weight: 500; }
.org-sort select {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--text-strong);
  font: 600 var(--text-xs) var(--font-body);
  cursor: pointer;
}
.org-sort select:focus { outline: 0; }
.org-sort:focus-within { border-color: var(--border-strong); }
.org-sort vs-icon {
  position: absolute;
  right: var(--space-4);
  color: var(--text-subtle);
  pointer-events: none;
}

/* Saringan aktif: hanya saat cari/filter menyempitkan daftar. */
.org__active {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}
.org__shown {
  margin-right: var(--space-3);
  color: var(--text-muted);
  font-size: var(--text-xs);
}
.org__shown strong { color: var(--text-strong); }
.org-token {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 30px;
  padding: 0 var(--space-4);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-pill);
  background: var(--surface-1);
  color: var(--text-strong);
  font-size: var(--text-xs);
  font-weight: 600;
  text-decoration: none;
}
.org-token:hover { border-color: var(--border-strong); }

/* Chip status cepat. Chip terpisah (Arsip, Sampah) diberi jarak dari kelompok utama. */
.org-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}
.org-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--field-h-sm);
  padding: 0 var(--space-5);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-xs);
  background: var(--surface-0);
  color: var(--text-muted);
  font: 600 var(--text-xs) var(--font-body);
  text-decoration: none;
  white-space: nowrap;
}
.org-chip:hover { border-color: var(--border-strong); color: var(--text-strong); }
.org-chip.is-active {
  border-color: var(--bg-ink);
  background: var(--bg-ink);
  color: var(--text-on-dark);
}
.org-chip__count { font: 500 var(--text-2xs) var(--font-mono); opacity: 0.72; }
.org-chip--apart { margin-left: var(--space-5); }
.org-chip--apart ~ .org-chip--apart { margin-left: 0; }

/* Kepala daftar: pilih semua + bilah aksi massal. */
.org__lead {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-5);
  min-height: 56px;
  padding: var(--space-3) var(--space-6);
  border-bottom: 1px solid var(--border-faint);
  background: var(--surface-1);
}
.org-check {
  display: inline-flex;
  align-items: center;
  gap: var(--space-4);
  min-width: var(--field-h);
  min-height: var(--field-h);
  color: var(--text-strong);
  font-size: var(--text-xs);
  font-weight: 600;
  cursor: pointer;
}
.org-check input { width: 18px; height: 18px; margin: 0; accent-color: var(--bg-ink); cursor: pointer; }
.org-bulk {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}
.org-bulk__count {
  margin-right: var(--space-3);
  color: var(--text-muted);
  font-size: var(--text-xs);
}
.org-bulk .vs-btn:disabled { opacity: 0.45; cursor: not-allowed; }
.org-lead__all { margin-left: auto; }
.org-btn--danger { color: var(--tag-danger-text); }
.vs-btn--secondary.org-btn--danger:not(:disabled):hover { border-color: var(--tag-danger-text); }

/* Isi: daftar/galeri tanpa bingkai sendiri; kartu organizer yang membingkai. */
.org__body { min-width: 0; padding: var(--space-6); }
.org__body > .hairline-list > * { padding-block: var(--space-5); }
.org__body > .hairline-list > *:first-child { padding-top: 0; }
.org__body > .album-grid { margin: 0; }
.org-empty {
  display: grid;
  gap: var(--space-2);
  justify-items: start;
  padding: var(--space-6) 0;
  color: var(--text-muted);
  font-size: var(--text-xs);
}
.org-empty p { margin: 0; }
.org-empty strong { color: var(--text-strong); font-size: var(--text-md); }
.org__foot {
  padding: var(--space-4) var(--space-6);
  border-top: 1px solid var(--border-faint);
}
.org__foot p { margin: 0; color: var(--text-muted); font-size: var(--text-2xs); }

/* Baris berpilih: kotak pilih di kolom pertama (grid, bukan flex bersarang). */
.org-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  column-gap: var(--space-4);
}
.album-card { position: relative; }
.album-card > .org-check {
  position: absolute;
  top: var(--space-3);
  right: var(--space-3);
  z-index: 2;
  justify-content: center;
  background: var(--surface-0);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-xs);
}

/* Baris album (tampilan Daftar). */
.album-row__link {
  display: grid;
  grid-template-columns: 48px minmax(0, 1fr) auto auto;
  align-items: center;
  gap: var(--space-5);
  color: inherit;
  text-decoration: none;
}
.album-row__thumb {
  display: grid;
  place-items: center;
  width: 48px;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--bg-inset);
  color: var(--text-subtle);
}
.album-row__thumb img { width: 100%; height: 100%; object-fit: cover; }
.album-row__copy { display: grid; gap: var(--space-1); min-width: 0; }
.album-row__copy strong { color: var(--text-strong); font-size: 14px; font-weight: 600; }
.album-row__copy span { color: var(--text-muted); font-size: var(--text-xs); overflow-wrap: anywhere; }
.album-row__link:hover .album-row__copy strong { text-decoration: underline; text-underline-offset: 3px; }
.album-row__link > vs-icon { color: var(--text-subtle); }
.org-row.is-picked { background: var(--surface-1); }
/* Baris lama (.response-row) di dalam baris organizer: garis & jarak milik .org-row. */
.org-row > .response-row { padding-block: 0; border-top: 0; }

@media (max-width: 899px) {
  .org__head { padding: var(--space-5); }
  .org__body { padding: var(--space-5); }
  .org__lead { padding-inline: var(--space-5); }
  .org__foot { padding-inline: var(--space-5); }
  .org-search { flex-basis: 100%; max-width: none; }
  .org-search input,
  .org-range input { font-size: var(--text-md); }
  .org__spacer { display: none; }
  .org-sort { flex: 1 1 auto; justify-content: flex-start; }
  .org-pop { position: static; }
  .org__bar { position: relative; }
  .org-pop__panel { left: 0; right: 0; width: auto; }
  .org-lead__all { margin-left: 0; }
  .album-row__link { grid-template-columns: 48px minmax(0, 1fr); row-gap: var(--space-2); }
  .album-row__link .status-badge { grid-column: 2; justify-self: start; }
  .album-row__link > vs-icon { display: none; }
}
@media (prefers-reduced-motion: no-preference) {
  .org-pop[open] .org-pop__panel { animation: org-pop-in 0.12s ease-out; }
}
@keyframes org-pop-in { from { opacity: 0; } to { opacity: 1; } }

/* Dialog konfirmasi DS (app.js askConfirm): pengganti confirm() bawaan. */
.confirm-dialog {
  width: min(440px, calc(100vw - 32px));
  padding: 0;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  background: var(--surface-0);
  color: var(--text-body);
  box-shadow: var(--shadow-pop);
}
.confirm-dialog::backdrop { background: rgba(5, 5, 5, 0.42); }
.confirm-dialog__card {
  display: grid;
  gap: var(--space-6);
  padding: var(--space-7);
}
.confirm-dialog__text {
  margin: 0;
  color: var(--text-strong);
  font-size: var(--text-md);
  line-height: 1.55;
  white-space: pre-line;
}
.confirm-dialog__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-3);
}
.confirm-dialog__ok--danger,
.confirm-dialog__ok--danger:hover {
  background: var(--tag-danger-text);
  color: var(--text-on-dark);
}

/* ---- Fokus keyboard (WAJIB aturan terakhir di berkas ini) ----
   Cincin --shadow-focus (rgba 5,5,5,.14) hanya 1.37:1 di putih, dan varian
   .vs-btn dulu mematikannya. Satu outline tinta 2px untuk semua kontrol
   layar login; spesifisitasnya (0,2,1) sama dengan .field input:focus, jadi
   posisinya di akhir berkas yang membuatnya menang. */
body.is-app :focus-visible {
  outline: 2px solid var(--border-strong);
  outline-offset: 2px;
  box-shadow: none;
}
/* Di dalam wadah yang menggulir/memotong, cincin digambar ke dalam. */
body.is-app .filter-tab:focus-visible,
body.is-app .workspace-tab:focus-visible,
body.is-app .bottom-nav__item:focus-visible,
body.is-app .drive-folder-item:focus-visible,
body.is-app .org-seg__item:focus-visible {
  outline-offset: -2px;
}
/* Kolom teks: garis tinta menempel ke border-strong-nya sendiri. */
body.is-app .field input:focus-visible,
body.is-app .field textarea:focus-visible,
body.is-app .field select:focus-visible,
body.is-app .search-field input:focus-visible,
body.is-app .whatsapp-template-card textarea:focus-visible,
.drive-folder-modal__search input:focus-visible {
  outline-offset: 0;
}
/* Wadahnya (:focus-within) sudah menggambar cincin; tanpa cincin kedua. */
body.is-app .input-with-prefix input:focus,
body.is-app .input-with-prefix input:focus-visible,
body.is-app .purpose-option input:focus-visible,
body.is-app .look-option input:focus-visible,
body.is-app .look-tile label input:focus-visible,
body.is-app .org-search input:focus-visible,
body.is-app .org-sort select:focus-visible {
  outline: none;
  box-shadow: none;
}
/* Organizer: cincin di bingkai kotak cari / Urutkan, bukan di input telanjang di dalamnya. */
body.is-app .org-search:has(input:focus-visible),
body.is-app .org-sort:has(select:focus-visible) {
  outline: 2px solid var(--border-strong);
  outline-offset: 2px;
}
body.is-app .album-panel:focus-visible {
  outline-offset: 4px;
}
