/* ==========================================================================
   Arunika-POS (BrewPOS) - Modern Warm Coffee Light Design System
   Inspired by Square POS, Toast POS & Material Design 3
   ========================================================================== */

@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700;800&family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&family=Space+Mono:ital,wght@0,400;0,700;1,400&display=swap');

:root {
  /* Typography */
  --font-heading: 'Outfit', sans-serif;
  --font-body: 'Plus Jakarta Sans', sans-serif;
  --font-mono: 'Space Mono', monospace;

  /* Warm Coffee Light Theme Palette */
  --bg-main: #FAF8F5;          /* Warm clean off-white */
  --bg-sidebar: #FFFFFF;       /* Crisp white sidebar */
  --bg-card: #FFFFFF;          /* Pure white cards */
  --bg-surface: #F5EFEB;       /* Subtle warm latte surface */
  --bg-input: #FFFFFF;         /* Clean input background */
  --bg-hover: #F0E6DE;         /* Soft hover highlight */

  /* Borders & Dividers */
  --border-color: #EADBCE;     /* Subtle warm border */
  --border-light: #F0E6DD;
  --border-focus: #6F4E37;     /* Coffee brown focus ring */

  /* Brand Accents */
  --color-primary: #6F4E37;       /* Rich Espresso / Coffee Brown */
  --color-primary-hover: #5A3D2A;
  --color-primary-light: #F4EAE1; /* Latte cream highlight */
  --color-secondary: #C89058;     /* Warm Caramel */
  --color-secondary-light: #FBF4EC;
  --color-accent: #E07A5F;        /* Terracotta accent */

  /* Functional Status Colors */
  --color-success: #2E7D32;       /* Forest green */
  --color-success-bg: #E8F5E9;
  --color-warning: #ED6C02;       /* Warm amber */
  --color-warning-bg: #FFF3E0;
  --color-danger: #D32F2F;        /* Crimson */
  --color-danger-bg: #FFEBEE;
  --color-info: #0288D1;          /* Sky blue */
  --color-info-bg: #E1F5FE;

  /* Text Colors */
  --text-main: #2D2424;        /* Deep roasted charcoal brown */
  --text-secondary: #5C524F;   /* Soft brown text */
  --text-muted: #8E837D;       /* Muted gray-brown */
  --text-dark: #1F1916;
  --text-inverse: #FFFFFF;

  /* Shadows (Soft & Elegant) */
  --shadow-xs: 0 1px 3px rgba(70, 45, 30, 0.05);
  --shadow-sm: 0 2px 8px rgba(70, 45, 30, 0.06);
  --shadow-md: 0 6px 18px rgba(70, 45, 30, 0.08);
  --shadow-lg: 0 12px 32px rgba(70, 45, 30, 0.12);
  --shadow-modal: 0 20px 50px rgba(45, 25, 15, 0.18);

  /* Radius (Material 3 Touch-friendly) */
  --radius-xs: 6px;
  --radius-sm: 10px;
  --radius-md: 14px;
  --radius-lg: 20px;
  --radius-xl: 28px;
  --radius-full: 9999px;
}

/* Base Reset */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

/* Global type scale.
   Every font-size in this stylesheet and in the templates is written in rem, so this
   single value scales all UI text at once. Bump it to enlarge the whole interface.
   Receipt and @media print rules deliberately stay in physical px/mm: they have to
   match the paper, not the screen. */
html {
  font-size: 18px;
}

body {
  font-family: var(--font-body);
  background-color: var(--bg-main);
  color: var(--text-main);
  min-height: 100vh;
  display: flex;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

/* App Container Layout */
.app-container {
  display: flex;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  background-color: var(--bg-main);
}

/* Modern Sidebar */
.sidebar {
  width: 270px;
  background-color: var(--bg-sidebar);
  border-right: 1px solid var(--border-color);
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  z-index: 100;
  box-shadow: var(--shadow-sm);
  transition: width 0.3s ease;
}

.sidebar-header {
  padding: 22px 20px;
  display: flex;
  align-items: center;
  gap: 14px;
  border-bottom: 1px solid var(--border-color);
}

.brand-logo {
  width: 44px;
  height: 44px;
  background: linear-gradient(135deg, var(--color-primary), #8F6647);
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.375rem;
  color: #FFF;
  box-shadow: 0 4px 12px rgba(111, 78, 55, 0.3);
}

.brand-info h1 {
  font-family: var(--font-heading);
  font-size: 1.125rem;
  font-weight: 800;
  color: var(--color-primary);
  letter-spacing: -0.2px;
  line-height: 1.2;
}

.brand-info p {
  font-size: 0.6875rem;
  color: var(--color-secondary);
  font-weight: 600;
  letter-spacing: 0.5px;
  text-transform: uppercase;
}

.sidebar-nav {
  flex: 1;
  padding: 16px 14px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.nav-section-title {
  font-size: 0.6875rem;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 14px 12px 6px;
  font-weight: 700;
  letter-spacing: 0.8px;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 14px;
  color: var(--text-secondary);
  text-decoration: none;
  border-radius: var(--radius-md);
  font-size: 0.8438rem;
  font-weight: 600;
  transition: all 0.2s ease;
}

.nav-item i {
  font-size: 1.0625rem;
  width: 22px;
  text-align: center;
  color: var(--text-muted);
  transition: color 0.2s ease;
}

.nav-item:hover {
  background-color: var(--bg-surface);
  color: var(--color-primary);
}

.nav-item:hover i {
  color: var(--color-primary);
}

.nav-item.active {
  background-color: var(--color-primary-light);
  color: var(--color-primary);
  font-weight: 700;
}

.nav-item.active i {
  color: var(--color-primary);
}

.sidebar-footer {
  padding: 16px 14px;
  border-top: 1px solid var(--border-color);
  background-color: #FAFAFA;
}

.user-profile-badge {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 10px;
  background-color: #FFF;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
}

.user-avatar {
  width: 38px;
  height: 38px;
  flex-shrink: 0;
  border-radius: var(--radius-full);
  background: var(--color-primary-light);
  color: var(--color-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-size: 0.9375rem;
}

.user-meta {
  flex: 1;
  min-width: 0;
}

.user-name {
  font-size: 0.8125rem;
  font-weight: 700;
  color: var(--text-main);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.user-role {
  font-size: 0.6562rem;
  font-weight: 700;
  color: var(--color-secondary);
  text-transform: uppercase;
}

/* Collapsed sidebar: icon rail. Only meaningful >=1024px, since below that the
   sidebar is already off-canvas and those rules sit later in this file. */
.sidebar.collapsed {
  width: 76px;
}

.sidebar.collapsed .brand-info,
.sidebar.collapsed .nav-section-title,
.sidebar.collapsed .nav-item span,
.sidebar.collapsed .user-meta {
  display: none;
}

.sidebar.collapsed .sidebar-header,
.sidebar.collapsed .user-profile-badge {
  justify-content: center;
  padding-left: 0;
  padding-right: 0;
}

/* The 76px rail cannot fit avatar + logout side by side, so stack them. */
.sidebar.collapsed .sidebar-footer {
  padding: 12px 8px;
}

.sidebar.collapsed .user-profile-badge {
  flex-direction: column;
  gap: 8px;
  padding-top: 10px;
  padding-bottom: 10px;
}

.sidebar.collapsed .nav-item {
  justify-content: center;
  padding-left: 0;
  padding-right: 0;
}

.sidebar.collapsed .sidebar-toggle {
  display: none;
}

/* Suppress the width transition on first paint so a restored collapsed state does
   not animate open then snap shut on every page load. */
.sidebar.no-transition {
  transition: none;
}

.sidebar-toggle {
  margin-left: auto;
  border: none;
  background: none;
  color: var(--text-muted);
  cursor: pointer;
  padding: 6px;
  border-radius: var(--radius-xs);
  font-size: 0.875rem;
  transition: all 0.15s ease;
}

.sidebar-toggle:hover {
  background: var(--bg-surface);
  color: var(--color-primary);
}

/* Floating re-expand handle, the only affordance left once the rail is collapsed */
.sidebar-expand {
  display: none;
  border: none;
  background: none;
  color: var(--text-muted);
  cursor: pointer;
  padding: 6px;
  border-radius: var(--radius-xs);
  font-size: 0.875rem;
}

.sidebar.collapsed .sidebar-expand {
  display: block;
  margin: 8px auto 0;
}

.sidebar-expand:hover {
  background: var(--bg-surface);
  color: var(--color-primary);
}

/* Profile page */
.profile-layout {
  display: grid;
  grid-template-columns: 1.4fr 1fr;
  gap: 22px;
  align-items: start;
}

.profile-identity {
  display: flex;
  align-items: center;
  gap: 16px;
}

.profile-avatar {
  width: 68px;
  height: 68px;
  flex-shrink: 0;
  border-radius: var(--radius-full);
  background: linear-gradient(135deg, var(--color-primary), #8F6647);
  color: #FFF;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-heading);
  font-size: 1.75rem;
  font-weight: 800;
}

.profile-username {
  font-family: var(--font-heading);
  font-size: 1.375rem;
  font-weight: 800;
  color: var(--text-main);
  line-height: 1.2;
  word-break: break-word;
}

.profile-facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px;
  margin-top: 20px;
  padding-top: 18px;
  border-top: 1px solid var(--border-light);
}

.profile-facts dt {
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--text-muted);
  font-weight: 700;
  margin-bottom: 4px;
}

.profile-facts dd {
  font-size: 0.8438rem;
  font-weight: 700;
  color: var(--text-main);
}

.profile-pages {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

/* Main Wrapper */
.main-wrapper {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  overflow: hidden;
  background-color: var(--bg-main);
}

/* Topbar */
.topbar {
  height: 68px;
  padding: 0 28px;
  background-color: var(--bg-sidebar);
  border-bottom: 1px solid var(--border-color);
  display: flex;
  align-items: center;
  justify-content: space-between;
  box-shadow: var(--shadow-xs);
  flex-shrink: 0;
}

.page-title h2 {
  font-family: var(--font-heading);
  font-size: 1.25rem;
  font-weight: 700;
  color: var(--text-main);
}

.topbar-actions {
  display: flex;
  align-items: center;
  gap: 14px;
}

.shift-status-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  border-radius: var(--radius-full);
  font-size: 0.7812rem;
  font-weight: 700;
  border: 1px solid transparent;
}

.shift-status-pill.open {
  background-color: var(--color-success-bg);
  color: var(--color-success);
  border-color: rgba(46, 125, 50, 0.25);
}

.shift-status-pill.closed {
  background-color: var(--color-danger-bg);
  color: var(--color-danger);
  border-color: rgba(211, 47, 47, 0.25);
}

.status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background-color: currentColor;
}

/* Content Area */
.content-area {
  flex: 1;
  padding: 24px 28px;
  overflow-y: auto;
}

/* Cards (Clean Light Surface) */
.card {
  background-color: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 22px;
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.2s ease, transform 0.2s ease;
}

.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 18px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border-light);
}

.card-title {
  font-family: var(--font-heading);
  font-size: 1rem;
  font-weight: 700;
  color: var(--text-main);
  display: flex;
  align-items: center;
  gap: 10px;
}

/* Stats KPI Grid */
.stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 18px;
  margin-bottom: 24px;
}

