@font-face { font-family: 'Noto Sans Khmer'; font-style: normal; font-weight: 400; src: url('/static/vendor/noto-khmer/noto-sans-khmer-khmer-400-normal.woff2') format('woff2'); }
@font-face { font-family: 'Noto Sans Khmer'; font-style: normal; font-weight: 500; src: url('/static/vendor/noto-khmer/noto-sans-khmer-khmer-500-normal.woff2') format('woff2'); }
@font-face { font-family: 'Noto Sans Khmer'; font-style: normal; font-weight: 600; src: url('/static/vendor/noto-khmer/noto-sans-khmer-khmer-600-normal.woff2') format('woff2'); }
@font-face { font-family: 'Noto Sans Khmer'; font-style: normal; font-weight: 700; src: url('/static/vendor/noto-khmer/noto-sans-khmer-khmer-700-normal.woff2') format('woff2'); }

:root {
  --primary: #4f46e5;
  --primary-dark: #3730a3;
  --primary-light: #818cf8;
  --accent: #06b6d4;
  --success: #10b981;
  --warning: #f59e0b;
  --danger: #ef4444;
  --ink: #0f172a;
  --muted: #64748b;
  --border: #e2e8f0;
  --bg: #f8fafc;
  --card: #ffffff;
  /* Table background/text color - configurable from Settings (see
     the "ពណ៍តារាង" section there) rather than fixed in code, so a
     color change never needs another deploy. Falls back to the same
     grey/white "reset default" pair get_site_settings() itself
     defaults to, in case site_settings somehow wasn't passed to a
     given page. */
  --table-bg: #ffffff;
  --table-text: #101828;
  /* Header row color - kept as its own pair (not derived from
     --table-bg above) precisely so the header always reads as a
     distinct band above the data rows, even when someone picks a
     --table-bg close to the old fixed navy header color. Also
     configurable from Settings, same as the body colors. */
  --table-header-bg: #4338ca;
  --table-header-text: #ffffff;
  --radius: 16px;
  --radius-sm: 12px;
  --shadow: 0 4px 24px rgba(15, 23, 42, 0.06);
  --shadow-lg: 0 12px 40px rgba(15, 23, 42, 0.1);
}

* { box-sizing: border-box; }

body {
  font-family: 'Noto Sans Khmer', 'Khmer OS', system-ui, -apple-system, sans-serif;
  color: var(--ink);
  background: var(--bg);
  min-height: 100vh;
  line-height: 1.6;
}