.stat-card {
  background-color: #FFF;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 18px 20px;
  display: flex;
  align-items: center;
  gap: 16px;
  box-shadow: var(--shadow-sm);
  border-left: 4px solid var(--color-primary);
}

.stat-icon {
  width: 48px;
  height: 48px;
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.375rem;
  flex-shrink: 0;
}

.stat-info {
  flex: 1;
}

.stat-label {
  font-size: 0.75rem;
  color: var(--text-muted);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin-bottom: 4px;
}

.stat-value {
  font-family: var(--font-heading);
  font-size: 1.375rem;
  font-weight: 800;
  color: var(--text-main);
  line-height: 1.1;
}

/* Buttons (Material 3 Touch Style) */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 10px 18px;
  border-radius: var(--radius-sm);
  font-size: 0.8438rem;
  font-weight: 700;
  cursor: pointer;
  border: 1px solid transparent;
  text-decoration: none;
  transition: all 0.2s ease;
  font-family: var(--font-body);
}

.btn-primary {
  background-color: var(--color-primary);
  color: #FFF;
  box-shadow: 0 4px 12px rgba(111, 78, 55, 0.25);
}

.btn-primary:hover {
  background-color: var(--color-primary-hover);
  transform: translateY(-1px);
  box-shadow: 0 6px 16px rgba(111, 78, 55, 0.35);
}

.btn-secondary {
  background-color: #FFF;
  border-color: var(--border-color);
  color: var(--text-secondary);
}

.btn-secondary:hover {
  background-color: var(--bg-surface);
  border-color: var(--color-secondary);
  color: var(--color-primary);
}

.btn-success {
  background-color: var(--color-success);
  color: #FFF;
}

.btn-success:hover {
  background-color: #256628;
}

.btn-danger {
  background-color: var(--color-danger);
  color: #FFF;
}

.btn-danger:hover {
  background-color: #B71C1C;
}

.btn-warning {
  background-color: var(--color-warning);
  color: #FFF;
}

.btn-sm {
  padding: 7px 13px;
  font-size: 0.75rem;
  border-radius: var(--radius-xs);
}

.btn-lg {
  padding: 14px 24px;
  font-size: 1rem;
  border-radius: var(--radius-md);
}

.btn-icon {
  width: 36px;
  height: 36px;
  padding: 0;
  border-radius: var(--radius-sm);
}

.btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
  transform: none !important;
  box-shadow: none !important;
}

/* Form Controls */
.form-group {
  margin-bottom: 16px;
}

.form-label {
  display: block;
  font-size: 0.7812rem;
  font-weight: 700;
  color: var(--text-secondary);
  margin-bottom: 6px;
}

.form-control {
  width: 100%;
  padding: 10px 14px;
  background-color: var(--bg-input);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  color: var(--text-main);
  font-size: 0.8438rem;
  font-family: var(--font-body);
  transition: all 0.2s ease;
}

.form-control:focus {
  outline: none;
  border-color: var(--border-focus);
  box-shadow: 0 0 0 3px rgba(111, 78, 55, 0.12);
}

.form-control::placeholder {
  color: var(--text-muted);
  opacity: 0.7;
}

/* Tables (Clean Light) */
.table-responsive {
  width: 100%;
  overflow-x: auto;
}

.custom-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.8125rem;
  text-align: left;
}

.custom-table th {
  background-color: #F8F5F2;
  color: var(--text-secondary);
  font-weight: 700;
  padding: 12px 16px;
  border-bottom: 2px solid var(--border-color);
  text-transform: uppercase;
  font-size: 0.6875rem;
  letter-spacing: 0.5px;
}

.custom-table td {
  padding: 14px 16px;
  border-bottom: 1px solid var(--border-light);
  color: var(--text-main);
  vertical-align: middle;
}

.custom-table tr:hover td {
  background-color: rgba(245, 239, 235, 0.4);
}

/* Badges & Status Chips */
.badge-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 10px;
  border-radius: var(--radius-full);
  font-size: 0.6875rem;
  font-weight: 700;
}

.badge-chip.primary {
  background-color: var(--color-primary-light);
  color: var(--color-primary);
}

.badge-chip.success {
  background-color: var(--color-success-bg);
  color: var(--color-success);
}

.badge-chip.warning {
  background-color: var(--color-warning-bg);
  color: var(--color-warning);
}

.badge-chip.danger {
  background-color: var(--color-danger-bg);
  color: var(--color-danger);
}

.badge-chip.info {
  background-color: var(--color-info-bg);
  color: var(--color-info);
}

/* Modal Backdrop & Dialog */
.modal-backdrop {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background-color: rgba(25, 15, 10, 0.45);
  backdrop-filter: blur(4px);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease;
  padding: 16px;
  box-sizing: border-box;
}

.modal-backdrop.show {
  opacity: 1;
  pointer-events: auto;
}

.modal-dialog {
  background-color: #FFF;
  border-radius: var(--radius-xl);
  width: 100%;
  max-width: 520px;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  box-shadow: var(--shadow-modal);
  border: 1px solid var(--border-color);
  transform: scale(0.96);
  transition: transform 0.25s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

.modal-backdrop.show .modal-dialog {
  transform: scale(1);
}

/* Banyak modal membungkus body+footer dalam <form>. Tanpa aturan ini form
   tersebut jadi flex item biasa dengan min-height:auto, menolak menyusut, dan
   footernya (tombol Simpan) terdorong keluar layar di HP. */
.modal-dialog > form {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}

.modal-header {
  padding: 18px 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid var(--border-color);
  flex-shrink: 0;
}

.modal-title {
  font-family: var(--font-heading);
  font-size: 1.125rem;
  font-weight: 700;
  color: var(--color-primary);
}

.modal-close {
  background: transparent;
  border: none;
  /* Dulu 1.5rem untuk glif "x" yang tipis. Ikon fa-xmark digambar jauh lebih
     tebal, jadi pada ukuran yang sama ia mendominasi judul dialog. */
  font-size: 1.125rem;
  color: var(--text-muted);
  cursor: pointer;
  line-height: 1;
  padding: 4px 8px;
  border-radius: var(--radius-xs);
  transition: color 0.2s ease;
}

.modal-close:hover {
  color: var(--color-danger);
}

.modal-body {
  padding: 20px 24px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  /* Tinggi body mengikuti sisa ruang dialog, bukan hasil calc() yang menebak
     tinggi header+footer. Tebakan itu meleset begitu footer menumpuk dua
     tombol di HP, dan tombol Simpan terdorong keluar layar. min-height:0
     wajib supaya flex item ini boleh menyusut dan menggulung isinya. */
  flex: 1 1 auto;
  min-height: 0;
}

.modal-footer {
  padding: 14px 24px;
  border-top: 1px solid var(--border-color);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  background-color: #FAF8F5;
  border-radius: 0 0 var(--radius-xl) var(--radius-xl);
  flex-shrink: 0;
}

/* Toast Notifications */
#toast-container {
  position: fixed;
  top: 24px;
  right: 24px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  z-index: 9999;
}

.toast {
  background-color: #FFF;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  padding: 14px 18px;
  box-shadow: var(--shadow-lg);
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 0.8438rem;
  font-weight: 600;
  color: var(--text-main);
  min-width: 280px;
  animation: slideInToast 0.3s ease;
}

@keyframes slideInToast {
  from { transform: translateX(100%); opacity: 0; }
  to { transform: translateX(0); opacity: 1; }
}

.toast.success { border-left: 4px solid var(--color-success); }
.toast.success i { color: var(--color-success); font-size: 1.125rem; }
.toast.error { border-left: 4px solid var(--color-danger); }
.toast.error i { color: var(--color-danger); font-size: 1.125rem; }
.toast.warning { border-left: 4px solid var(--color-warning); }
.toast.warning i { color: var(--color-warning); font-size: 1.125rem; }
.toast.info { border-left: 4px solid var(--color-info); }
.toast.info i { color: var(--color-info); font-size: 1.125rem; }

/* ==========================================================================
   POS Specific Styles (Product Cards, Split Cart Panel, Cash Presets)
   ========================================================================== */

.pos-layout {
  display: grid;
  /* Katalog | Member | Keranjang. The right region holds the last two side by side. */
  grid-template-columns: 1fr 728px;
  gap: 22px;
  height: calc(100vh - 116px);
}

.pos-catalog-panel {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}

.pos-categories-bar {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  padding-bottom: 8px;
  margin-bottom: 12px;
  flex-shrink: 0;
}

.category-chip {
  padding: 8px 18px;
  background-color: #FFF;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-full);
  color: var(--text-secondary);
  font-size: 0.8125rem;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
  transition: all 0.2s ease;
  box-shadow: var(--shadow-xs);
}

.category-chip:hover {
  border-color: var(--color-secondary);
  color: var(--color-primary);
  background-color: var(--bg-surface);
}

.category-chip.active {
  background-color: var(--color-primary);
  color: #FFF;
  border-color: var(--color-primary);
  box-shadow: 0 4px 12px rgba(111, 78, 55, 0.3);
}

.pos-search-bar {
  margin-bottom: 14px;
  flex-shrink: 0;
}

/* Grid, bukan multi-kolom. Dengan column-width browser harus menata ulang
   SELURUH kartu setiap kali daftarnya berubah atau area ini di-scroll -- itu
   sumber tersendat paling terasa di HP saat mengetik di pencarian menu. */
.menu-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(165px, 1fr));
  gap: 12px;
  align-content: start;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding-right: 6px;
  padding-bottom: 18px;
  flex: 1;
}

.menu-card {
  display: flex;
  flex-direction: column;
  width: 100%;
  background-color: #FFF;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  padding: 10px 12px;
  cursor: pointer;
  transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
  position: relative;
  box-shadow: var(--shadow-xs);
}

.menu-card:hover {
  transform: translateY(-2px);
  border-color: var(--color-secondary);
  box-shadow: var(--shadow-md);
}

.menu-card-img {
  width: 100%;
  height: 80px;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.75rem;
  color: #FFF;
  margin-bottom: 8px;
  object-fit: cover;
  overflow: hidden;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06);
  /* Kartu kini sebaris tingginya (grid); gambar tidak boleh ikut memipih. */
  flex: 0 0 80px;
}

.menu-card-title {
  font-family: var(--font-heading);
  font-size: 0.8438rem;
  font-weight: 700;
  color: var(--text-main);
  margin-bottom: 2px;
  line-height: 1.25;
}

.menu-card-desc {
  font-size: 0.6875rem;
  color: var(--text-muted);
  margin-bottom: 6px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  line-height: 1.3;
}

.menu-card-desc:empty {
  display: none;
  margin-bottom: 0;
}

.menu-card-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 4px;
  /* Harga menempel di dasar kartu, sejajar antar kartu satu baris. */
  margin-top: auto;
  padding-top: 6px;
}

.menu-card-price {
  font-family: var(--font-heading);
  font-size: 0.8438rem;
  font-weight: 800;
  color: var(--color-primary);
  /* "Rp 28.000" tidak boleh pecah jadi dua baris saat kartunya menyempit */
  white-space: nowrap;
}

/* Keranjang kosong. Di desktop boleh lapang; di HP tidak.
   Sebagai bottom sheet, blok ini ada DI ATAS panel member, jadi saat keyboard
   naik dan area terlihat tinggal ~400px, isinya cuma bidang putih ini -- kotak
   pencarian membernya terdorong ke bawah layar. */
.cart-empty {
  text-align: center;
  color: var(--text-muted);
  margin-top: 40px;
}

.cart-empty i {
  font-size: 2.375rem;
  margin-bottom: 12px;
  opacity: 0.35;
  color: var(--color-primary);
}

.cart-empty-title {
  font-size: 0.8125rem;
  font-weight: 600;
}

.cart-empty-hint {
  font-size: 0.7188rem;
  margin-top: 4px;
}

/* POS Cart Sidebar Panel */
/* The right column is no longer one card: it holds two independent panes, side by
   side, so the member panel can never push the order list out of view. */
.pos-cart-panel {
  display: flex;
  flex-direction: row;
  align-items: stretch;
  gap: 14px;
  height: 100%;
  min-height: 0;
  background: none;
  border: none;
  box-shadow: none;
  overflow: visible;
}