/* ========== Navbar ========== */
.topbar {
  background: linear-gradient(135deg, #0f172a 0%, #1e1b4b 50%, #0c4a6e 100%);
  border-bottom: 1px solid rgba(255,255,255,0.06);
  position: sticky;
  top: 0;
  z-index: 1000;
}

/* Phone PWA shell for submitters — gold bar + bottom tabs like a ministry app */
.phone-app {
  background: #F7F4F0;
}
.phone-app .topbar {
  background: #E8B923;
  border-bottom: none;
  box-shadow: 0 2px 8px rgba(120, 80, 0, 0.18);
}
.phone-app .brand { color: #3F2A00 !important; }
.phone-app .brand-title { color: #3F2A00; font-size: 1.05rem; }
.phone-app .brand-subtitle { color: #6B4E00; opacity: 1; display: block; font-size: 0.68rem; letter-spacing: 0.04em; }
.phone-app .top-post-info { color: #3F2A00; line-height: 1.2; white-space: nowrap; }
.phone-app .top-post-info #topPostName { font-weight: 700; font-size: 0.92rem; }
.phone-app .top-post-info #topPostPhone { font-size: 0.75rem; color: #6B4E00; }
.phone-app.has-post .brand-subtitle { display: none !important; }
.phone-app .top-post-info #topPostName,
.phone-app .top-post-info #topPostPhone { display: inline !important; }
.phone-app .top-post-info #topPostName { font-size: 0.74rem; }
.phone-app .top-post-info #topPostPhone { font-size: 0.7rem; margin-left: 6px; }
.phone-app .brand-logo, .phone-app .brand-fallback {
  width: 44px; height: 44px; border-radius: 50%;
  background: #fff; border: 2px solid rgba(255,255,255,0.9); padding: 2px;
}
.phone-app .notif-bell-btn { color: #3F2A00; }
.phone-app .notif-bell-btn .badge { background: #dc2626 !important; }
.phone-app main.container { padding-bottom: 88px; }
.phone-app .hero {
  background: #fff;
  color: #1e293b;
  border: none;
  box-shadow: 0 8px 24px rgba(15,23,42,.06);
}
.phone-app .hero h1 { color: #1e293b; }
.phone-app .hero p { color: #64748b; }
.phone-bottom-nav {
  display: none;
}
.phone-app .phone-bottom-nav {
  display: flex;
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 1100;
  background: #E8B923;
  padding: 6px 4px calc(8px + env(safe-area-inset-bottom));
  justify-content: space-around;
  box-shadow: 0 -2px 10px rgba(120,80,0,0.15);
}
.phone-bottom-nav a, .phone-bottom-nav button {
  flex: 1;
  background: none;
  border: none;
  color: #3F2A00;
  text-align: center;
  font-size: 0.68rem;
  font-weight: 600;
  text-decoration: none;
  padding: 4px 2px 2px;
  line-height: 1.15;
}
.phone-bottom-nav i { display: block; font-size: 1.25rem; margin-bottom: 2px; }
.phone-bottom-nav .is-active { color: #111827; }
.phone-bottom-nav .badge { min-width: 16px; }
.phone-app.staff-app .nav-actions { display: none !important; }
.phone-app.staff-app main.container-fluid,
.phone-app.staff-app main.container { padding-bottom: 88px; }

/* Continuously scrolling credit line, right under the title row - the
   actual scrolling is driven entirely by JS (see the script block near
   the end of this file) rather than a CSS @keyframes animation, since
   the CSS-only version relied on the browser correctly sizing a
   width:max-content flex container to calculate a percentage-based
   translateX, and that calculation wasn't landing the same way on every
   browser - measuring the real pixel width in JS and stepping the
   position directly removes that ambiguity entirely. */
.credit-marquee {
  background: #0c1a3a;
  border-bottom: 1px solid rgba(255,255,255,0.06);
  overflow: hidden;
  white-space: nowrap;
  min-height: 26px;
  position: sticky;
  /* "top" is set dynamically in JS to exactly the topbar's own rendered
     height (which varies with the logo/title), so this always sits
     directly under it with no gap or overlap - see the script block
     near the end of this file. */
  z-index: 999;
}

.credit-marquee-track {
  display: inline-block;
  white-space: nowrap;
  position: relative;
}

.credit-marquee-track span {
  padding: 6px 0;
  padding-right: 40px;
  font-size: 0.75rem;
  color: rgba(255,255,255,0.55);
  white-space: nowrap;
}

.brand {
  color: #fff !important;
  text-decoration: none;
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}

.brand-logo, .brand-fallback {
  width: 42px;
  height: 42px;
  border-radius: 12px;
  object-fit: cover;
  flex-shrink: 0;
}

.brand-logo {
  background: rgba(255,255,255,0.1);
  padding: 3px;
  border: 1px solid rgba(255,255,255,0.15);
}

.brand-fallback {
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, var(--primary), var(--accent));
  font-size: 20px;
}

.brand-title {
  font-weight: 700;
  font-size: 1rem;
  line-height: 1.2;
  letter-spacing: -0.01em;
}

.brand-subtitle {
  font-size: 0.7rem;
  opacity: 0.6;
  margin-top: 2px;
  font-weight: 400;
}

/* Plain icon, not a boxed button - no background/border, just the icon
   itself in the navbar's own light text color, matching how the brand
   logo/title sit un-boxed on the other side of the same row. */
.notif-bell-btn {
  background: none;
  border: none;
  color: #fff;
  font-size: 1.25rem;
  padding: 4px;
  line-height: 1;
  flex-shrink: 0;
}
.notif-bell-btn:hover {
  opacity: 0.8;
}
.bell-new-announcement {
  animation: bellPulse 1s ease-in-out infinite;
}
@keyframes bellPulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.25); }
}

.nav-pill {
  border: 1px solid rgba(255,255,255,0.15) !important;
  color: rgba(255,255,255,0.85) !important;
  border-radius: 10px !important;
  padding: 7px 14px !important;
  font-size: 0.85rem;
  font-weight: 500;
  transition: all 0.2s ease;
  background: transparent;
}

.nav-pill:hover {
  background: rgba(255,255,255,0.12) !important;
  color: #fff !important;
  border-color: rgba(255,255,255,0.25) !important;
}

.nav-pill.active {
  background: rgba(255,255,255,0.15) !important;
  color: #fff !important;
}

/* ========== Layout ========== */
.page-shell {
  max-width: 100%;
}

/* ========== Hero ========== */
.hero {
  background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 45%, #0891b2 100%);
  color: #fff;
  border-radius: 20px;
  padding: 28px 32px;
  box-shadow: 0 16px 48px rgba(79, 70, 229, 0.25);
  position: relative;
  overflow: hidden;
}

.hero::before {
  content: '';
  position: absolute;
  top: -50%;
  right: -20%;
  width: 400px;
  height: 400px;
  background: radial-gradient(circle, rgba(255,255,255,0.12) 0%, transparent 70%);
  pointer-events: none;
}

.hero h1 {
  font-weight: 700;
  font-size: clamp(1.3rem, 3vw, 1.75rem);
  margin: 0;
  letter-spacing: -0.02em;
}

.hero p {
  opacity: 0.85;
  margin: 6px 0 0;
  font-size: 0.95rem;
  font-weight: 400;
}

.hero-icon {
  width: 56px;
  height: 56px;
  border-radius: 16px;
  background: rgba(255,255,255,0.15);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.6rem;
  flex-shrink: 0;
}

/* ========== Cards ========== */
.card {
  border: 1px solid var(--border) !important;
  border-radius: var(--radius) !important;
  background: var(--card);
  box-shadow: var(--shadow);
}

.section-card {
  padding: 28px;
}

.section-title {
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--ink);
  display: flex;
  align-items: center;
  gap: 8px;
}

.section-title .icon {
  width: 32px;
  height: 32px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.95rem;
  background: linear-gradient(135deg, rgba(79,70,229,0.1), rgba(6,182,212,0.1));
  color: var(--primary);
}

/* ========== Forms ========== */
.field-label {
  font-weight: 600;
  color: #334155;
  margin-bottom: 6px;
  font-size: 0.9rem;
}

.form-control, .form-select {
  min-height: 48px;
  font-size: 0.95rem;
  border-radius: var(--radius-sm);
  border: 1.5px solid var(--border);
  background: #fff;
  padding: 10px 14px;
  transition: border-color 0.2s, box-shadow 0.2s;
  color: var(--ink);
}

.form-control:focus, .form-select:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.12);
  outline: none;
}

.form-select:disabled {
  background: #f1f5f9;
  color: #94a3b8;
  cursor: not-allowed;
}

.form-control::placeholder {
  color: #94a3b8;
}

/* ========== Buttons ========== */
.btn {
  min-height: 44px;
  border-radius: var(--radius-sm);
  font-weight: 600;
  font-size: 0.9rem;
  padding: 10px 20px;
  transition: all 0.2s ease;
  border: none;
}

.btn-primary {
  background: linear-gradient(135deg, var(--primary) 0%, #7c3aed 100%);
  color: #fff;
  box-shadow: 0 4px 14px rgba(79, 70, 229, 0.3);
}

.btn-primary:hover {
  background: linear-gradient(135deg, var(--primary-dark) 0%, #6d28d9 100%);
  transform: translateY(-1px);
  box-shadow: 0 6px 20px rgba(79, 70, 229, 0.35);
  color: #fff;
}

.btn-primary:active {
  transform: translateY(0);
}

.btn-lg {
  min-height: 52px;
  font-size: 1.05rem;
  border-radius: 14px;
  padding: 12px 28px;
}

.btn-outline-secondary {
  border: 1.5px solid var(--border);
  color: var(--muted);
  background: #fff;
}

.btn-outline-secondary:hover {
  background: #f1f5f9;
  border-color: #cbd5e1;
  color: var(--ink);
}

.btn-outline-danger {
  border: 1.5px solid #fecaca;
  color: var(--danger);
  background: #fff;
}

.btn-outline-danger:hover {
  background: #fef2f2;
  border-color: #fca5a5;
}

.btn-outline-warning {
  border: 1.5px solid rgba(245,158,11,0.4);
  color: #fbbf24;
  background: transparent;
}

.btn-outline-warning:hover {
  background: rgba(245,158,11,0.15);
  color: #fcd34d;
}

/* ========== Activity Choice ========== */
.activity-choice {
  border: 1.5px solid var(--border);
  border-radius: 14px;
  padding: 14px 16px;
  display: flex;
  align-items: center;
  gap: 12px;
  transition: all 0.2s ease;
  background: #fff;
  cursor: pointer;
  user-select: none;
}

.activity-choice:hover {
  border-color: #c7d2fe;
  background: #fafafe;
}

.activity-choice:has(input:checked) {
  border-color: var(--primary);
  background: linear-gradient(135deg, rgba(79,70,229,0.06), rgba(124,58,237,0.04));
  box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.08);
}

.activity-choice input {
  width: 20px;
  height: 20px;
  accent-color: var(--primary);
  flex-shrink: 0;
}

.activity-choice .act-icon {
  width: 40px;
  height: 40px;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.15rem;
  flex-shrink: 0;
}

.activity-choice .act-icon.forum {
  background: linear-gradient(135deg, #e0e7ff, #c7d2fe);
  color: #4338ca;
}

.activity-choice .act-icon.publicity {
  background: linear-gradient(135deg, #fef3c7, #fde68a);
  color: #b45309;
}

/* ========== Photo Zone ========== */
.photo-zone {
  border: 2px dashed #cbd5e1;
  border-radius: 16px;
  padding: 24px;
  background: linear-gradient(180deg, #f8fafc 0%, #f1f5f9 100%);
  text-align: center;
  transition: border-color 0.2s;
}

.photo-zone:hover {
  border-color: var(--primary-light);
}

.gps-box {
  border-radius: 10px;
  padding: 10px 14px;
  background: #f1f5f9;
  font-size: 0.85rem;
  display: flex;
  align-items: center;
  gap: 8px;
}

.gps-box.success {
  background: #ecfdf5;
  color: #065f46;
}

.gps-box.error {
  background: #fef2f2;
  color: #991b1b;
}

/* ========== Stats ========== */
.stat-card {
  padding: 20px;
  text-align: center;
  height: 100%;
  border-radius: var(--radius) !important;
  transition: transform 0.2s, box-shadow 0.2s;
}

.stat-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-lg);
}

.stat-value {
  font-size: 1.75rem;
  font-weight: 700;
  margin-top: 4px;
  letter-spacing: -0.02em;
}

.stat-label {
  font-size: 0.8rem;
  color: var(--muted);
  font-weight: 500;
}

.stat-icon {
  width: 36px;
  height: 36px;
  border-radius: 10px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1rem;
  margin-bottom: 8px;
}

/* ========== Table ========== */
.table {
  font-size: 0.9rem;
}

.table thead th {
  white-space: nowrap;
  font-weight: 600;
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: #64748b;
  background: #f8fafc !important;
  border-bottom: 2px solid var(--border) !important;
  padding: 12px 14px !important;
  text-align: center !important;
  vertical-align: middle !important;
}

.table td {
  padding: 12px 14px !important;
  vertical-align: middle !important;
  text-align: center !important;
  border-color: #f1f5f9;
}

.table-hover > tbody > tr:hover {
  background: #f8fafc;
}

/* Dark table theme - applies everywhere (this app has many pages with
   their own colored header variants: publicity/forum sections, totals
   rows, etc.) - rather than editing each page's own table CSS
   individually, this single block overrides all of them at once with
   !important, so every table on every page gets the same black
   background + white text regardless of what color scheme that page
   originally set for itself. */
.table,
.table td,
.table tbody td,
.table .group-pub, .table .group-forum, .table .sub-pub, .table .sub-forum {
  background-color: var(--table-bg) !important;
  color: var(--table-text) !important;
  border-color: #6b7280 !important;
}
.table thead th {
  background-color: var(--table-header-bg) !important;
  color: var(--table-header-text) !important;
  border-color: #16304d !important;
}
/* The totals row is deliberately the one exception to the black
   table theme above - a white background with dark text sets it
   visually apart from the ordinary black data rows around it, making
   it read as a distinct summary line rather than just another row. */
.table .totals-row td {
  background-color: #fff !important;
  color: #0f172a !important;
  border-color: #cbd5e1 !important;
}
/* :not(...) here is load-bearing, not decoration - .table-hover
   matches via DOM ancestry, not "belongs to this exact <table>", so
   without it this rule was ALSO matching every row inside a nested
   .hierarchy-children/.province-children detail table (they're still
   DOM descendants of the outer summary table's own .table-hover
   class, several levels down through the <td> that holds them) -
   hovering a detail row got this summary-level indigo color even
   though a separate, correctly-scoped rule further down was also
   trying to color it something else entirely. Excluding both
   containers here is what actually stops that other rule from ever
   being in the running for those rows in the first place. */
.table-hover > tbody > tr:hover > td {
  background-color: #4338ca !important;
  color: #fff !important;
}
.table-hover > tbody > tr:hover > td.hierarchy-children,
.table-hover > tbody > tr:hover > td.province-children {
  background-color: #fff !important;
  color: #0f172a !important;
}
/* A badge or button with a light/white background (Bootstrap's
   .bg-light, or the default background every .btn-outline-* variant
   has) is invisible or looks like a stray white block against the
   black table background above - the "GPS ត្រូវ" is invisible /
   pending badge, and every action button (Map, delete, photo
   viewer...) in a table row, fall into this. Each keeps its own
   border/icon/text color (still meaningful - red for delete, green
   for verified, etc.) but gets a transparent background instead of a
   light one, so it blends into the black row rather than floating on
   top of it as a separate white patch. */
.table .badge.bg-light {
  background-color: #1f2937 !important;
  color: var(--table-text) !important;
}
/* Catches every Bootstrap text-color utility class (text-muted,
   text-success, text-danger, etc.) wherever it turns up inside a
   table cell - rather than tracking down and separately overriding
   each individual spot across every report/list template that uses
   one of these for a date, a status label, a small note under a
   value, and so on, this one rule forces all of them white at once,
   the same "plain white everywhere, easier to read together" request
   already applied to the buttons/badges above. */
.table .text-muted, .table .text-success, .table .text-danger, .table .text-warning,
.table .text-primary, .table .text-secondary, .table .text-info, .table .text-dark,
.table small, .table .small {
  color: var(--table-text) !important;
}
/* The totals row's own white background (set further below) needs
   dark text to stay readable - re-asserted here since it's more
   specific than the catch-all rule just above and would otherwise
   lose to it in the source order. */
.table .totals-row .text-muted, .table .totals-row .text-success, .table .totals-row .text-danger,
.table .totals-row .text-warning, .table .totals-row .text-primary, .table .totals-row .text-secondary,
.table .totals-row .text-info, .table .totals-row .text-dark, .table .totals-row small, .table .totals-row .small {
  color: #0f172a !important;
}
.table .btn-outline-secondary,
.table .btn-outline-danger,
.table .btn-outline-primary,
.table .btn-outline-success,
.table .btn-outline-warning,
.table .btn-outline-info {
  background-color: transparent !important;
}
/* Each outline button's icon/text and border color set explicitly,
   rather than left to inherit - an <a>-tag button (the Edit link)
   was actually falling back to the browser's own default unvisited-
   link blue (#0000EE) instead of picking up Bootstrap's intended
   color at all, and the warning (reset password) button's border was
   rendering at only 40% opacity, both close to invisible against the
   black table background above. All set to the same plain white now
   (rather than each variant's own distinct color) - easier to read
   at a glance than several different colors side by side. */
.table .btn-outline-secondary, .table .btn-outline-danger, .table .btn-outline-primary,
.table .btn-outline-success, .table .btn-outline-warning, .table .btn-outline-info {
  color: var(--table-text) !important;
  border-color: var(--table-text) !important;
}
.table .btn-outline-secondary i, .table .btn-outline-danger i, .table .btn-outline-primary i,
.table .btn-outline-success i, .table .btn-outline-warning i, .table .btn-outline-info i {
  color: inherit !important;
}
.table .btn-outline-secondary:hover, .table .btn-outline-danger:hover, .table .btn-outline-primary:hover,
.table .btn-outline-success:hover, .table .btn-outline-warning:hover, .table .btn-outline-info:hover {
  background-color: #1f2937 !important;
}

/* Every page with a summary -> click to expand -> detail structure
   (province_summary's province rows expanding to their communes,
   users' province groups expanding to individual accounts, posts'
   province/district/commune/village drill-down) deliberately swaps
   to the OPPOSITE color scheme for the expanded detail table - white
   background, dark text - rather than the black/white summary theme
   above, so the two levels read as visually distinct at a glance
   rather than the detail view just looking like more of the same
   black table underneath. Higher specificity than the plain .table
   rules earlier (three selectors deep instead of two) is what makes
   this win for anything nested inside one of these two containers,
   regardless of source order. */
.hierarchy-children .table, .province-children .table,
.hierarchy-children .table th, .hierarchy-children .table td,
.province-children .table th, .province-children .table td,
.hierarchy-children .table tbody td, .province-children .table tbody td {
  background-color: #fff !important;
  color: #0f172a !important;
  border-color: #cbd5e1 !important;
}
.hierarchy-children .table thead th, .province-children .table thead th {
  background-color: var(--table-header-bg) !important;
  color: var(--table-header-text) !important;
  border-color: #16304d !important;
}
.hierarchy-children .table .text-muted, .province-children .table .text-muted,
.hierarchy-children .table .text-success, .province-children .table .text-success,
.hierarchy-children .table .text-danger, .province-children .table .text-danger,
.hierarchy-children .table .text-warning, .province-children .table .text-warning,
.hierarchy-children .table .text-primary, .province-children .table .text-primary,
.hierarchy-children .table .text-secondary, .province-children .table .text-secondary,
.hierarchy-children .table .text-info, .province-children .table .text-info,
.hierarchy-children .table .text-dark, .province-children .table .text-dark,
.hierarchy-children .table small, .province-children .table small,
.hierarchy-children .table .small, .province-children .table .small {
  color: #0f172a !important;
}
.hierarchy-children .table .btn-outline-secondary, .province-children .table .btn-outline-secondary,
.hierarchy-children .table .btn-outline-danger, .province-children .table .btn-outline-danger,
.hierarchy-children .table .btn-outline-primary, .province-children .table .btn-outline-primary,
.hierarchy-children .table .btn-outline-success, .province-children .table .btn-outline-success,
.hierarchy-children .table .btn-outline-warning, .province-children .table .btn-outline-warning,
.hierarchy-children .table .btn-outline-info, .province-children .table .btn-outline-info {
  color: #0f172a !important;
  border-color: #0f172a !important;
  background-color: transparent !important;
}
/* Native CSS :hover, not JS - a JS mouseover/mouseout listener
   turned out not to fire reliably for every kind of mouse movement
   across these dynamically-generated rows, which is strictly worse
   than the plain CSS this replaces. Written with enough of its own
   selector weight (table + tbody + tr:hover, all under
   .hierarchy-children/.province-children) to beat the general
   .table-hover rule's specificity outright, on top of that rule
   already excluding these two containers via :not() - two
   independent reasons for this one to win, not just one. */
.hierarchy-children table > tbody > tr:hover > td,
.province-children table > tbody > tr:hover > td {
  background-color: #dbeafe !important;
  color: #0f172a !important;
}

/* Fullscreen "maximize" state for a table card - toggled by
   toggleTableMaximize() below rather than a separate page, so a wide
   table with many columns gets the whole screen to work with without
   navigating away from the page it's already on. */
.export-area.table-maximized {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1060;
  margin: 0 !important;
  border-radius: 0 !important;
  overflow: auto;
  background: var(--card);
}
/* The maximize button itself must float ABOVE the fixed, full-screen
   overlay above once active - it started out sitting in the ordinary
   toolbar row above the table card, which that overlay now covers
   completely, leaving no way to click it again to minimize back. */
.table-maximize-btn.maximized {
  position: fixed;
  top: 12px;
  right: 12px;
  z-index: 1070;
}
.table-maximize-btn .bi-arrows-fullscreen,
.table-maximize-btn.maximized .bi-fullscreen-exit {
  display: inline-block;
}
.table-maximize-btn .bi-fullscreen-exit,
.table-maximize-btn.maximized .bi-arrows-fullscreen {
  display: none;
}

.num-highlight,
.table .num-highlight {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.8em;
  padding: 0.15em 0.5em;
  border-radius: 999px;
  background: #facc15 !important;
  color: #1e293b !important;
  font-weight: 600;
}

.badge {
  font-weight: 600;
  font-size: 0.75rem;
  padding: 5px 10px;
  border-radius: 8px;
}

/* ========== Settings Preview ========== */
.settings-preview {
  border-radius: 16px;
  padding: 24px;
  color: #fff;
  background: linear-gradient(135deg, #0f172a 0%, #4f46e5 50%, #0891b2 100%);
}

/* ========== Alerts ========== */
.alert {
  border-radius: 12px !important;
  border: none !important;
  font-weight: 500;
  font-size: 0.9rem;
}

/* ========== Login ========== */
.login-card {
  border: none !important;
  box-shadow: var(--shadow-lg) !important;
  border-radius: 24px !important;
}

/* ========== Empty State ========== */
.empty-state {
  text-align: center;
  padding: 48px 24px;
  color: var(--muted);
}

.empty-state .empty-icon {
  font-size: 3rem;
  opacity: 0.4;
  margin-bottom: 12px;
}

/* ========== Responsive ========== */
@media (max-width: 768px) {
  .topbar .container-fluid {
    padding: 10px 14px !important;
  }
  .brand-title { font-size: 1.15rem; }
  .brand-subtitle { display: none; }
  .brand-logo, .brand-fallback {
    width: 48px;
    height: 48px;
    border-radius: 12px;
  }
  .nav-actions {
    width: 100%;
    overflow-x: auto;
    padding-top: 8px;
    gap: 6px !important;
    -webkit-overflow-scrolling: touch;
  }
  .nav-actions .nav-pill {
    white-space: nowrap;
    font-size: 0.8rem;
    padding: 6px 12px !important;
  }
  .hero {
    border-radius: 18px;
    padding: 22px;
  }
  .hero::before {
    width: 260px;
    height: 260px;
  }
  .hero-icon {
    width: 48px;
    height: 48px;
    font-size: 1.3rem;
    border-radius: 14px;
  }
  /* On a narrow screen every section card sits directly under the last
     one with nothing beside it, so a flat, barely-there shadow reads as
     no depth at all - a touch more lift here is what keeps the same
     layered, "held above the page" feel the desktop layout gets for
     free from having cards side by side to compare against. */
  .section-card {
    padding: 20px;
    border-radius: 18px;
    box-shadow: 0 6px 20px rgba(15, 23, 42, 0.08);
  }
  .section-title {
    font-size: 1rem;
  }
  .section-title .icon {
    width: 38px;
    height: 38px;
    border-radius: 10px;
    font-size: 1.05rem;
    box-shadow: 0 2px 8px rgba(79, 70, 229, 0.15);
  }
  .stat-value {
    font-size: 1.4rem;
  }
  /* A phone screen is all thumb, no mouse hover - the lift-on-hover
     buttons rely on desktop's :hover translateY never quite lands here,
     so pressing one instead gives a quick, deliberate scale-down: the
     same "this responded to me" feedback a hover would give, just
     tuned for touch instead. */
  .btn:active {
    transform: scale(0.97);
  }
  .btn-lg {
    border-radius: 16px;
  }
  .form-control, .form-select {
    border-radius: 12px;
  }
  .photo-zone {
    border-radius: 18px;
    padding: 18px;
  }
  .gps-box {
    border-radius: 12px;
  }
}

/* Custom Khmer calendar popup - shared across every page that needs a
   date field (submission form, and the date_from/date_to filters on
   the reports pages) - the native <input type="date"> picker is drawn
   entirely by the browser/OS and can't be made to show Khmer month
   names or Khmer numerals inside it, so this replaces it with a small,
   self-contained calendar built from plain HTML/CSS/JS instead, which
   this app fully controls the language and styling of. One shared
   overlay/popup is used no matter which page's date field opened it -
   see initKhmerDatePicker in the script block below. */
.khmer-cal-overlay {
  position: fixed;
  inset: 0;
  z-index: 20000;
  background: rgba(15, 23, 42, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}
.khmer-calendar-popup {
  position: relative;
  background: #fff;
  border: 1px solid var(--border, #e2e8f0);
  border-radius: 16px;
  box-shadow: 0 16px 40px rgba(0,0,0,0.25);
  padding: 16px;
  width: min(340px, 100%);
}
.khmer-cal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
  font-weight: 600;
}
.khmer-cal-header button {
  border: none;
  background: #f1f5f9;
  border-radius: 6px;
  width: 32px;
  height: 32px;
  cursor: pointer;
}
.khmer-cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
  text-align: center;
}
.khmer-cal-grid .dow {
  font-size: 0.75rem;
  color: #94a3b8;
  padding: 4px 0;
}
.khmer-cal-grid .day {
  padding: 6px 0;
  border-radius: 6px;
  cursor: pointer;
  font-size: 0.9rem;
}
.khmer-cal-grid .day:hover {
  background: #e0e7ff;
}
.khmer-cal-grid .day.selected {
  background: #4f46e5;
  color: #fff;
}
.khmer-cal-grid .day.today {
  border: 2px solid #4f46e5;
  font-weight: 700;
}
.khmer-cal-grid .day.today.selected {
  border-color: #fff;
}
.khmer-cal-grid .day.empty {
  cursor: default;
}
/* Readable, tappable text box standing in for the native date input on
   every page that uses the shared Khmer calendar above. */
.khmer-date-text {
  cursor: pointer;
  background: #fff;
}
@media print {
  .topbar, .no-print, .nav-actions, .btn, nav, .alert { display: none !important; }
  .page-shell { padding: 0 !important; }
  .card { box-shadow: none !important; }
  /* Print/Save-PDF only ever needs the page's own title and the table
     itself - everything else on the page (the hero's icon/subtitle,
     filter forms, any other card besides the table one) is just
     interactive chrome for the on-screen view, not part of what
     anyone printing or saving this as a PDF actually wants on the
     page. */
  .hero-icon, .hero p { display: none !important; }
  .hero { background: none !important; padding: 0 !important; margin-bottom: 12px !important; box-shadow: none !important; }
  .hero h1 { color: #000 !important; font-size: 1.3rem !important; }
  .card:not(.export-area) { display: none !important; }
  /* The on-screen dark table theme (black background, white text)
     below is deliberately reverted back to a normal light background
     with dark text here - practical for anyone who actually prints a
     physical copy (a full black background would use far more ink/
     toner than the table itself), and still normal, readable body
     text if saved as a PDF through the browser's print dialog rather
     than the site's own dedicated PDF-export buttons. */
  .table, .table th, .table td, .table thead th, .table tbody td,
  .table .group-pub, .table .group-forum, .table .sub-pub, .table .sub-forum,
  .table .totals-row td {
    background-color: #fff !important;
    color: #000 !important;
    border-color: #999 !important;
  }
  /* Every scrollable table wrapper on this site (sticky headers use
     max-height + overflow-y:auto to scroll on screen) would otherwise
     get clipped to just its on-screen visible height when printed -
     browsers print only what's visible inside a scrolling container,
     not its full scrolled content. Forcing these back to their
     natural, unclipped height for print is what lets the table's
     remaining rows flow onto further printed/PDF pages instead of
     being cut off after the first screenful. */
  .table-responsive, [style*="max-height"] {
    overflow: visible !important;
    max-height: none !important;
    height: auto !important;
  }
  table thead th {
    position: static !important;
  }
  .totals-row td {
    position: static !important;
  }
  /* Colored backgrounds (table header shading, badges, the sticky
     totals row) otherwise silently print as plain white in some
     browsers, since color/background isn't printed by default unless
     explicitly told to - confirmed working correctly once added to a
     sibling app's own print styles. */
  * {
    -webkit-print-color-adjust: exact !important;
    print-color-adjust: exact !important;
  }
  /* An explicit, plain border color on every cell - Bootstrap's own
     border relies on a CSS custom property that some browsers drop
     when printing, which otherwise shows some rows with a visible
     border and others without, inconsistently. */
  .table > :not(caption) > * > * {
    border: 1px solid #999 !important;
  }
  .table {
    border: 1px solid #999 !important;
    border-collapse: separate !important;
  }
  .table thead th {
    border-bottom: 2px solid #333 !important;
  }
  /* Repeats the header row on every printed page for a table that
     spans more than one - without this, only the FIRST page shows
     column labels at all. */
  .table thead {
    display: table-header-group;
  }
  .table tbody {
    display: table-row-group;
  }
  /* Discourages (doesn't force - the browser can still override if
     honoring it would create a worse layout) a single row splitting
     across a page break. Both the older and newer property together,
     since browsers are inconsistent about honoring just one. */
  .table tbody tr {
    page-break-inside: avoid !important;
    break-inside: avoid !important;
  }
  /* Slightly smaller text/padding for print specifically fits more of
     a wide table onto a physical page without needing horizontal
     scrolling, which printing can't do at all. */
  .table th, .table td {
    white-space: normal !important;
    word-wrap: break-word !important;
    overflow-wrap: break-word !important;
    font-size: 0.75rem !important;
    padding: 0.3rem 0.4rem !important;
  }
}