.pos-side-card {
  background-color: #FFF;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-md);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.mobile-cart-close {
  display: none;
}

/* Checkout pane: fixed right column holding member, totals and the pay button */
.pos-side-card.checkout-card {
  flex: 0 0 348px;
  min-width: 0;
}

/* Order lines pane: takes the remaining width and scrolls internally.
   min-height/min-width 0 is what actually lets the inner list scroll in a flex child. */
.pos-side-card.cart-card {
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
}

.pos-card-head {
  padding: 14px 18px;
  border-bottom: 1px solid var(--border-color);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  background-color: #FAF8F5;
  cursor: pointer;
  flex-shrink: 0;
  user-select: none;
}

.pos-card-head.static {
  cursor: default;
}

.pos-card-title {
  font-family: var(--font-heading);
  font-size: 0.9375rem;
  font-weight: 800;
  color: var(--color-primary);
  display: flex;
  align-items: center;
  gap: 8px;
}

.pos-card-chevron {
  color: var(--text-muted);
  font-size: 0.75rem;
  transition: transform 0.2s ease;
}

.checkout-card.collapsed .pos-card-chevron {
  transform: rotate(180deg);
}

.checkout-card.collapsed .customer-selector {
  display: none;
}

/* Totals + payment sit at the bottom of the checkout pane and never scroll away */
.checkout-card .cart-summary {
  margin-top: auto;
}

.customer-selector {
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  background-color: #FCFBF9;
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}

.member-search-dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  background: #FFF;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  box-shadow: 0 10px 25px rgba(70, 45, 30, 0.18);
  max-height: 220px;
  overflow-y: auto;
  z-index: 100;
  margin-top: 4px;
}

.member-search-item {
  padding: 11px 13px;
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  border-bottom: 1px solid var(--border-light);
  transition: background 0.15s ease;
}

.member-search-item:last-child {
  border-bottom: none;
}

.member-search-item:hover {
  background: var(--color-primary-light);
}

.member-search-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--color-primary-light);
  color: var(--color-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 0.8125rem;
  flex-shrink: 0;
}

.member-selected-card {
  background: #FAF5EE;
  border: 1px solid #E6D7C8;
  border-radius: var(--radius-sm);
  padding: 13px 14px;
}

.member-avatar-mini {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--color-primary);
  color: #FFF;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 0.75rem;
  flex-shrink: 0;
}

.cart-items-list {
  flex: 1 1 auto;
  /* Guarantee the order list keeps room even when the member/loyalty boxes above
     are all expanded, instead of being squeezed to a couple of visible rows. */
  min-height: 180px;
  overflow-y: auto;
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.cart-item-row {
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding: 14px 14px;
  background-color: #FAF8F5;
  border-radius: var(--radius-md);
  border: 1px solid var(--border-light);
}

.cart-item-main {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.cart-item-info h5 {
  font-size: 0.8125rem;
  font-weight: 700;
  color: var(--text-main);
  margin-bottom: 2px;
}

.cart-item-info span {
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--color-primary);
}

.cart-item-discount-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: #FFF;
  padding: 4px 8px;
  border-radius: var(--radius-xs);
  border: 1px dashed #EADBCE;
  font-size: 0.6875rem;
}

.cart-item-discount-input {
  width: 90px;
  padding: 2px 6px;
  font-size: 0.7188rem;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-xs);
  text-align: right;
}

.qty-stepper {
  display: flex;
  align-items: center;
  gap: 6px;
  background-color: #FFF;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-full);
  padding: 2px 6px;
}

.qty-btn {
  background: transparent;
  border: none;
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-size: 0.8125rem;
  color: var(--color-primary);
  cursor: pointer;
  border-radius: 50%;
  transition: background 0.15s ease;
}

.qty-btn:hover {
  background-color: var(--color-primary-light);
}

.cart-summary {
  padding: 18px 20px;
  flex-shrink: 0;
  border-top: 1px solid var(--border-color);
  background-color: #FAF8F5;
  font-size: 0.75rem;
}

.summary-row {
  display: flex;
  justify-content: space-between;
  color: var(--text-secondary);
  margin-bottom: 8px;
}

.summary-row.discount {
  color: var(--color-danger);
  font-weight: 600;
}

/* Tax disclosure sits under the total in a lighter weight: menu prices are
   tax-inclusive, so this is information, not another line on the bill. */
.summary-tax-note {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  margin-top: 6px;
  padding-left: 10px;
  font-size: 0.6875rem;
  color: var(--text-muted);
}

.summary-row.total {
  font-family: var(--font-heading);
  font-size: 1.1875rem;
  font-weight: 800;
  color: var(--color-primary);
  border-top: 1px dashed var(--border-color);
  padding-top: 12px;
  margin-top: 12px;
  margin-bottom: 0;
}

/* Loyalty actions collapsed into one chip row instead of three stacked cards */
.loyalty-chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}

.loyalty-chip-row:empty {
  display: none;
}

.loyalty-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 6px 10px;
  border-radius: var(--radius-full);
  border: 1px solid var(--border-color);
  background: #FFF;
  font-size: 0.6875rem;
  font-weight: 700;
  color: var(--text-secondary);
  cursor: pointer;
  transition: all 0.15s ease;
}

.loyalty-chip:hover {
  border-color: var(--color-secondary);
  background: var(--color-secondary-light);
}

.loyalty-chip.warning {
  border-color: #FFE082;
  background: #FFF8E1;
  color: #8D6E63;
}

.loyalty-chip-value {
  font-weight: 800;
  color: var(--color-primary);
}

.loyalty-reward {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: var(--radius-full);
  border: 1px solid #E6D7C8;
  background: #FAF5EE;
  font-size: 0.6875rem;
  min-width: 0;
  flex: 1 1 160px;
}

.loyalty-reward-select {
  flex: 1 1 auto;
  min-width: 0;
  border: none;
  background: transparent;
  font-size: 0.6875rem;
  font-weight: 700;
  color: var(--color-primary);
  cursor: pointer;
  outline: none;
}

/* Payment modal: figures a cashier can read at arm's length */
.pay-total-box,
.pay-change-box {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 16px;
  border-radius: var(--radius-md);
  margin-bottom: 16px;
}

.pay-total-box {
  background: var(--color-primary-light);
  border: 1px solid var(--border-color);
}

.pay-change-box {
  background: var(--color-success-bg);
  border: 1px solid rgba(46, 125, 50, 0.25);
  margin-top: 12px;
  margin-bottom: 0;
}

.pay-total-label {
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-secondary);
}

.pay-total-value,
.pay-change-value {
  font-family: var(--font-heading);
  font-size: 1.75rem;
  font-weight: 800;
  line-height: 1.1;
}

.pay-total-value {
  color: var(--color-primary);
}

.pay-change-value {
  color: var(--color-success);
}

.pay-method-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
}

.pay-method-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 14px 10px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-color);
  background: #FFF;
  font-size: 0.8125rem;
  font-weight: 700;
  color: var(--text-secondary);
  cursor: pointer;
  transition: all 0.15s ease;
}

.pay-method-btn:hover {
  border-color: var(--color-secondary);
  background: var(--color-secondary-light);
}

.pay-method-btn.active {
  border-color: var(--color-primary);
  background: var(--color-primary);
  color: #FFF;
  box-shadow: 0 4px 12px rgba(111, 78, 55, 0.25);
}

/* Quick Cash Presets */
.cash-preset-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
  margin: 8px 0;
}

.cash-preset-btn {
  padding: 12px 6px;
  background-color: #FFF;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-xs);
  font-size: 0.7188rem;
  font-weight: 700;
  color: var(--color-primary);
  cursor: pointer;
  text-align: center;
  transition: all 0.15s ease;
}

.cash-preset-btn:hover, .cash-preset-btn.active {
  background-color: var(--color-primary-light);
  border-color: var(--color-primary);
}

/* ==========================================================================
   Thermal Receipt Component & High-Accuracy Printing
   ========================================================================== */

.thermal-receipt-card {
  width: 100%;
  max-width: 330px;
  box-sizing: border-box;
  background-color: #FFFFFF;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  padding: 20px 16px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
  font-family: var(--font-mono);
  font-size: 11.5px;
  line-height: 1.4;
  color: #111111;
  margin: 0 auto;
  position: relative;
  word-break: break-word;
}

.receipt-header {
  text-align: center;
  margin-bottom: 12px;
}

.receipt-logo {
  display: none !important;
}

.receipt-store-title {
  font-weight: 800;
  font-size: 15px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
}

.receipt-meta-info {
  font-size: 10.5px;
  color: #444;
  margin-top: 3px;
  line-height: 1.35;
}

.receipt-divider {
  border-top: 1px dashed #777;
  margin: 10px 0;
}

.receipt-divider.double {
  border-top: 2px solid #333;
  margin: 10px 0;
}

.receipt-row {
  display: flex;
  justify-content: space-between;
  margin-bottom: 3px;
}

.receipt-row.bold {
  font-weight: 800;
  font-size: 13px;
}

.receipt-footer {
  text-align: center;
  font-size: 10.5px;
  color: #444;
  margin-top: 14px;
  line-height: 1.4;
}

/* Mobile Hamburger Toggle Button */
.mobile-menu-toggle {
  display: none !important;
}

.mobile-cart-bar {
  display: none;
}

/* ==========================================================================
   Comprehensive Mobile & Tablet Responsive Layout
   ========================================================================== */

/* Three columns need roughly 1400px of viewport: 728px for the two right panes, plus
   a catalog wide enough to still show two menu columns. Below that they stack again
   rather than all three going too narrow to use. Move this breakpoint if your terminal
   screen is wider or narrower than that. */
@media (max-width: 1400px) {
  .pos-layout {
    grid-template-columns: 1fr 452px;
  }

  .pos-cart-panel {
    flex-direction: column;
  }

  /* Stacked: the order lines keep the flexible height, checkout sizes to content */
  .pos-side-card.cart-card {
    flex: 1 1 auto;
  }

  .pos-side-card.checkout-card {
    flex: 0 0 auto;
  }

  .customer-selector {
    flex: 0 1 auto;
    max-height: 32vh;
  }
}

@media (max-width: 1024px) {
  .profile-layout {
    grid-template-columns: 1fr;
  }

  /* Tablets are usually the touch terminal — give the whole UI another notch */
  html {
    font-size: 19px;
  }

  .app-container {
    overflow-x: hidden;
  }

  .sidebar {
    position: fixed;
    left: -290px;
    top: 0;
    bottom: 0;
    width: 280px;
    z-index: 1050;
    transition: left 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    box-shadow: var(--shadow-lg);
  }

  .sidebar.open {
    left: 0;
  }

  .sidebar-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
    backdrop-filter: blur(2px);
    z-index: 1040;
    display: none;
    opacity: 0;
    transition: opacity 0.3s ease;
  }

  .sidebar-backdrop.show {
    display: block;
    opacity: 1;
  }

  .mobile-menu-toggle {
    display: inline-flex !important;
  }

  .main-wrapper {
    width: 100vw !important;
    max-width: 100vw !important;
  }

  .topbar {
    padding: 12px 16px;
  }

  .content-area {
    padding: 16px;
  }
}

@media (max-width: 768px) {
  .page-title h2 {
    font-size: 1.0625rem;
  }

  .topbar-actions .shift-text {
    display: none;
  }

  .topbar-actions .btn-text {
    display: none;
  }

  .stats-grid {
    grid-template-columns: 1fr 1fr;
    gap: 12px;
  }

  .stat-card {
    padding: 14px;
  }

  .stat-value {
    font-size: 1rem;
  }

  .modal-backdrop {
    padding: 8px !important;
  }

  .modal-dialog {
    width: 100% !important;
    max-width: 100% !important;
    margin: auto !important;
    max-height: 94vh !important;
    border-radius: var(--radius-lg) !important;
  }

  .modal-header {
    padding: 14px 18px !important;
  }

  .modal-footer {
    padding: 12px 18px !important;
  }

  .modal-body {
    padding: 12px !important;
    overflow-y: auto !important;
    -webkit-overflow-scrolling: touch !important;
  }

  .thermal-receipt-card {
    width: 100% !important;
    max-width: 100% !important;
    padding: 14px 10px !important;
    font-size: 11px !important;
  }

  /* Grid collapsing on mobile for all multi-column pages */
  [style*="grid-template-columns: 1fr 1.35fr"],
  [style*="grid-template-columns: 1fr 1fr"],
  [style*="grid-template-columns: 2fr 1fr"],
  [style*="grid-template-columns: 1fr 2fr"],
  [style*="grid-template-columns: repeat(4, 1fr)"] {
    grid-template-columns: 1fr !important;
    gap: 16px !important;
  }

  .stats-grid {
    grid-template-columns: 1fr 1fr !important;
    gap: 10px !important;
  }

  .menu-grid {
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 10px;
  }

  /* Table horizontal touch scroll */
  .table-responsive {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    width: 100%;
    margin-bottom: 10px;
  }
}

@media (max-width: 480px) {
  /* Turun dari skala tablet: di HP, teks 19.5px membuat judul menu pecah dua baris
     dan hanya menyisakan satu setengah baris kartu yang terlihat. */
  html {
    font-size: 18px;
  }

  .stats-grid {
    grid-template-columns: 1fr !important;
  }
  .topbar {
    padding: 10px 12px;
  }
  .content-area {
    padding: 12px 10px;
  }
  .card-header {
    flex-direction: column;
    align-items: flex-start !important;
    gap: 10px;
  }
  .card-header > button, .card-header .btn {
    width: 100%;
  }
  .menu-grid {
    grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
    gap: 8px;
  }
}

/* ==========================================================================
   Touch & Small-Screen Refinements

   Dipisah dari blok @media di atas supaya jelas mana aturan layout dan mana
   aturan kenyamanan sentuh. Urutannya sengaja setelah semua breakpoint agar
   menang tanpa perlu !important.
   ========================================================================== */

/* Scroll dikunci saat sidebar / bottom sheet terbuka: tanpa ini halaman di
   belakang ikut ter-scroll dan posisi baca pengguna hilang. */
body.scroll-locked {
  overflow: hidden;
}

/* Target sentuh. Jari butuh sekitar 44px; btn-sm sebelumnya hanya ~33px,
   dan itu tombol yang paling sering dipakai (filter, aksi di tabel). */
@media (pointer: coarse) {
  .btn {
    min-height: 44px;
  }

  .btn-sm {
    min-height: 38px;
    padding: 8px 14px;
  }

  .btn-icon {
    width: 42px;
    height: 42px;
  }

  .form-control,
  select.form-control {
    min-height: 44px;
  }

  .modal-close {
    width: 42px;
    height: 42px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  .nav-item {
    min-height: 46px;
  }

  /* Baris tabel lebih longgar supaya tidak salah tekan */
  .custom-table td {
    padding-top: 16px;
    padding-bottom: 16px;
  }
}

@media (max-width: 1024px) {
  /* Tinggi viewport dinamis: bar alamat browser mobile yang muncul-hilang
     membuat 100vh memotong isi modal dan bottom sheet. */
  .modal-dialog {
    /* vh dulu, dvh menimpanya. Mesin yang belum mengenal dvh (Chromium di
       bawah 108 -- dan paket WebView di HP diperbarui terpisah dari Chrome,
       jadi bisa jauh tertinggal) MEMBUANG deklarasi dvh diam-diam. Tanpa
       cadangan ini panel kehilangan batas tingginya sama sekali, memanjang
       melampaui layar, dan yang terlihat tinggal bidang kosong. */
    max-height: 90vh;
    max-height: 90dvh;
  }

  /* Tabel lebar (laporan sesi kas punya 11 kolom) tidak boleh digencet sampai
     tiap kata pecah per huruf. Biarkan menggeser horizontal dengan header lengket. */
  .table-responsive {
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }

  .table-responsive .custom-table {
    min-width: 680px;
  }

  /* Wajib bersamaan dengan min-width tabel di atas. Item grid/flex punya
     min-width:auto, jadi tabel selebar 680px membuat kartu induknya menolak
     menyusut dan seluruh halaman meluber keluar layar (halaman Pengaturan
     paling terasa). min-width:0 mengembalikan hak menyusut, dan tabelnya
     tetap bisa digeser di dalam .table-responsive. */
  .content-area .card,
  .content-area .table-responsive,
  .content-area [style*="display: grid"] > * {
    min-width: 0;
  }

  .custom-table th,
  .custom-table td {
    white-space: nowrap;
  }

  /* Kolom keterangan tetap boleh membungkus, kalau tidak barisnya jadi sangat panjang */
  .custom-table td.wrap,
  .custom-table th.wrap {
    white-space: normal;
    min-width: 180px;
  }

  /* Deretan tab laporan (8 tab) jadi strip geser, bukan tembok tombol setinggi layar.
     Kepala dokumen laporan ikut menumpuk supaya alamat toko tidak jadi kolom sempit. */
  .report-doc-header {
    flex-direction: column;
    gap: 12px;
  }

  .report-doc-header > div:last-child {
    text-align: left !important;
  }

  #report-tabs-nav {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding-bottom: 4px;
  }

  #report-tabs-nav::-webkit-scrollbar {
    display: none;
  }

  #report-tabs-nav .rep-tab-btn {
    flex: 0 0 auto;
  }
}

/* Tablet lanskap: POS tetap dua kolom, panel keranjang dirampingkan supaya katalog
   menu tidak tersisa sesempit satu setengah kartu. */
@media (min-width: 769px) and (max-width: 1024px) and (orientation: landscape) {
  .pos-layout {
    grid-template-columns: 1fr 380px;
  }

  .content-area {
    padding: 18px 20px;
  }
}

/* ==========================================================================
   POS sebagai bottom sheet.

   Berlaku di HP dan juga di tablet PORTRAIT: pada iPad tegak, panel keranjang
   yang menetap hanya menyisakan dua kolom menu: katalog jadi sempit padahal
   layarnya lebar. Sebagai bottom sheet, katalog dapat lebar penuh.
   ========================================================================== */
@media (max-width: 768px),
       (max-width: 1024px) and (orientation: portrait) {
  .pos-layout {
    grid-template-columns: 1fr;
    height: auto;
    min-height: calc(100vh - 65px);
    padding-bottom: calc(75px + env(safe-area-inset-bottom));
  }

  .pos-cart-panel {
    position: fixed;
    bottom: 0;
    /* Digeser dengan transform, bukan `bottom`. Menganimasikan `bottom` memaksa
       tata letak dihitung ulang tiap frame untuk seluruh isi panel; transform
       hanya menggeser lapisan yang sudah jadi. */
    transform: translateY(100%);
    left: 0;
    right: 0;
    /* Setinggi isinya, bukan selalu 85% layar: pesanan satu item tidak lagi
       menyisakan area kosong besar di bawah tombol Bayar. */
    height: auto;
    max-height: 88vh;
    max-height: 88dvh;
    z-index: 1000;
    background: #FFF;
    border-top-left-radius: var(--radius-lg);
    border-top-right-radius: var(--radius-lg);
    box-shadow: 0 -6px 16px rgba(0, 0, 0, 0.22);
    transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1);
    /* TANPA will-change di sini, dan itu disengaja. will-change: transform
       memaksa panel ini jadi satu lapisan komposit PERMANEN. Panelnya tinggi,
       bisa digulung, dan berbayang besar -- tiap kali isinya berubah (satu
       huruf diketik) atau jendela diubah ukurannya oleh keyboard, seluruh
       lapisan harus diraster ulang. Petak yang belum selesai diraster
       digambar putih, dan itulah kedipan putih yang menghalangi layar saat
       kasir mengetik nama member. Animasinya sendiri tetap mulus: Chromium
       otomatis mempromosikan lapisan selama transisi transform berjalan. */
    display: flex;
    flex-direction: column;
    border-left: none;
    border-top: 3px solid var(--color-primary);
    /* As a bottom sheet the two panes read as one continuous surface: drop their
       individual card chrome and let the sheet own the scrolling. */
    gap: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding-bottom: env(safe-area-inset-bottom);
  }

  .pos-cart-panel.open {
    transform: translateY(0);
  }

  /* Pegangan visual bahwa panel ini bisa ditutup */
  .pos-cart-panel::before {
    content: '';
    position: sticky;
    top: 0;
    z-index: 3;
    display: block;
    width: 44px;
    height: 4px;
    margin: 8px auto 4px;
    border-radius: var(--radius-full);
    background: var(--border-color);
    flex: 0 0 auto;
  }

  .pos-sheet-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.4);
    z-index: 999;
    display: none;
  }

  .pos-sheet-backdrop.show {
    display: block;
  }

  .pos-side-card {
    border: none;
    border-radius: 0;
    box-shadow: none;
  }

  .pos-side-card + .pos-side-card {
    border-top: 1px solid var(--border-color);
  }

  .pos-side-card.checkout-card,
  .pos-side-card.cart-card {
    flex: 0 0 auto;
  }

  .customer-selector {
    max-height: none;
    overflow: visible;
  }

  .cart-items-list {
    overflow: visible;
    min-height: 0;
  }

  /* ~180px -> ~60px: satu baris ikon + judul, petunjuknya sudah jelas dari
     katalog yang terlihat di belakang sheet. */
  .cart-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    margin: 0;
    padding: 14px 0;
  }

  .cart-empty i {
    font-size: 1.25rem;
    margin-bottom: 0;
  }

  .cart-empty-hint {
    display: none;
  }

  .mobile-cart-close {
    display: inline-flex;
  }

  .mobile-cart-bar {
    display: flex !important;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    height: calc(60px + env(safe-area-inset-bottom));
    background: var(--color-primary);
    color: #FFF;
    padding: 0 18px env(safe-area-inset-bottom);
    align-items: center;
    justify-content: space-between;
    z-index: 990;
    box-shadow: 0 -4px 16px rgba(111, 78, 55, 0.35);
    cursor: pointer;
  }

  .mobile-cart-bar .cart-badge {
    background: var(--color-secondary);
    color: #FFF;
    padding: 3px 8px;
    border-radius: var(--radius-full);
    font-size: 0.7188rem;
    font-weight: 700;
  }
}

@media (max-width: 768px) {
  /* Topbar ringkas: judul satu baris, status sesi tidak melipat jadi dua baris.
     Sebelumnya "Terminal Kasir (POS)" + pill sesi memakan hampir seperlima layar. */
  .topbar {
    gap: 10px;
  }

  .page-title h2 {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 42vw;
  }

  .shift-status-pill {
    white-space: nowrap;
    max-width: 45vw;
    overflow: hidden;
    text-overflow: ellipsis;
    font-size: 0.6875rem;
    padding: 6px 10px;
  }

  /* Grup judul yang boleh menyusut, grup status yang dipertahankan: tanpa ini
     pill sesi terdorong keluar layar dan terpotong di tepi kanan. */
  .topbar > div:first-child {
    flex: 0 1 auto;
    min-width: 0;
  }

  .topbar-actions {
    gap: 8px;
    flex: 0 0 auto;
    min-width: 0;
  }

  /* Hasil pencarian member: mengalir di dalam panel, bukan mengambang.
     Sebagai dropdown mengambang di bottom sheet, daftarnya menutupi tombol Bayar
     dan terpotong tepi panel sehingga hasil terakhir tidak bisa diketuk. */
  .member-search-dropdown {
    position: static;
    /* Relatif tinggi layar yang tersisa: dengan keyboard terbuka, 260px tetap
       mendorong tombol Bayar keluar dari area yang terlihat. */
    max-height: 38vh;
    max-height: 38dvh;
    box-shadow: none;
    margin-top: 6px;
    -webkit-overflow-scrolling: touch;
  }

  .menu-card-footer {
    flex-wrap: wrap;
    row-gap: 4px;
  }

  /* Tombol di header kartu memenuhi lebar: lebih mudah ditekan, lebih rapi */
  .card-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
  }

  /* Judul dan grup tombol masing-masing satu baris penuh, tapi tombolnya
     dibiarkan membungkus dan berbagi lebar. Memaksa tiap tombol 100% membuat
     baris filter (Pengeluaran, Monitoring) meluber keluar layar. */
  .card-header > * {
    width: 100%;
  }

  .card-header > div {
    flex-wrap: wrap;
  }

  .card-header .btn {
    flex: 1 1 auto;
  }

  /* Baris flex horizontal yang sengaja ditumpuk di layar sempit */
  .stack-on-mobile {
    flex-direction: column;
    align-items: flex-start !important;
    gap: 10px !important;
  }

  .stack-on-mobile > * {
    margin-left: 0 !important;
    width: 100%;
  }

  /* Grup tombol di dalamnya membungkus, tidak memanjang keluar layar */
  .stack-on-mobile > div {
    flex-wrap: wrap;
  }

  .stack-on-mobile .btn {
    flex: 1 1 auto;
  }

  /* Baris filter periode / aksi laporan: geser horizontal daripada menumpuk */
  .filter-period-btn,
  .filter-exp-btn {
    flex: 1 1 auto;
  }

  /* Toolbar aksi laporan (Excel/PDF) menumpuk penuh supaya tidak terpotong */
  .report-actions {
    width: 100%;
  }

  .report-actions .btn {
    flex: 1 1 auto;
  }
}

@media (max-width: 480px) {
  /* Ukuran kertas struk tidak dipakai saat kerja di HP; ruang topbar lebih berharga */
  #topbar-paper-size {
    display: none;
  }

  .page-title h2 {
    max-width: 50vw;
  }

  /* "Member & Pembayaran" jangan sampai melipat dua baris dan memakan tinggi
     panel yang justru dibutuhkan untuk daftar pesanan. */
  .pos-card-title {
    font-size: 0.8125rem;
  }

  /* Gambar kartu menu dipendekkan: di layar 360px tingginya membuat hanya dua
     baris menu yang terlihat, padahal kasir butuh cepat memindai katalog. */
  .menu-card-img {
    height: 62px;
    font-size: 1.5rem;
  }

  .badge-chip {
    font-size: 0.625rem;
  }

  .modal-footer {
    flex-direction: column-reverse;
    gap: 8px;
  }

  .modal-footer .btn {
    width: 100%;
  }
}

/* ==========================================================================
   Pratinjau struk di layar

   Isi & tata letaknya sama persis dengan yang keluar di kertas (dibangun dari
   model baris yang sama di escpos.js), tapi tampilannya dibuat menyerupai
   gulungan kertas thermal: tepi sobek, garis pemisah sungguhan, spasi lega.
   ========================================================================== */

/* Latar redup di belakang kertas, kalau tidak tepi sobeknya putih di atas putih
   dan struk tidak terbaca sebagai lembaran. */
#receipt-modal-body,
#report-receipt-body {
  background: #E9E2DB;
  padding: 18px 12px !important;
}

/* Lebar isi dikunci tepat selebar kolom printer (32 untuk 58mm, 48 untuk 80mm).
   Tanpa ini kartu lebih lebar daripada barisnya: nilai yang rata kanan berhenti
   jauh sebelum tepi sementara garis pemisah memanjang penuh, dan struk terlihat
   miring. --receipt-cols diisi oleh escpos.js sesuai ukuran kertas. */
.receipt-paper {
  position: relative;
  box-sizing: content-box !important;
  width: calc(var(--receipt-cols, 32) * 1ch) !important;
  max-width: none !important;
  background: #FFFDFA;
  border: none;
  border-radius: 0;
  padding: 22px 18px 26px !important;
  margin: 6px auto;
  box-shadow: 0 6px 22px rgba(70, 45, 30, 0.16);
  color: #2A2320;
  font-size: 13px;
  letter-spacing: 0;
}

@media (max-width: 480px) {
  .receipt-paper {
    font-size: 12px;
    padding: 18px 14px 22px !important;
  }
}

/* Tanpa hiasan tepi sobek: zigzag CSS-nya terbaca sebagai coretan miring, bukan
   kertas robek. Lembaran polos dengan bayangan lembut sudah cukup jelas. */

.receipt-line {
  white-space: pre;
  font-family: inherit;
  line-height: 1.5;
}

.receipt-line.center {
  text-align: center;
}

.receipt-line.bold {
  font-weight: 700;
}

/* Nama toko */
.receipt-line.title {
  font-size: 1.5em;
  font-weight: 800;
  letter-spacing: 0.04em;
  line-height: 1.4;
  margin-bottom: 2px;
}

/* Baris TOTAL: satu-satunya angka yang harus langsung ketemu mata.
   Lebar huruf sengaja tidak diperbesar -- printer pun hanya menggandakan tinggi,
   dan font yang lebih lebar membuat 32 karakternya menjulur keluar dari kertas. */
.receipt-line.total {
  font-weight: 800;
  padding: 4px 0;
  line-height: 1.7;
}

.receipt-rule {
  border-top: 1px dashed #C9B9A8;
  margin: 7px 0;
}

.receipt-rule.strong {
  border-top: 1px solid #8A7561;
}

/* ==========================================================================
   Print CSS Engine: Thermal Receipt & Reports
   ========================================================================== */

@media print {
  /* Hiasan pratinjau tidak boleh ikut tercetak */
  .receipt-paper {
    box-shadow: none !important;
    background: #FFF !important;
    margin: 0 !important;
    max-width: 100% !important;
  }

  #receipt-modal-body,
  #report-receipt-body {
    background: #FFF !important;
    padding: 0 !important;
  }

  /* Global Hide for Non-Print elements */
  .no-print, .sidebar, .topbar, .modal-header, .modal-footer, button, #toast-container, .mobile-cart-bar {
    display: none !important;
  }

  body {
    background: #FFF !important;
    color: #000 !important;
    margin: 0 !important;
    padding: 0 !important;
  }

  /* Receipt slips print through their own iframe (see printReceipt in app.js), so the
     old body.printing-receipt isolation rules are gone. What is left below only covers
     printing a modal that happens to be open. */
  .modal-backdrop.show {
    position: static !important;
    display: block !important;
    background: transparent !important;
    padding: 0 !important;
    margin: 0 auto !important;
    width: 100% !important;
    height: auto !important;
    opacity: 1 !important;
  }

  .modal-backdrop.show .modal-dialog {
    box-shadow: none !important;
    border: none !important;
    max-width: 100% !important;
    width: 100% !important;
    padding: 0 !important;
    margin: 0 auto !important;
    max-height: none !important;
    overflow: visible !important;
    transform: none !important;
  }

  .modal-backdrop.show .modal-body {
    padding: 0 !important;
    max-height: none !important;
    overflow: visible !important;
  }

  /* Thermal Receipt Card Print Styling (72mm standard thermal POS width) */
  .thermal-receipt-card, #printable-receipt {
    display: block !important;
    visibility: visible !important;
    width: 72mm !important;
    max-width: 100% !important;
    border: none !important;
    box-shadow: none !important;
    padding: 2mm 3mm !important;
    margin: 0 auto !important;
    font-family: 'Space Mono', 'Courier New', monospace !important;
    font-size: 11px !important;
    line-height: 1.35 !important;
    color: #000 !important;
    background: #FFF !important;
  }

  .thermal-receipt-card * {
    visibility: visible !important;
    color: #000 !important;
  }

  .receipt-divider {
    border-top: 1px dashed #000 !important;
    margin: 6px 0 !important;
  }

  .receipt-divider.double {
    border-top: 2px solid #000 !important;
    margin: 8px 0 !important;
  }

  /* Report Print Mode - isolates full multi-page printable report */
  body.printing-report .report-printable-area {
    display: block !important;
    visibility: visible !important;
    width: 100% !important;
    margin: 0 !important;
    padding: 20px !important;
  }

  body.printing-report .report-printable-area * {
    visibility: visible !important;
    color: #000 !important;
  }

  body.printing-report .custom-table {
    border: 1px solid #000 !important;
  }

  body.printing-report .custom-table th, 
  body.printing-report .custom-table td {
    border: 1px solid #ccc !important;
    color: #000 !important;
  }
}

/* ==========================================================================
   Gamification Visuals: Lucky Spin & Mystery Box
   ========================================================================== */

.lucky-wheel-container {
  position: relative;
  width: 260px;
  height: 260px;
  margin: 0 auto 20px;
}

.lucky-wheel {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  border: 8px solid #C89058;
  background: conic-gradient(
    #6F4E37 0deg 60deg,
    #E6B98D 60deg 120deg,
    #8F6647 120deg 180deg,
    #D4A373 180deg 240deg,
    #5A3D2A 240deg 300deg,
    #F4EAE1 300deg 360deg
  );
  box-shadow: 0 0 24px rgba(200, 144, 88, 0.4);
  transition: transform 3.5s cubic-bezier(0.15, 0.9, 0.2, 1);
}

.lucky-wheel-pointer {
  position: absolute;
  top: -14px;
  left: 50%;
  transform: translateX(-50%);
  width: 0;
  height: 0;
  border-left: 14px solid transparent;
  border-right: 14px solid transparent;
  border-top: 24px solid #D32F2F;
  z-index: 10;
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3));
}

.mystery-box-anim {
  width: 140px;
  height: 140px;
  margin: 20px auto;
  background: #FFF;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 4.5rem;
  box-shadow: 0 10px 30px rgba(111, 78, 55, 0.2);
  cursor: pointer;
  animation: boxWiggle 1.4s infinite;
}

@keyframes boxWiggle {
  0%, 100% { transform: rotate(0deg) scale(1); }
  25% { transform: rotate(-8deg) scale(1.04); }
  75% { transform: rotate(8deg) scale(1.04); }
}

/* ==========================================================================
   Pemberitahuan & kehalusan antarmuka
   ========================================================================== */

.notif-bell {
  position: relative;
  background: transparent;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  width: 34px; height: 34px;
  cursor: pointer;
  color: var(--text-secondary);
  /* Transisi hanya pada properti yang tidak memicu layout ulang. */
  transition: background-color 0.15s ease, color 0.15s ease;
}
.notif-bell:hover { background: var(--color-primary-bg, #F4EAE1); color: var(--color-primary); }

.notif-dot {
  position: absolute; top: 5px; right: 6px;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--color-danger);
  box-shadow: 0 0 0 2px #FFF;
}

.notif-panel {
  position: absolute; right: 0; top: calc(100% + 8px);
  width: min(360px, calc(100vw - 32px));
  max-height: 70vh; overflow-y: auto;
  background: #FFF;
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  box-shadow: 0 10px 30px rgba(70, 45, 30, 0.18);
  z-index: 1200;
}
.notif-head {
  font-size: 0.75rem; font-weight: 800; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--text-muted);
  padding: 12px 14px 8px;
}
.notif-item {
  display: flex; gap: 10px;
  padding: 10px 14px;
  border-top: 1px solid var(--border-light);
  font-size: 0.8125rem;
}
.notif-item .notif-ico { flex: 0 0 18px; margin-top: 2px; }
.notif-item.danger  .notif-ico { color: var(--color-danger); }
.notif-item.warning .notif-ico { color: var(--color-warning); }
.notif-item.info    .notif-ico { color: var(--color-primary); }
.notif-item strong { display: block; margin-bottom: 2px; }
.notif-item span   { color: var(--text-muted); font-size: 0.75rem; line-height: 1.45; }
.notif-item a { color: var(--color-primary); font-size: 0.75rem; font-weight: 700; }
.notif-empty { padding: 14px; color: var(--text-muted); font-size: 0.8125rem; text-align: center; }

/* Rangka pemuatan. Menahan tinggi baris supaya isi tidak melompat saat data
   datang -- lompatan itu yang paling terasa sebagai "tidak halus", jauh lebih
   daripada lamanya menunggu. */
.skeleton {
  background: linear-gradient(90deg, #EFE9E3 25%, #F7F3EF 37%, #EFE9E3 63%);
  background-size: 400% 100%;
  animation: skeleton-sweep 1.2s ease-in-out infinite;
  border-radius: 4px;
  color: transparent !important;
}
@keyframes skeleton-sweep {
  0% { background-position: 100% 50%; }
  100% { background-position: 0 50%; }
}
.skeleton-row { height: 14px; margin: 9px 0; }

/* Hormati pengguna yang mematikan animasi di sistemnya. */
@media (prefers-reduced-motion: reduce) {
  .skeleton { animation: none; }
  * { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}

/* Bilah progres navigasi. Reload halaman penuh tetap terjadi, tapi jeda yang
   disertai indikator terasa jauh lebih pendek daripada jeda hening. */
.nav-progress {
  position: fixed; top: 0; left: 0;
  height: 2px; width: 0;
  background: var(--color-primary);
  z-index: 3000;
  opacity: 0;
  pointer-events: none;
}
.nav-progress.running {
  opacity: 1;
  /* Berhenti di 90%: sisanya tidak bisa diketahui, dan bilah yang penuh lalu
     menggantung terasa seperti macet. */
  animation: nav-progress-run 2.4s ease-out forwards;
}
@keyframes nav-progress-run {
  0%   { width: 0; }
  40%  { width: 55%; }
  100% { width: 90%; }
}
@media (prefers-reduced-motion: reduce) {
  .nav-progress.running { animation: none; width: 90%; }
}

/* ==========================================================================
   Layar cari member (HP)

   Ditulis dengan properti paling jinak yang ada. Tidak ada transform,
   transisi, bayangan, backdrop-filter, maupun sudut membulat pada elemen
   sebesar layar -- semuanya pemicu lapisan komposit, dan lapisan komposit
   besar yang diraster ulang tiap keyboard bergerak persis yang melahirkan
   kedipan putih di cangkang WebView.
   ========================================================================== */
.member-screen {
  display: none;
}

@media (max-width: 768px),
       (max-width: 1024px) and (orientation: portrait) {
  .member-screen.open {
    display: block;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1100;
    background: #FFF;
  }

  /* Sheet keranjang dikeluarkan dari pohon render selama layar ini terbuka.
     display:none, bukan sekadar digeser: yang tidak dirender tidak bisa
     meninggalkan petak putih. */
  body.member-screen-open .pos-cart-panel,
  body.member-screen-open .pos-sheet-backdrop,
  body.member-screen-open .mobile-cart-bar {
    display: none !important;
  }

  .member-screen-head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 12px;
    border-bottom: 1px solid var(--border-color);
    background: #FAF8F5;
  }

  .member-screen-head .form-control {
    flex: 1;
    min-width: 0;
    height: 40px;
    font-size: 0.8125rem;
  }

  .member-screen-back {
    background: transparent;
    border: none;
    font-size: 1rem;
    color: var(--color-primary);
    padding: 8px 10px;
    cursor: pointer;
  }

  .member-screen-body {
    position: absolute;
    top: 61px;
    left: 0;
    right: 0;
    bottom: 0;
    overflow-y: auto;
    padding: 4px 0 24px;
  }

  /* Baris hasil memakai gaya dropdown yang sudah ada, tanpa kotak mengambang. */
  .member-screen-body .member-search-item {
    border-bottom: 1px solid var(--border-light);
  }
}
