:root{
  --bg: #ffffff;
  --bg-subtle: #fafafa;
  --border: #eaeaea;
  --border-strong: #e0e0e0;
  --fg: #171717;
  --fg-muted: #666666;
  --fg-subtle: #999999;
  --black: #000000;
  --green: #0a7d3c;
  --green-bg: #e9f9ee;
  --red: #c8290b;
  --red-bg: #fdeeed;
  --blue: #0070f3;
  --blue-bg: #eaf2ff;
  /* Shared column widths for the Check Schedule list — keeping these fixed
     and reused across the header, each row, and the total row is what keeps
     the "Total" divider a single straight line down the whole card. */
  --sched-count-w: 60px;
  --sched-actions-w: 40px;
  --amber: #b5730a;
  --amber-bg: #fdf3e2;
  --purple: #6b3fc9;
  --purple-bg: #f0eafd;
  --radius: 8px;
  --shadow-sm: 0 1px 2px rgba(0,0,0,.04);
  --shadow-md: 0 4px 14px rgba(0,0,0,.06);
  --sidebar-w: 240px;
}

*{box-sizing:border-box;}
html,body{margin:0;padding:0; overflow-x:hidden; width:100%;}

/* ---------- Thin scrollbars, app-wide ----------
   The default OS scrollbar (thick, opaque) is visually loud against this
   app's minimal look. Firefox gets it via scrollbar-width/-color; Chrome/
   Edge/Safari via the ::-webkit-scrollbar pseudo-elements. Applies to the
   main page scroll and every internal scrollable panel (tables, modals
   that don't already opt out, etc) unless overridden — the sidebar gets
   its own lighter-on-dark variant right after .sidebar below, since a
   dark thumb would vanish against its near-black background. */
html{ scrollbar-width: thin; scrollbar-color: rgba(0,0,0,.22) transparent; }
::-webkit-scrollbar{ width:6px; height:6px; }
::-webkit-scrollbar-track{ background:transparent; }
::-webkit-scrollbar-thumb{ background:rgba(0,0,0,.18); border-radius:10px; }
::-webkit-scrollbar-thumb:hover{ background:rgba(0,0,0,.32); }

body{
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg-subtle);
  color: var(--fg);
  font-size: 14px;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
a{color:inherit;text-decoration:none;}
ul{list-style:none;margin:0;padding:0;}
h1,h2,h3,h4{margin:0;font-weight:600;letter-spacing:-.01em;}
img{max-width:100%;}
button{font-family:inherit;}

/* ---------- Layout ---------- */
.app{ display:flex; min-height:100vh; min-height:100dvh; }

/* ---------- Sidebar ---------- */
.sidebar{
  width: var(--sidebar-w);
  background: linear-gradient(180deg, #141414 0%, #000000 55%);
  color: #fff;
  padding: 18px 12px;
  position: fixed;
  top:0; left:0; bottom:0;
  display:flex;
  flex-direction:column;
  z-index: 110;
  transition: transform .25s ease;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  box-shadow: 6px 0 28px rgba(0,0,0,.28);
  /* Thin scrollbar override: the global rule above uses a dark thumb,
     which would be invisible against this near-black background — use a
     light, translucent thumb here instead, same slim width. */
  scrollbar-width: thin; scrollbar-color: rgba(255,255,255,.22) transparent;
}
.sidebar::-webkit-scrollbar{ width:5px; }
.sidebar::-webkit-scrollbar-track{ background:transparent; }
.sidebar::-webkit-scrollbar-thumb{ background:rgba(255,255,255,.18); border-radius:10px; }
.sidebar::-webkit-scrollbar-thumb:hover{ background:rgba(255,255,255,.32); }
.sidebar .brand{
  display:flex; align-items:center; gap:10px;
  padding: 10px 8px 18px; font-weight:700; font-size:15px;
  letter-spacing:-.01em;
  margin-bottom: 10px;
  border-bottom: 1px solid rgba(255,255,255,.08);
}
.sidebar .brand .dot{
  width:26px;height:26px;border-radius:7px; background:#fff;
  display:flex;align-items:center;justify-content:center;
  color:#000;font-size:13px;font-weight:800; flex-shrink:0;
  box-shadow: 0 0 0 1px rgba(255,255,255,.12), 0 3px 8px rgba(0,0,0,.4);
}
.sidebar .brand .brand-logo-img{
  width:26px;height:26px;border-radius:7px; object-fit:contain;
  background:#fff; flex-shrink:0;
  box-shadow: 0 0 0 1px rgba(255,255,255,.12), 0 3px 8px rgba(0,0,0,.4);
}
.sidebar .brand .sidebar-close{
  margin-left:auto; display:none; background:transparent; border:none;
  color:#a1a1a1; font-size:20px; line-height:1; cursor:pointer; padding:4px 6px;
}

/* Nav links: icon sits in its own soft rounded tile (translucent on rest/
   hover, solid accent on active) rather than a bare glyph, and the active
   row gets a left accent bar + a subtle lift shadow instead of a flat
   color swap — small touches that read as "designed" rather than default
   sidebar-template styling. */
.sidebar nav a{
  position:relative;
  display:flex; align-items:center; gap:11px;
  padding:9px 10px; border-radius:9px; color:#9c9c9c;
  font-size:13.5px; font-weight:500; letter-spacing:-.005em;
  margin-bottom:2px;
  transition: background-color .18s cubic-bezier(.4,0,.2,1), color .18s cubic-bezier(.4,0,.2,1), transform .18s cubic-bezier(.4,0,.2,1);
}
.sidebar nav a::before{
  content:''; position:absolute; left:-12px; top:50%; transform:translateY(-50%);
  width:3px; height:0; border-radius:0 3px 3px 0; background:#fff;
  transition: height .18s cubic-bezier(.4,0,.2,1);
}
.sidebar nav a:hover{ color:#fff; background:rgba(255,255,255,.06); transform:translateX(1px); }
.sidebar nav a.active{
  color:#0a0a0a; background:#fff; font-weight:600;
  box-shadow: 0 4px 14px rgba(0,0,0,.35);
}
.sidebar nav a.active::before{ height:18px; }
.sidebar nav .icon{
  display:flex; align-items:center; justify-content:center;
  width:28px; height:28px; border-radius:7px; flex-shrink:0;
  background: rgba(255,255,255,.06);
  transition: background-color .18s cubic-bezier(.4,0,.2,1), color .18s cubic-bezier(.4,0,.2,1);
}
.sidebar nav a:hover .icon{ background:rgba(255,255,255,.1); }
.sidebar nav a.active .icon{ background:var(--blue-bg); color:var(--blue); }
.sidebar .group-label{
  color:#5c5c5c; font-size:10.5px; text-transform:uppercase; letter-spacing:.08em;
  padding: 16px 10px 7px; font-weight:700;
}
/* Only the "Menu" label sits directly under .sidebar — "Admin" is nested
   inside <nav> alongside its own .nav-divider — so a plain child combinator
   is enough to single it out for the reduced top padding, no :first-of-type
   trickery needed (which wouldn't match here anyway, since .brand is also
   a div and would win that race). */
.sidebar > .group-label{ padding-top:4px; }
.sidebar .nav-divider{ height:1px; background:rgba(255,255,255,.08); margin:10px 4px 0; }
/* Guarantees breathing room above the footer's own border-top divider
   even when the menu list is tall enough to nearly fill the sidebar —
   .foot's margin-top:auto pushes it down but can shrink toward 0px on
   its own, which is what made the last nav item ("Form Kegiatan") look
   stuck directly against the footer's separator line. */
.sidebar nav{ margin-bottom:10px; }
.sidebar .foot{
  margin-top:auto; padding:14px 10px 4px; color:#555; font-size:11px; line-height:1.6;
  border-top: 1px solid rgba(255,255,255,.08);
}
.sidebar .foot b{ color:#888; font-weight:600; }

/* ---------- Bottom nav (mobile only) ----------
   Floating pill bar with margin on all sides (not docked to the edges),
   pill-highlighted active item, and a raised circular "+" that pokes out
   above the bar via negative margin. Hidden by default; only shown under
   the same 900px breakpoint the sidebar itself collapses at. */
.bottom-nav{
  display:none;
  position:fixed; left:12px; right:12px; bottom:max(12px, env(safe-area-inset-bottom));
  z-index:60;
  background:var(--bg);
  border:1px solid var(--border);
  border-radius:22px;
  box-shadow: 0 10px 28px rgba(0,0,0,.14);
  padding:6px 6px;
  align-items:center;
  justify-content:space-around;
  gap:2px;
}
.bottom-nav .bn-item{
  flex:1 1 0; display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:2px; padding:7px 2px 6px; border-radius:15px; min-width:0;
  color:var(--fg-muted); text-decoration:none; text-align:center;
  transition: color .15s ease, background-color .15s ease;
}
.bottom-nav .bn-item .bn-icon{
  width:22px; height:22px; display:flex; align-items:center; justify-content:center;
}
.bottom-nav .bn-item .bn-label{
  font-size:10px; font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:100%;
}
.bottom-nav .bn-item.active{ color:var(--blue); background:#eaf2ff; }
/* Wrapper only exists to lift the FAB out of the bar via negative margin
   without disturbing the flex row's own height/alignment. */
.bottom-nav .bn-fab-wrap{ position:relative; flex:0 0 auto; margin-top:-30px; }
.bottom-nav .bn-fab{
  width:54px; height:54px; border-radius:50%;
  background:var(--black); color:#fff; border:4px solid var(--bg);
  display:flex; align-items:center; justify-content:center;
  box-shadow: 0 8px 18px rgba(0,0,0,.28);
  transition: transform .15s ease;
}
.bottom-nav .bn-fab:active{ transform:scale(.94); }

@media (max-width:900px){
  .bottom-nav{ display:flex; }
}

.sidebar-overlay{
  display:none; position:fixed; inset:0; background:rgba(0,0,0,.45);
  z-index:105; opacity:0; transition:opacity .2s ease;
}
.sidebar-overlay.show{ display:block; opacity:1; }

.menu-toggle{
  display:none; align-items:center; justify-content:center;
  width:36px; height:36px; border:1px solid var(--border-strong); border-radius:6px;
  background:#fff; cursor:pointer; flex-shrink:0; margin-right:12px; padding:0;
}
.menu-toggle span, .menu-toggle span::before, .menu-toggle span::after{
  content:''; display:block; width:18px; height:2px; background:var(--fg);
  position:relative; transition:.15s;
}
.menu-toggle span::before{ position:absolute; top:-6px; }
.menu-toggle span::after{ position:absolute; top:6px; }

/* ---------- Main ---------- */
.main{ margin-left: var(--sidebar-w); flex:1; min-width:0; width:100%; }
.topbar{
  display:flex; align-items:center; justify-content:space-between; flex-wrap:nowrap; gap:12px;
  padding: 16px 28px; background: var(--bg); border-bottom: 1px solid var(--border);
  position:sticky; top:0; z-index:20;
}
.topbar-left{ display:flex; align-items:center; min-width:0; flex:1 1 auto; overflow:hidden; }
.topbar-left .title-wrap{ min-width:0; overflow:hidden; }
.topbar h1{ font-size:16px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.topbar .sub{ color:var(--fg-muted); font-size:12.5px; margin-top:2px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.content{ padding: 24px 28px 60px; max-width:1200px; }

/* ---------- Card ---------- */
.card{ background: var(--bg); border:1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-sm); max-width:100%; }
.card-pad{ padding:20px; }
.card-head{
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  padding:16px 20px; border-bottom:1px solid var(--border); flex-wrap:wrap;
}
.card-head h3{ font-size:13.5px; }
.card-head .muted{ color:var(--fg-subtle); font-size:12px; }
.card-head-title-group{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; min-width:0; }

/* ---------- Stat grid ---------- */
.stat-grid{ display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:16px; margin-bottom:20px; width:100%; }
.stat-card{ background:var(--bg); border:1px solid var(--border); border-radius:var(--radius); padding:18px 20px; box-shadow: var(--shadow-sm); min-width:0; max-width:100%; overflow:hidden; }
.stat-card .label{ color:var(--fg-muted); font-size:12.5px; font-weight:500; display:flex; align-items:center; gap:6px; margin-bottom:10px; min-width:0; }
.stat-card .value{ font-size: clamp(17px, 4.8vw, 24px); font-weight:700; letter-spacing:-.02em; overflow-wrap:anywhere; word-break:break-word; }
.stat-card .delta{ font-size:12px; margin-top:6px; font-weight:500; }
.stat-card .icon-box{ width:34px;height:34px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:16px; }

/* ---------- Grid 2 col ---------- */
.grid-2{ display:grid; grid-template-columns: minmax(0,1.6fr) minmax(0,1fr); gap:16px; align-items:start; }

/* ---------- Table ---------- */
.table-responsive{ width:100%; overflow-x:auto; -webkit-overflow-scrolling:touch; }
table{ width:100%; border-collapse:collapse; }
th{
  text-align:left; font-size:11.5px; text-transform:uppercase; letter-spacing:.04em;
  color:var(--fg-subtle); font-weight:600; padding:10px 20px; border-bottom:1px solid var(--border);
  background:var(--bg-subtle); white-space:nowrap;
}
td{ padding:13px 20px; border-bottom:1px solid var(--border); font-size:13.5px; vertical-align:middle; }
tr:last-child td{ border-bottom:none; }
tbody tr:hover{ background:var(--bg-subtle); }
.text-right{ text-align:right; }
.text-muted{ color:var(--fg-muted); }
.mono{ font-variant-numeric: tabular-nums; }

/* ---------- Pill / Tag / Badge ---------- */
.pill{ display:inline-flex; align-items:center; gap:5px; padding:3px 9px; border-radius:20px; font-size:11.5px; font-weight:600; white-space:nowrap; }
.pill-green{ background:var(--green-bg); color:var(--green); }
.pill-red{ background:var(--red-bg); color:var(--red); }
.pill-blue{ background:var(--blue-bg); color:var(--blue); }
.pill-amber{ background:var(--amber-bg); color:var(--amber); }
.pill-purple{ background:var(--purple-bg); color:var(--purple); }
.pill-neutral{ background:#f1f1f1; color:var(--fg-muted); }

/* ---------- Buttons ---------- */
.btn{
  display:inline-flex; align-items:center; gap:6px; padding:8px 14px; border-radius:6px;
  font-size:13px; font-weight:500; border:1px solid var(--border-strong); background:#fff;
  color:var(--fg); cursor:pointer; transition:.15s; white-space:nowrap;
}
.btn:hover{ border-color:#c9c9c9; background:#f7f7f7; }
.btn-primary{ background:var(--black); color:#fff; border-color:var(--black); }
.btn-primary:hover{ background:#2a2a2a; border-color:#2a2a2a; }
.btn-green{ background:var(--green); color:#fff; border-color:var(--green); }
.btn-green:hover{ opacity:.9; }
.btn-red{ background:var(--red); color:#fff; border-color:var(--red); }
.btn-red:hover{ opacity:.9; }
.btn-sm{ padding:5px 10px; font-size:12px; }
.btn-ghost{ background:transparent; border-color:transparent; }
.btn-ghost:hover{ background:var(--bg-subtle); }
.btn-block{ width:100%; justify-content:center; }
.btn[disabled]{ opacity:.5; cursor:not-allowed; }

.row-actions{ display:flex; align-items:center; justify-content:flex-end; gap:6px; flex-wrap:nowrap; white-space:nowrap; }

/* ---------- Forms ----------
   Vertical rhythm is intentionally driven from ONE place per unit — either
   a standalone .form-group or a .form-row/.form-row-3 pair — using
   margin-TOP so it never depends on collapsing between grid items (which
   never collapse in CSS) vs normal block siblings (which do). Every row
   gets the exact same 20px gap above it regardless of whether the row
   before it has help-text, is a single field, or a 2-3 column row — and
   regardless of whether it's reused on Input Booking, Edit Booking, the
   Users form, login, or the schedule filters. */
.form-group{ margin-top:20px; margin-bottom:0; }
.form-row, .form-row-3{ margin-top:20px; margin-bottom:0; }
.form-row{ display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:14px; }
.form-row-3{ display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr) minmax(0,1fr); gap:14px; }
.form-row .form-group, .form-row-3 .form-group{ margin-top:0; }

/* No extra top gap when a row is the very first thing in its form, or
   when it directly follows a section title (the title's own bottom
   margin already provides the separation). */
.form-group:first-child, .form-row:first-child, .form-row-3:first-child,
.form-section-title + .form-group, .form-section-title + .form-row, .form-section-title + .form-row-3{ margin-top:0; }

label{ display:block; font-size:12.5px; font-weight:600; margin-bottom:6px; color:var(--fg); }
label .req{ color:var(--red); }
input[type=text], input[type=date], input[type=time], input[type=month], input[type=number],
input[type=password], input[type=email], input[type=tel], input[type=url], input[type=search],
select, textarea{
  width:100%; padding:9px 12px; border:1px solid var(--border-strong); border-radius:6px;
  font-size:13.5px; font-family:inherit; background:#fff; color:var(--fg); transition:.15s; max-width:100%;
}
input:focus, select:focus, textarea:focus{ outline:none; border-color:var(--black); box-shadow:0 0 0 3px rgba(0,0,0,.06); }
input.is-invalid, select.is-invalid, textarea.is-invalid{ border-color:var(--red); }
textarea{ resize:vertical; min-height:90px; }

/* Read-only twin of the form controls above, used by the Booking Detail
   modal so it renders pixel-identical to Input/Edit Booking — same box,
   border, padding and type color, just not editable. Browsers grey out
   [readonly]/:disabled by default; we cancel that here on purpose. */
input[readonly], textarea[readonly]{ background:#fff; color:var(--fg); cursor:default; }
input[readonly]:focus, textarea[readonly]:focus{ border-color:var(--border-strong); box-shadow:none; }
textarea[readonly]{ resize:none; }
select:disabled{ background:#fff; color:var(--fg); opacity:1; -webkit-text-fill-color:var(--fg); cursor:default; }
input[readonly]::-webkit-calendar-picker-indicator{ opacity:.35; pointer-events:none; }
input[type=number][readonly]::-webkit-inner-spin-button,
input[type=number][readonly]::-webkit-outer-spin-button{ -webkit-appearance:none; margin:0; }

/* File inputs (Logo/Favicon in Settings, Attachment in the Booking form,
   dynamic "Upload File" fields): a proper bordered upload field instead
   of a bare "Browse... / No file selected" text line — the field itself
   reads as a dropzone-style card, and the button is a solid dark pill
   matching .btn-primary elsewhere, so it feels like one deliberate
   control rather than an unstyled native input. */
input[type=file]{
  display:flex; align-items:center; width:100%; min-height:20px;
  font-size:12.5px; font-family:inherit; color:var(--fg-subtle);
  background:var(--bg-subtle); border:1px dashed var(--border-strong); border-radius:9px;
  padding:11px 14px; cursor:pointer; transition:border-color .15s ease, background-color .15s ease;
}
input[type=file]:hover{ border-color:var(--fg-muted); background:#fff; }
input[type=file]:focus-visible{ outline:none; border-color:var(--black); border-style:solid; box-shadow:0 0 0 3px rgba(0,0,0,.08); }
input[type=file]::file-selector-button{
  font-family:inherit; font-size:12.5px; font-weight:600; color:#fff; background:var(--black);
  border:1px solid var(--black); border-radius:7px; padding:8px 16px; margin-right:14px; cursor:pointer;
  transition:background-color .15s ease, transform .1s ease;
}
input[type=file]::file-selector-button:hover{ background:#2a2a2a; }
input[type=file]::file-selector-button:active{ transform:scale(.97); }

.help-text{ font-size:11.5px; color:var(--fg-subtle); margin-top:6px; margin-bottom:0; line-height:1.5; }
.field-error{ font-size:11.5px; color:var(--red); margin-top:6px; margin-bottom:0; font-weight:500; }
.form-actions{ display:flex; gap:10px; margin-top:24px; flex-wrap:wrap; }
.form-section-title{ font-size:12px; font-weight:700; text-transform:uppercase; letter-spacing:.04em; color:var(--fg-subtle); margin:15px 0 14px; }

/* Anything that follows a field row (e.g. the informational conflict
   warning banner between Status and Attachment) keeps the same 20px
   rhythm instead of falling back to the component's own default margin. */
.form-group + .alert, .form-row + .alert, .form-row-3 + .alert{ margin-top:20px; }

/* Checkbox row (override conflict, etc) */
.check-row{ display:flex; align-items:flex-start; gap:8px; padding:10px 12px; background:var(--amber-bg); border:1px solid #f0dcae; border-radius:6px; }
.check-row input[type=checkbox]{ width:16px; height:16px; margin-top:2px; flex-shrink:0; }
.check-row label{ margin:0; font-weight:500; font-size:12.5px; color:var(--fg); }

/* ---------- Alerts ---------- */
.alert{ padding:12px 16px; border-radius:6px; font-size:13px; margin-bottom:18px; border:1px solid; display:flex; align-items:flex-start; gap:8px; }
.alert-success{ background:var(--green-bg); color:var(--green); border-color:#bfe8cc; }
.alert-error{ background:var(--red-bg); color:var(--red); border-color:#f6c6bd; }
.alert-warning{ background:var(--amber-bg); color:var(--amber); border-color:#f0dcae; }
.alert-info{ background:var(--blue-bg); color:var(--blue); border-color:#c7dffb; }
.alert ul{ margin:4px 0 0; padding-left:16px; list-style:disc; }

/* ---------- Filter bar ---------- */
.filter-bar{ display:flex; align-items:center; gap:10px; margin-bottom:16px; flex-wrap:wrap; }
/* Fields default to flex-shrink:1 as flex children, but their default
   min-width:auto floors that shrink at each one's own content-based
   width (an option's text, a date placeholder) — same class of bug as
   the sidebar/tab overflow fixed earlier. With 5-6 fields plus the
   button group all hitting that floor at once, the row's total content
   width exceeds a normal desktop window well before any single field
   looks "full", so the button group (last in source order) is what gets
   pushed to a second line. flex-grow:1 + min-width:90px lets each field
   grow to fill spare room and genuinely shrink below its own content
   width when space is tight, so everything reliably shares one row; the
   existing inline max-width on each field still caps how wide it grows. */
.filter-bar select, .filter-bar input{ width:auto; flex:1 1 110px; min-width:90px; }
.filter-bar .btn-filter{ padding:9px 16px; font-size:13.5px; line-height:1.2; }
/* Filter + Reset always travel together, so they're wrapped in their own
   flex group — this guarantees they land side by side as a pair (not
   Reset alone on the next line) no matter how many filter fields come
   before them, and how those fields happen to wrap. flex:0 0 auto keeps
   the pair at its natural size (never stretched, never shrunk) and
   margin-left:auto pins it to the row's right edge once the fields
   above have taken their share — the same "hug the far end" pattern a
   toolbar's primary actions usually get. */
.filter-bar .filter-actions{ display:flex; gap:8px; flex:0 0 auto; margin-left:auto; }
.tabs{ display:flex; gap:4px; background:#f1f1f1; padding:4px; border-radius:8px; }
.tabs a, .tabs button{ padding:7px 14px; border-radius:6px; font-size:12.5px; font-weight:600; color:var(--fg-muted); white-space:nowrap; border:none; background:transparent; cursor:pointer; font-family:inherit; }
.tabs a.active, .tabs button.active{ background:#fff; color:var(--fg); box-shadow:var(--shadow-sm); }

/* Single/Bulk schedule-search switch: same segmented-tab look as .tabs,
   but split 50/50 and full-width since it's a two-way mode toggle rather
   than a row of independently-sized nav links. min-width:0 overrides the
   flex-item default of auto, which otherwise refuses to shrink below the
   nowrap label's full width; white-space:normal (overriding .tabs'
   nowrap) lets "Date Range (Bulk)" wrap to a second line instead of
   overflowing whenever the available width is tight — narrow phones as
   much as the desktop sidebar below — rather than depending on it just
   barely fitting on one line at any particular width. Selector is
   ".tabs .sched-mode-btn", not just ".sched-mode-btn", because ".tabs
   button"'s white-space:nowrap above is one type-selector heavier and
   would otherwise win over a plain class selector and silently keep the
   overflow regardless of what's set here. */
.tabs .sched-mode-btn{ flex:1 1 0; min-width:0; text-align:center; white-space:normal; line-height:1.25; }
@media (max-width:520px){
  .tabs .sched-mode-btn{ font-size:11.5px; padding:7px 6px; }
}

/* Desktop-only: filter card becomes a narrow left sidebar so the results
   list isn't stretched edge-to-edge on wide screens. Below the same
   900px breakpoint the sidebar nav itself collapses at, this drops back
   to the original single-column stack — that's the existing mobile
   layout and is left untouched. */
.sched-layout{ display:grid; grid-template-columns: minmax(0,1fr); gap:16px; align-items:start; }
.sched-filter-col .card{ margin-bottom:0; }
@media (min-width: 901px){
  .sched-layout{ grid-template-columns: minmax(260px,300px) minmax(0,1fr); gap:20px; }
  .sched-filter-col{ position:sticky; top:80px; }
  /* Same width problem as the tabs above: at 260-300px, "Date Range
     (Bulk)" doesn't fit on one nowrap line even at the mobile font size,
     so here it's allowed to wrap to two lines instead of overflowing. */
  .sched-filter-col .tabs .sched-mode-btn{ font-size:11px; padding:7px 4px; white-space:normal; line-height:1.3; }
  /* Date From/To side-by-side needs ~500px+ to stay legible; in this
     narrow column force them back to the same stacked single-column
     layout the mobile breakpoint already uses at a similarly tight width. */
  .sched-filter-col .form-row{ grid-template-columns:minmax(0,1fr); }
  /* The filter card is narrow here, so the 3-across Search/Today/Tomorrow
     row needs the same compact button styling the mobile breakpoint
     already uses at a similarly tight width — otherwise the labels wrap. */
  .sched-filter-col .btn-row-3{ gap:6px; }
  .sched-filter-col .btn-row-3 .btn{ padding:9px 4px; font-size:11.5px; flex-direction:row; gap:4px; }
  /* Search Range / Reset (.btn-row-2) hit the same nowrap-overflow problem
     at this width as the tabs and Search/Today/Tomorrow row did — shrink
     them the same way. */
  .sched-filter-col .btn-row-2{ gap:6px; }
  .sched-filter-col .btn-row-2 .btn{ padding:8px 4px; font-size:11.5px; gap:4px; }
  /* Grid/flex items default to min-width:auto, which floors their size at
     the nowrap content's width — every ".btn" in the sidebar needs this
     overridden or a long enough label overflows its column regardless of
     how much padding/font-size is trimmed above. */
  .sched-filter-col .btn{ min-width:0; }
}

/* ---------- Empty state ---------- */
.empty-state{ padding:50px 20px; text-align:center; color:var(--fg-subtle); }
.empty-state .icon{ font-size:32px; margin-bottom:10px; }

/* ---------- Login page ---------- */
.login-page{ min-height:100vh; min-height:100dvh; display:flex; align-items:center; justify-content:center; background: var(--bg-subtle); padding:20px; }
.login-card{ width:100%; max-width:380px; background:var(--bg); border:1px solid var(--border); border-radius:var(--radius); box-shadow: var(--shadow-md); padding:32px 28px; }
.login-brand{ display:flex; align-items:center; gap:10px; font-weight:700; font-size:16px; margin-bottom:6px; }
.login-brand .dot{ width:26px;height:26px;border-radius:7px; background:var(--black); color:#fff; display:flex;align-items:center;justify-content:center; font-size:14px;font-weight:800; flex-shrink:0; }
.login-sub{ color:var(--fg-muted); font-size:12.5px; margin:0 0 20px; }
.login-footer{ margin-top:22px; padding-top:16px; border-top:1px solid var(--border); text-align:center; color:var(--fg-subtle); font-size:11.5px; }
.login-demo{ margin-top:16px; padding:12px 14px; background:var(--bg-subtle); border:1px solid var(--border); border-radius:6px; font-size:11.5px; color:var(--fg-muted); line-height:1.6; }
.login-demo b{ color:var(--fg); }
.form-check-label{ display:flex; align-items:center; gap:8px; font-size:13.5px; font-weight:500; cursor:pointer; }
.form-check-label input[type="checkbox"]{ width:16px; height:16px; margin:0; cursor:pointer; }
.login-links{ text-align:right; margin:8px 0 20px; font-size:12.5px; }
.login-links a{ color:var(--fg-muted); text-decoration:none; }
.login-links a:hover{ color:var(--fg); text-decoration:underline; }
.login-links-center{ text-align:center; margin:16px 0 0; color:var(--fg-muted); }

/* ---------- Topbar user menu ---------- */
.user-menu{ position:relative; flex-shrink:0; }
.user-trigger{ display:flex; align-items:center; gap:8px; padding:5px 8px 5px 5px; border-radius:24px; border:1px solid transparent; background:transparent; cursor:pointer; transition:.15s; }
.user-trigger:hover{ background:var(--bg-subtle); border-color:var(--border); }
.user-menu.open .user-trigger{ background:var(--bg-subtle); border-color:var(--border); }
.avatar-circle{ width:32px; height:32px; border-radius:50%; background:var(--black); color:#fff; display:flex; align-items:center; justify-content:center; font-size:13px; font-weight:700; flex-shrink:0; }
.avatar-circle-lg{ width:40px; height:40px; font-size:15px; }
.user-trigger-info{ display:flex; flex-direction:column; align-items:flex-start; gap:2px; min-width:0; }
.user-trigger-name{ font-size:12.5px; font-weight:600; color:var(--fg); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:140px; }
.user-caret{ font-size:10px; color:var(--fg-subtle); transition:transform .15s; flex-shrink:0; }
.user-menu.open .user-caret{ transform:rotate(180deg); }
.user-dropdown{ position:absolute; top:calc(100% + 8px); right:0; min-width:220px; background:#fff; border:1px solid var(--border); border-radius:10px; box-shadow:var(--shadow-md); padding:14px; opacity:0; visibility:hidden; transform:translateY(-6px); transition:.15s ease; z-index:200; }
.user-menu.open .user-dropdown{ opacity:1; visibility:visible; transform:translateY(0); }
.user-dropdown-head{ display:flex; align-items:center; gap:10px; }
.user-dropdown-meta{ min-width:0; }
.user-dropdown-name{ font-size:13.5px; font-weight:700; margin-bottom:4px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.user-dropdown-divider{ height:1px; background:var(--border); margin:12px 0; }
.logout-form{ margin:0; }
.user-dropdown-logout{ display:flex; align-items:center; gap:8px; padding:9px 10px; border-radius:6px; font-size:13px; font-weight:600; color:var(--red); background:var(--red-bg); width:100%; border:none; cursor:pointer; font-family:inherit; text-align:left; }
.user-dropdown-logout:hover{ opacity:.85; }
.user-dropdown-link{ display:flex; align-items:center; gap:8px; padding:9px 10px; border-radius:6px; font-size:13px; font-weight:600; color:var(--fg); }
.user-dropdown-link:hover{ background:var(--hover-bg, #f1f1f1); }

.role-badge{ display:inline-flex; align-items:center; padding:3px 9px; border-radius:20px; font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.02em; white-space:nowrap; }
.role-badge.role-admin{ background:#e9f9ee; color:var(--green); }
.role-badge.role-staff{ background:#eaf2ff; color:var(--blue); }

/* ---------- Generic inline dropdown (e.g. toolbar "Export" menu) ---------- */
.menu-dropdown{ position:relative; display:inline-flex; flex-shrink:0; }
.menu-dropdown-toggle{ display:inline-flex; align-items:center; gap:6px; }
.menu-dropdown-caret{ font-size:9px; line-height:1; margin-left:1px; transition:transform .15s ease; }
.menu-dropdown.open .menu-dropdown-caret{ transform:rotate(180deg); }
.menu-dropdown-panel{ position:absolute; top:calc(100% + 8px); right:0; min-width:200px; background:#fff; border:1px solid var(--border); border-radius:10px; box-shadow:var(--shadow-md); padding:6px; opacity:0; visibility:hidden; transform:translateY(-6px); transition:.15s ease; z-index:200; }
.menu-dropdown.open .menu-dropdown-panel{ opacity:1; visibility:visible; transform:translateY(0); }
.menu-dropdown-item{ display:flex; align-items:center; gap:10px; padding:9px 10px; border-radius:7px; font-size:12.5px; font-weight:600; color:var(--fg); white-space:nowrap; }
.menu-dropdown-item:hover{ background:var(--bg-subtle); }
.menu-dropdown-item .ico-circle{ width:26px; height:26px; flex-shrink:0; }
.menu-dropdown-item-sub{ display:block; font-size:10.5px; font-weight:500; color:var(--fg-subtle); margin-top:1px; }
.menu-dropdown-caption{ padding:8px 10px 4px; font-size:10.5px; font-weight:700; text-transform:uppercase; letter-spacing:.03em; color:var(--fg-subtle); }
@media (max-width:640px){
  .menu-dropdown-panel{ right:0; left:auto; min-width:220px; }
  /* Inside a full-width row (.row-actions-full, e.g. Bookings' Export
     button), the toggle itself spans ~half the screen from the left
     edge, so anchoring the panel to its right edge pushes most of the
     panel off the left side of the viewport. Anchor to the toggle's
     left edge instead, where there's clear room to the right. */
  .row-actions-full .menu-dropdown-panel{ left:0; right:auto; }
}

/* ---------- Modal ---------- */
.modal-overlay{ display:none; position:fixed; inset:0; background:rgba(0,0,0,.5); z-index:300; align-items:center; justify-content:center; padding:20px; }
.modal-overlay.show{ display:flex; }
.modal-box{ background:#fff; border-radius:12px; width:100%; max-width:480px; box-shadow:var(--shadow-md); max-height:90vh; display:flex; flex-direction:column; overflow:hidden; }
.modal-head{ display:flex; align-items:center; justify-content:space-between; padding:16px 20px; border-bottom:1px solid var(--border); flex-shrink:0; }
.modal-head h3{ font-size:15px; }
.modal-close{ background:none; border:none; font-size:18px; cursor:pointer; color:var(--fg-subtle); padding:2px 6px; }
.modal-body{ padding:16px 20px 20px; overflow-y:auto; flex:1 1 auto; min-height:0; scrollbar-width:none; -ms-overflow-style:none; }
.modal-body::-webkit-scrollbar{ display:none; width:0; height:0; }
.modal-foot{ padding:16px 20px; border-top:1px solid var(--border); display:flex; gap:10px; justify-content:flex-end; flex-shrink:0; }
.modal-loading{ padding:40px 0; text-align:center; color:var(--fg-subtle); font-size:13px; }

/* ---------- Toasts ---------- */
.toast-host{ position:fixed; right:16px; bottom:16px; z-index:500; display:flex; flex-direction:column; gap:8px; align-items:flex-end; }
.toast{ background:#1f2430; color:#fff; padding:10px 16px; border-radius:8px; font-size:13px; box-shadow:var(--shadow-md); opacity:0; transform:translateY(8px); transition:opacity .25s, transform .25s; max-width:320px; }
.toast.show{ opacity:1; transform:translateY(0); }
.toast-error{ background:#b3261e; }
.toast-success{ background:#1e7e4a; }
@media (max-width:900px){
  /* Clear the bottom nav (~64px tall + safe-area) so toasts don't land
     underneath it. */
  .toast-host{ bottom: calc(64px + env(safe-area-inset-bottom, 0px) + 12px); right:12px; }
}

@media (max-width: 680px){
  .modal-overlay{ padding:16px 14px; align-items:flex-end; }
  .modal-box{ max-width:100%!important; width:100%; max-height:88vh; border-radius:14px; }
  .modal-head{ padding:14px 18px; }
  .modal-body{ padding:14px 18px 18px; }
  .modal-foot{ padding:14px 18px; }
  /* Modal action rows (Submit/Reset/Cancel, Confirm/Cancel, etc.) go
     full-width and inline on mobile instead of left-aligned, natural-width
     buttons: flex:1 1 0 on every .btn splits the row evenly across
     however many buttons are present (1, 2 or 3) with no extra markup
     needed per page. Padding/font drop slightly so 3-across rows (e.g.
     Submit / Reset / Cancel) still read comfortably on a narrow screen —
     same treatment already used for .btn-row-3 elsewhere in the app. */
  .form-actions,
  .modal-foot{
    flex-wrap:nowrap; gap:8px;
  }
  .form-actions .btn,
  .modal-foot .btn{
    flex:1 1 0; width:auto; min-width:0; padding:10px 6px; font-size:12.5px; justify-content:center; text-align:center;
  }
  /* .btn-ghost is deliberately borderless for quiet, secondary actions
     (e.g. the "Clear" filter link) — but inside an action row, sitting
     next to bordered buttons, a borderless Cancel/Back/Close reads as
     unfinished rather than "quiet". Restoring its border here only
     within these two action-row containers keeps the rest of the app's
     ghost buttons untouched. */
  .form-actions .btn-ghost,
  .modal-foot .btn-ghost{
    border-color:var(--border-strong); background:#fff;
  }
  .form-actions .btn-ghost:hover,
  .modal-foot .btn-ghost:hover{
    background:#f7f7f7;
  }
}
.detail-row{ display:flex; justify-content:space-between; gap:12px; padding:9px 0; border-bottom:1px solid var(--border); font-size:13px; }
.detail-row:last-child{ border-bottom:none; }
/* Same rhythm rule as .form-group/.form-row above: no extra top gap when
   a detail row is the first thing in its container, or when it directly
   follows a section title (the title's own bottom margin already provides
   the separation). Keeps "Booking Detail" flush with the same gap under
   its "Booking Details" title as the Input/Edit Booking forms use. */
.detail-row:first-child, .form-section-title + .detail-row{ padding-top:0; }
.detail-row .k{ color:var(--fg-muted); flex-shrink:0; }
.detail-row .v{ font-weight:400; text-align:right; }
.detail-row .v.strong{ font-weight:600; }
.detail-row .v.note{ font-weight:400; font-style:italic; }

/* ---------- Attachment list (Booking Detail) ----------
   Each file gets a small colored icon tile + name/size stack + a
   dedicated round download action, in a bordered row that lifts
   gently on hover — reads as a real file manager, not a bare link
   list. Kept in the app's existing token system (--border, --blue,
   --shadow-sm) rather than introducing new colors. */
.attachment-list{ display:flex; flex-direction:column; gap:8px; }
.attachment-item{
  display:flex; align-items:center; gap:12px;
  padding:10px 10px 10px 12px;
  border:1px solid var(--border);
  border-radius:10px;
  background:var(--bg);
  transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}
.attachment-item:hover{
  border-color:var(--border-strong);
  box-shadow:var(--shadow-sm);
  transform:translateY(-1px);
}
.attachment-icon{
  width:36px; height:36px; border-radius:9px; flex-shrink:0;
  display:flex; align-items:center; justify-content:center;
  background:var(--blue-bg); color:var(--blue);
}
.attachment-main{ min-width:0; flex:1; display:flex; flex-direction:column; gap:2px; }
.attachment-name{
  font-size:13px; font-weight:600; color:var(--fg);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.attachment-meta{ font-size:11.5px; color:var(--fg-subtle); font-variant-numeric:tabular-nums; }
.attachment-download{
  flex-shrink:0; display:flex; align-items:center; justify-content:center;
  width:32px; height:32px; border-radius:8px;
  border:1px solid var(--border); background:var(--bg-subtle); color:var(--fg-muted);
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
.attachment-item:hover .attachment-download{ background:var(--blue-bg); border-color:var(--blue-bg); color:var(--blue); }

/* ---------- Calendar (schedule) ---------- */
.cal-grid{ display:grid; grid-template-columns:repeat(7,1fr); gap:6px; }
.cal-dow{ text-align:center; font-size:11px; font-weight:700; color:var(--fg-subtle); text-transform:uppercase; padding-bottom:6px; }
.cal-dow.is-sunday{ color:var(--red); }
.cal-cell{ min-height:84px; border:1px solid var(--border); border-radius:6px; padding:6px; background:#fff; display:flex; flex-direction:column; gap:3px; }
.cal-cell.other-month{ background:var(--bg-subtle); opacity:.5; }
.cal-cell.today{ border-color:var(--black); border-width:2px; }
.cal-cell.is-holiday, .cal-cell.is-sunday{ background:var(--red-bg); border-color:#f3cfc8; }
.cal-cell.is-holiday.today, .cal-cell.is-sunday.today{ border-color:var(--red); }
.cal-cell.is-holiday .cal-daynum, .cal-cell.is-sunday .cal-daynum{ color:var(--red); }
.cal-cell.is-cuti-bersama{ background:var(--amber-bg); border-color:#f0dcae; }
.cal-cell.is-cuti-bersama .cal-daynum{ color:var(--fg); }
.cal-daynum{ font-size:11.5px; font-weight:700; color:var(--fg-muted); }
.cal-cell.today .cal-daynum{ color:var(--fg); }
.cal-holiday-label{ font-size:9.5px; font-weight:600; color:var(--red); line-height:1.3; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.cal-holiday-label.is-cuti-bersama{ color:#8a6417; }
.cal-event{ font-size:10px; padding:2px 5px; border-radius:4px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; cursor:pointer; font-weight:600; }
.cal-more{ font-size:10px; color:var(--fg-subtle); font-weight:600; padding-left:2px; }
.cal-legend{ display:flex; gap:18px; flex-wrap:wrap; margin-top:14px; font-size:11.5px; color:var(--fg-muted); }
.cal-legend-item{ display:flex; align-items:center; gap:6px; }
.cal-legend-dot{ width:9px; height:9px; border-radius:50%; display:inline-block; flex-shrink:0; }
.cal-legend-dot.is-holiday{ background:var(--red); }
.cal-legend-dot.is-cuti-bersama{ background:#c8960b; }

/* ---------- Timeline / recent list ---------- */
.tl-item{ display:flex; gap:10px; padding:10px 0; border-bottom:1px solid var(--border); font-size:12.5px; }
.tl-item:last-child{ border-bottom:none; }
.tl-dot{ width:8px; height:8px; border-radius:50%; background:var(--blue); flex-shrink:0; margin-top:5px; }
.tl-text{ min-width:0; }
.tl-time{ color:var(--fg-subtle); font-size:11px; margin-top:2px; }

/* ---------- Full Recent Activity feed (/activity) ---------- */
/* Day-by-day section header ("Today", "Yesterday", "02 Sep 2026") that
   breaks the feed into readable chunks instead of one long list. */
.act-group-label{
  font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.06em;
  color:var(--fg-subtle); padding:16px 0 8px;
}
.act-group-label:first-child{ padding-top:2px; }
/* One log row: a coloured category icon avatar (instead of the plain
   dot used by the dashboard's mini widget) + actor/description/time,
   with the category pill and IP address as secondary metadata — the
   richer per-row detail that turns a bare log into a proper audit feed. */
.act-item{ display:flex; gap:12px; padding:12px 0; border-bottom:1px solid var(--border); }
.act-item:last-child{ border-bottom:none; }
.act-icon{
  width:32px; height:32px; border-radius:50%; flex-shrink:0;
  display:flex; align-items:center; justify-content:center;
}
.act-body{ min-width:0; flex:1; }
.act-top{ display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.act-actor{ font-size:13px; font-weight:600; color:var(--fg); }
.act-desc{ font-size:12.5px; color:var(--fg-muted); margin-top:2px; }
.act-meta{ display:flex; align-items:center; gap:8px; margin-top:5px; flex-wrap:wrap; }
.act-time{ color:var(--fg-subtle); font-size:11px; }
.act-ip{ color:var(--fg-subtle); font-size:11px; font-family:ui-monospace, SFMono-Regular, Menlo, monospace; }
.act-meta-dot{ width:2px; height:2px; border-radius:50%; background:var(--fg-subtle); flex-shrink:0; }

/* .act-icon.ico-circle needs to win over the plain .ico-circle sizing
   declared later in this file (same specificity would otherwise let
   source order decide) — the compound selector below intentionally
   sizes the activity feed's avatar a touch smaller than the 34px
   default used for menu/action-sheet icons. */
.act-icon.ico-circle{ width:32px; height:32px; }
.ico-circle.ico-amber{ background:var(--amber-bg); color:var(--amber); }
.ico-circle.ico-purple{ background:var(--purple-bg); color:var(--purple); }
.ico-circle.ico-neutral{ background:#f1f1f1; color:var(--fg-muted); }
.ico-circle.ico-green{ background:var(--green-bg); color:var(--green); }
.ico-circle.ico-blue{ background:var(--blue-bg); color:var(--blue); }
.ico-circle.ico-red{ background:var(--red-bg); color:var(--red); }

@media (max-width: 900px){
  .act-item{ gap:10px; }
  .act-icon.ico-circle{ width:28px; height:28px; }
}

/* ---------- Progress toggle switch ---------- */
.switch{ position:relative; display:inline-block; width:38px; height:21px; flex-shrink:0; }
.switch input{ opacity:0; width:0; height:0; }
.switch .slider{ position:absolute; cursor:pointer; inset:0; background:#ccc; transition:.2s; border-radius:34px; }
.switch .slider::before{ position:absolute; content:""; height:15px; width:15px; left:3px; bottom:3px; background:white; transition:.2s; border-radius:50%; }
.switch input:checked + .slider{ background:var(--green); }
.switch input:checked + .slider::before{ transform:translateX(17px); }
.input-inline-action{ display:flex; gap:8px; }
.input-inline-action input{ flex:1; }
.input-inline-action .btn{ flex-shrink:0; white-space:nowrap; }

/* ---------- Schedule: date/activity search + grouped-by-time listing ---------- */
.date-field{ display:flex; align-items:stretch; border:1px solid var(--border-strong); border-radius:6px; overflow:hidden; }
.date-field .icon-box{ background:#171717; color:#fff; width:44px; display:flex; align-items:center; justify-content:center; flex-shrink:0; }
.date-field input[type=date]{ border:none; border-radius:0; flex:1; }
.date-field input[type=date]:focus{ box-shadow:none; }

.btn-outline-green{ border-color:var(--green); color:var(--green); background:#fff; }
.btn-outline-green:hover{ background:var(--green-bg); }
.btn-outline-blue{ border-color:var(--blue); color:var(--blue); background:#fff; }
.btn-outline-blue:hover{ background:var(--blue-bg); }
.btn-outline-dark{ border-color:#bbb; color:var(--fg); background:#fff; }
.btn-outline-dark:hover{ background:var(--bg-subtle); }

.btn-row-3{ display:grid; grid-template-columns:repeat(3,1fr); gap:8px; margin-top:14px; }
.btn-row-3 .btn{ justify-content:center; }
.btn-row-2{ display:grid; grid-template-columns:repeat(2,1fr); gap:8px; }
.btn-row-2 .btn{ justify-content:center; }

.btn-outline-red{ border-color:var(--red); color:var(--red); background:#fff; }
.btn-outline-red:hover{ background:var(--red-bg); }

/* Pending-approval callout: reason field + Reject/Approve as an even,
   precisely aligned 2-up grid so both buttons match width on any screen,
   mobile included, with no separate media query needed. */
.approval-box{ margin:0 0 16px; padding:14px 16px; border:1px solid #f0dcae; background:var(--amber-bg); border-radius:8px; }
.approval-box-head{ display:flex; align-items:center; gap:10px; margin-bottom:12px; }
.approval-box-icon{ width:32px; height:32px; flex-shrink:0; }
.approval-box-title{ font-size:13px; font-weight:700; color:var(--fg); }
.approval-box-sub{ font-size:11.5px; color:var(--fg-subtle); margin-top:1px; }
.approval-box input[type=text]{ width:100%; }
.approval-box .btn-row-2 .btn{ padding:9px 10px; font-weight:600; }

.sched-card-title{ text-align:center; padding:16px 20px; border-bottom:1px solid var(--border); }
.sched-card-title .activity-title{ font-size:14.5px; font-weight:800; text-transform:uppercase; letter-spacing:.03em; margin-bottom:2px; }
.sched-card-title .day-badge{ font-weight:800; font-size:14px; letter-spacing:.02em; }

.time-group-header{ background:var(--bg-subtle); padding:9px 20px; font-weight:700; font-size:12.5px; display:flex; align-items:center; gap:10px; border-top:1px solid var(--border); border-bottom:1px solid var(--border); color:var(--fg); }
.time-group-header:first-of-type{ border-top:none; }
.time-group-header > span:first-child{ flex:1; min-width:0; }

/* Date-level header used only by Check Schedule's bulk/rentang search — one
   level up from the #time headers nested under it, so a multi-day result
   reads as clear day sections rather than one long flat time-slot list.
   Reuses the app's own black (same as .sidebar/.btn-primary), not a new
   color, to keep it inside the existing theme. */
.time-group-header.sched-date-header{ background:var(--black); color:#fff; border-color:var(--black); text-transform:uppercase; letter-spacing:.03em; }
.time-group-header.sched-date-header .col-divider{ border-left-color:rgba(255,255,255,.25); color:#fff; }

.sched-item{ display:flex; align-items:center; gap:10px; padding:12px 20px; border-bottom:1px solid var(--border); }
.sched-item:last-child{ border-bottom:none; }
.sched-item .item-main{ min-width:0; flex:1; }
.sched-item .num-label{ font-size:13.5px; font-weight:600; line-height:1.6; }
.sched-item .pic-name{ font-size:10.5px; font-weight:400; font-style:italic; color:var(--fg-muted); }
.sched-item .item-badge{ display:inline-flex; vertical-align:middle; margin-left:4px; padding:2px 8px; font-size:9.5px; font-weight:700; line-height:1.4; }
.sched-item .ket{ font-size:11.5px; color:var(--amber); font-style:italic; margin-top:4px; line-height:1.4; }
.sched-item .guest-count{ font-weight:700; font-size:14px; flex:0 0 var(--sched-count-w); width:var(--sched-count-w); align-self:stretch; display:flex; align-items:center; justify-content:center; }
.sched-item .actions{ display:flex; align-items:center; gap:5px; flex:0 0 var(--sched-actions-w); width:var(--sched-actions-w); justify-content:flex-end; }
.icon-btn{ width:30px; height:30px; display:inline-flex; align-items:center; justify-content:center; border-radius:6px; border:1px solid var(--border-strong); background:#fff; color:var(--fg-muted); cursor:pointer; font-size:13px; padding:0; flex-shrink:0; }
.icon-btn:hover{ background:var(--bg-subtle); }
.icon-btn.icon-btn-danger{ color:var(--red); }
.icon-btn.icon-btn-download{ color:var(--blue); border-color:var(--blue); }

/* Row "⋮" trigger — deliberately bare: no border, no filled box. Just the
   three dots, with a soft circular hover/focus state for feedback. */
.action-trigger{
  width:30px; height:30px; flex-shrink:0; padding:0;
  display:inline-flex; align-items:center; justify-content:center;
  border:none; background:transparent; border-radius:50%;
  color:var(--fg-muted); cursor:pointer;
  font-size:18px; font-weight:800; letter-spacing:1px; line-height:1;
  transition:background-color .15s ease, color .15s ease;
}
.action-trigger:hover,
.action-trigger:focus-visible{ background:var(--bg-subtle); color:var(--fg); }
.action-trigger:active{ background:var(--border); }
.action-trigger:focus-visible{ outline:2px solid var(--blue); outline-offset:2px; }

/* ---------- Action sheet (premium) ----------
   A single "⋮" button per row opens this small modal (reuses
   .modal-overlay/.modal-box, scoped here via .action-sheet-modal /
   .action-sheet-box) instead of showing every action button inline. */
.action-sheet-modal{ background:rgba(15,15,20,.55); backdrop-filter:blur(2px); }
.action-sheet-box{
  border-radius:16px;
  box-shadow:0 10px 40px rgba(0,0,0,.18), 0 2px 8px rgba(0,0,0,.08);
  border:1px solid rgba(0,0,0,.04);
  animation:actionSheetIn .18s cubic-bezier(.2,.9,.3,1.2);
}
@keyframes actionSheetIn{
  from{ opacity:0; transform:translateY(6px) scale(.97); }
  to{ opacity:1; transform:translateY(0) scale(1); }
}
.action-sheet-box .modal-head{ padding:16px 18px 12px; border-bottom:none; }
.action-sheet-box .modal-head h3{ font-size:14.5px; font-weight:800; letter-spacing:.01em; }
.action-sheet-box .modal-body{ padding:6px 10px 12px !important; }

.action-sheet-item{
  display:flex; align-items:center; gap:12px; padding:11px 10px;
  border-radius:11px; font-size:14px; font-weight:600; color:var(--fg);
  text-decoration:none; cursor:pointer;
  transition:background-color .15s ease, transform .15s ease;
}
.action-sheet-item:hover{ background:var(--bg-subtle); transform:translateX(2px); }
.action-sheet-item:active{ transform:translateX(2px) scale(.99); }
.action-sheet-item + .action-sheet-item{ margin-top:3px; }

.ico-circle{
  width:34px; height:34px; flex-shrink:0; border-radius:50%;
  display:inline-flex; align-items:center; justify-content:center;
  font-size:14.5px; line-height:1;
}
.ico-circle.ico-edit{ background:var(--blue-bg); color:var(--blue); }
.ico-circle.ico-view{ background:var(--blue-bg); color:var(--blue); }
.ico-circle.ico-download{ background:var(--green-bg); color:var(--green); }
.ico-circle.ico-danger{ background:var(--red-bg); color:var(--red); }

.action-sheet-text{ display:flex; flex-direction:column; gap:1px; min-width:0; flex:1; }
.action-sheet-label{ font-size:13.5px; font-weight:700; color:var(--fg); }
.action-sheet-sub{ font-size:11px; font-weight:500; color:var(--fg-subtle); }
.action-sheet-item-danger .action-sheet-label{ color:var(--red); }

.action-sheet-chevron{ font-size:16px; color:var(--fg-subtle); flex-shrink:0; opacity:0; transform:translateX(-3px); transition:opacity .15s ease, transform .15s ease; }
.action-sheet-item:hover .action-sheet-chevron{ opacity:1; transform:translateX(0); }

.action-sheet-empty{ padding:16px 14px; color:var(--fg-subtle); font-size:13.5px; text-align:center; }

.sched-total-row{ display:flex; align-items:center; gap:10px; padding:14px 20px; font-weight:800; background:var(--bg-subtle); border-top:2px solid var(--border-strong); font-size:13.5px; }
.sched-total-row > span:first-child{ flex:1; min-width:0; }
.sched-total-row > span:last-child{ flex:0 0 auto; white-space:nowrap; }

/* Vertical divider marking the "Total" column — a fixed width shared by the
   time-slot header and each booking row keeps the line perfectly straight
   top to bottom, reading as two clear blocks: booking info on the left,
   quantity on the right. .col-spacer reserves the same width as the actions
   column (only present on booking rows) so the header's divider lines up
   with the one on each row, not with the icons after it. The total row
   intentionally skips this divider — it's a plain summary line, not part of
   the two-column list. */
.col-divider{ border-left:1px solid var(--border-strong); padding-left:14px; flex:0 0 var(--sched-count-w); width:var(--sched-count-w); text-align:center; white-space:nowrap; }
.col-spacer{ flex:0 0 var(--sched-actions-w); width:var(--sched-actions-w); }

.sched-empty{ padding:52px 20px 48px; text-align:center; }
.sched-empty svg{ width:130px; height:auto; margin-bottom:16px; }
.sched-empty-title{ font-size:14.5px; font-weight:700; color:var(--fg); margin-bottom:4px; }
.sched-empty-sub{ font-size:12.5px; color:var(--fg-subtle); }

@media (max-width: 480px){
  .btn-row-3{ gap:6px; }
  .btn-row-3 .btn{ padding:9px 4px; font-size:11.5px; flex-direction:row; gap:4px; }
  .sched-item{ padding:10px 14px; gap:6px; }
  .time-group-header{ padding:8px 14px; gap:6px; }
  .col-divider{ padding-left:10px; }
}

/* =========================================================
   RESPONSIVE BREAKPOINTS
   ========================================================= */
@media (max-width: 1024px){
  .content{ padding: 20px 20px 50px; }
  .topbar{ padding: 14px 20px; }
  .stat-grid{ grid-template-columns:repeat(2,minmax(0,1fr)); }
}

@media (max-width: 900px){
  .sidebar{ transform: translateX(-100%); box-shadow: var(--shadow-md); width: min(var(--sidebar-w), 82vw); }
  .sidebar.open{ transform: translateX(0); }
  .sidebar .brand .sidebar-close{ display:block; }
  .main{ margin-left:0; }
  .menu-toggle{ display:inline-flex; }
  .grid-2{ grid-template-columns:minmax(0,1fr); }
}

@media (max-width: 680px){
  .content{ padding: 16px 14px 44px; }
  .topbar{ padding: 12px 14px; }
  .topbar h1{ font-size:15px; }
  .card-pad{ padding:10px; }
  .card-head{ padding:14px 16px; }
  th, td{ padding:10px 14px; }
  .form-row, .form-row-3{ grid-template-columns:minmax(0,1fr); }
  .cal-grid{ grid-template-columns:repeat(7,minmax(0,1fr)); gap:3px; }
  .cal-cell{ min-height:56px; padding:4px; }
  .cal-event{ font-size:9px; }
}

/* Filter bar on mobile: a proper 2-column grid so "All activities" /
   "All statuses" sit side by side and each fully fills its half, same
   for the two date fields. Filter/Reset are handled separately below —
   see .filter-actions — since with an odd number of fields ahead of them
   (e.g. an extra PIC select on the Reports page), plain grid
   auto-placement would land Reset alone on its own row instead of next
   to Filter. */
@media (max-width: 680px){
  .filter-bar{
    display:grid; grid-template-columns:1fr 1fr; gap:8px; align-items:stretch;
  }
  .filter-bar input[type=text]{ grid-column:1 / -1; width:100% !important; max-width:none !important; }
  .filter-bar select,
  .filter-bar input[type=date]{ width:100% !important; max-width:none !important; }
  /* .filter-pic (Reports' PIC select) and .filter-solo (any other lone
     select in a filter-bar, e.g. Activity's category select) are the
     odd field out — no paired field to sit next to, so left as a plain
     grid item it ends up alone in a column with an empty gap beside it.
     Same span-both-columns trick as .filter-actions below fixes both. */
  .filter-bar .filter-pic,
  .filter-bar .filter-solo{ grid-column:1 / -1; }
  /* Forcing the wrapper to span both columns pushes it onto a fresh row
     of its own regardless of what parity of fields came before it. Flex
     (rather than a nested grid) is used for the two buttons themselves:
     flex:1 1 0 forces both to the same basis and lets them grow/shrink
     equally, so Filter and Reset always split the row exactly 50/50,
     fill all the way to both edges, and stay side by side on one line. */
  /* margin-left:auto from the desktop rule (.filter-bar .filter-actions,
     line ~380) is NOT overridden by display/gap/grid-column alone — a
     property the later rule doesn't mention stays in effect. Left as
     "auto" here, it shrinks this box to fit-content and shoves it to the
     right of its full-width grid cell, which is exactly the "small
     buttons with empty space on the left" bug. Resetting it to 0 is
     required for the flex children below to actually stretch full width. */
  .filter-bar .filter-actions{
    grid-column:1 / -1 !important; display:flex !important; gap:8px; margin-left:0 !important;
  }
  .filter-bar .filter-actions .btn{
    flex:1 1 0 !important; width:auto !important; min-width:0; text-align:center; justify-content:center;
  }
  /* Reset is intentionally .btn-sm (smaller/quieter) next to Filter on
     desktop, but once they're stretched to match widths in this stacked
     pair, the size mismatch reads as inconsistent — bring it up to
     Filter's dimensions here. */
  .filter-bar .filter-actions .btn-sm{ padding:9px 16px; font-size:13.5px; }
}

@media (max-width: 480px){
  :root{ --radius: 7px; }
  body{ font-size:13.5px; }
  .content{ padding: 14px 10px 40px; }
  .topbar{ padding: 10px 12px; gap:8px; }
  .topbar .sub{ display:none; }
  .stat-grid{ grid-template-columns:repeat(2,minmax(0,1fr)); gap:10px; }
  .stat-card{ padding:14px 16px; }
  .stat-card .value{ font-size:20px; }
  th, td{ padding:9px 12px; font-size:12.5px; }
  .btn{ padding:7px 11px; font-size:12.5px; }
  .row-actions{ gap:5px; }
  .row-actions .btn-sm{ padding:6px 9px; font-size:12px; }
  /* Header action rows that opt in via .row-actions-full (e.g. Bookings'
     Export + New Booking) go full-width and split evenly on mobile,
     same edge-to-edge precision as .form-actions/.btn-row-2 elsewhere,
     instead of hugging their natural width on the left. */
  .row-actions-full{ width:100%; }
  .row-actions-full > .menu-dropdown,
  .row-actions-full > .btn,
  .row-actions-full > a.btn{ flex:1 1 0; min-width:0; }
  .row-actions-full .menu-dropdown-toggle{ width:100%; justify-content:center; }
  .row-actions-full > .btn,
  .row-actions-full > a.btn{ justify-content:center; text-align:center; }
  .login-card{ padding:24px 18px; }
  .card-head{ flex-direction:column; align-items:flex-start; gap:6px; }
  /* Headers that only pair a title with a plain "View all →" / "← Back"
     link (no buttons) should never drop to a second line on mobile — the
     title truncates instead so the link stays inline on the right. */
  .card-head.card-head-inline{ flex-direction:row; align-items:center; flex-wrap:nowrap; gap:8px; }
  .card-head.card-head-inline h3{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .card-head.card-head-inline .muted{ flex-shrink:0; white-space:nowrap; }
  .card-head.card-head-inline .btn{ flex-shrink:0; }
  .user-trigger-info{ display:none; }
  .user-caret{ display:none; }
  .user-trigger{ padding:4px; border-radius:50%; }
}

/* .content's bottom padding gets overwritten by each of the max-width
   1024/680/480 blocks above via the shorthand `padding` property (last
   one wins, and 480px is the narrowest/last-defined, i.e. what most
   phones actually match) — so the bottom-nav clearance has to be
   reasserted here, after all of them, rather than back where .bottom-nav
   itself is defined. */
@media (max-width:900px){
  .content{ padding-bottom: calc(104px + env(safe-area-inset-bottom, 0px)); }
}

/* ---------- Dashboard: Recent Bookings compact list on mobile ----------
   Full table stays for desktop/tablet; below 680px it's swapped for the
   same compact "⋮ opens an action sheet" pattern used on Check Schedule,
   showing only institution, activity, and guest count. */
.recent-mobile-list{ display:none; }
@media (max-width: 680px){
  .recent-table-view{ display:none; }
  .recent-mobile-list{ display:block; }
  .recent-mobile-item{ padding:13px 16px; }
  .recent-mobile-item .num-label{ font-size:13px; }
}
/* Only the booking date itself ("11 Sep 2026") must always stay on one
   line. The line below it (time, or "Check-out: 14 Sep 2026") is free to
   wrap according to the Date column's width — it doesn't need to match. */
.recent-date-value{ white-space:nowrap; }

.recent-guest-count{ flex-direction:column; gap:0; line-height:1.1; }
.recent-guest-num{ font-weight:800; font-size:14px; }
.recent-guest-unit{ font-size:9px; font-weight:700; color:var(--fg-subtle); text-transform:uppercase; letter-spacing:.04em; margin-top:1px; }

/* ---------- Booking Management: mobile compact list ----------
   Same "date / company / guests + ⋮" pattern as the dashboard's Recent
   Bookings list. Full table stays for desktop/tablet. */
.bookings-mobile-list{ display:none; }
@media (max-width: 680px){
  .bookings-table-view{ display:none; }
  .bookings-mobile-list{ display:block; border-top:1px solid var(--border); }
  .bookings-mobile-item{ padding:13px 16px; }
  .bookings-mobile-item .num-label{ font-size:13px; }
  .bmi-date{ font-size:11px; font-weight:600; color:var(--fg-subtle); margin-bottom:3px; }
}

/* ---------- Reports: mobile compact list ----------
   Identical "date / company / guests + ⋮" pattern as Booking Management's
   mobile list, so both screens look and behave the same on mobile. The
   "⋮" here only offers View (Reports has no edit/delete). Full table
   stays for desktop/tablet. */
.reports-mobile-list{ display:none; }
@media (max-width: 680px){
  .reports-table-view{ display:none; }
  .reports-mobile-list{ display:block; border-top:1px solid var(--border); }
  .reports-mobile-item{ padding:13px 16px; }
  .reports-mobile-item .num-label{ font-size:13px; }
}

/* ---------- Users: mobile compact list ----------
   Same pattern again, adapted for the Users table: name, role/status,
   plus a "⋮" action sheet mirroring Booking Management's for Edit /
   Deactivate-Activate / Delete. Full table stays for desktop/tablet. */
.users-mobile-list{ display:none; }
@media (max-width: 680px){
  .users-table-view{ display:none; }
  .users-mobile-list{ display:block; border-top:1px solid var(--border); }
  .users-mobile-item{ padding:13px 16px; }
  .users-mobile-item .num-label{ font-size:13px; }
}
.umi-meta{ display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin-top:4px; font-size:11.5px; }

/* ---------- Form Kegiatan (Settings > Fields): mobile compact lists ----------
   Same "⋮ opens an action sheet" pattern as Booking Management / Users:
   the Jenis Kegiatan and Kolom Custom tables each get a hidden-on-desktop
   card list below 680px so rows never force horizontal scrolling. Each
   row is a real 3-column CSS grid (Nama | Slot resp. Label | Tipe&Status |
   "⋮") — NOT flex-wrap — so a long badge/label can never push the middle
   column onto its own line underneath; every column keeps its own fixed
   track no matter how long its neighbour's content is. Full tables stay
   for desktop/tablet. */
.fields-mobile-list{ display:none; }
@media (max-width: 680px){
  .fields-table-view{ display:none; }
  .fields-mobile-list{ display:block; border-top:1px solid var(--border); }
  .fields-mobile-item{
    display:grid; grid-template-columns: minmax(0,1fr) minmax(0,108px) 28px;
    align-items:center; column-gap:10px;
    padding:10px 0px; border-bottom:1px solid var(--border);
  }
  .fields-mobile-item:last-child{ border-bottom:none; }
  .fields-mobile-item .fmi-name{ min-width:0; overflow:hidden; }
  .fields-mobile-item .fmi-name .pill{ max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .fields-mobile-item .fmi-name .num-label{ display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .fields-mobile-item .fmi-slot{
    min-width:0; padding-left:10px; border-left:1px solid var(--border-strong);
    font-size:11.5px; font-weight:400; color:var(--fg-subtle); line-height:1.3;
    display:flex; flex-direction:column; align-items:flex-start; gap:3px;
  }
  .fields-mobile-item .fmi-actions{ display:flex; justify-content:flex-end; }
}


/* ---------- Dashboard: "Bookings by Activity Type" (premium) ---------- */
.kat-list{ display:flex; flex-direction:column; gap:6px; }
.kat-row{ display:flex; align-items:center; gap:12px; padding:9px 4px; border-radius:10px; transition:background-color .15s ease; }
.kat-row:hover{ background:var(--bg-subtle); }
.kat-icon{ width:34px; height:34px; border-radius:10px; display:flex; align-items:center; justify-content:center; font-size:15px; flex-shrink:0; }
.kat-main{ flex:1; min-width:0; }
.kat-row-top{ display:flex; align-items:baseline; justify-content:space-between; gap:8px; margin-bottom:6px; }
.kat-label{ font-size:13px; font-weight:700; color:var(--fg); }
.kat-count{ font-size:12.5px; font-weight:800; color:var(--fg); font-variant-numeric:tabular-nums; }
.kat-count-unit{ font-size:10.5px; font-weight:600; color:var(--fg-subtle); margin-left:1px; }
.kat-bar-bg{ height:7px; border-radius:20px; background:var(--bg-subtle); overflow:hidden; box-shadow:inset 0 1px 1px rgba(0,0,0,.03); }
.kat-bar-fill{ height:100%; border-radius:20px; transition:width .4s cubic-bezier(.2,.8,.3,1); position:relative; }
.kat-bar-fill::after{ content:""; position:absolute; inset:0; border-radius:20px; background:linear-gradient(180deg, rgba(255,255,255,.35), rgba(255,255,255,0) 60%); }
.kat-share{ font-size:11px; font-weight:700; color:var(--fg-subtle); flex-shrink:0; min-width:30px; text-align:right; font-variant-numeric:tabular-nums; }

/* ---------- Simple dependency-free line chart (Reports: guest trend) ---------- */
.trend-chart{ width:100%; height:220px; display:block; }
.trend-grid{ stroke:var(--border); stroke-width:1; }
.trend-axis-label{ font-size:9.5px; fill:var(--fg-subtle); }
.trend-dot{ fill:var(--blue); stroke:#fff; stroke-width:1.4; }
.trend-dot-peak{ fill:var(--amber); stroke:#fff; stroke-width:1.6; }
@media (max-width:900px){
  .trend-chart{ height:180px; }
}
/* ---------- Settings (System Settings): fullwidth layout, tabs on top ----------
   Desktop: the section-picker is a horizontal segmented tab bar sitting
   above the form panel — not a vertical sidebar-menu list. Each tab keeps
   its own accent color (via inline --accent/--accent-bg) as a small
   colored icon chip, but the pill itself stays neutral so four
   differently-colored tabs sitting side by side read as one calm,
   professional control instead of a row of candy-colored buttons. See
   the small inline script in settings/index.php for the tab logic.
   Below 680px (the app's standard mobile breakpoint) this entire block
   is superseded by the mobile pager rules further down — untouched. */
.settings-shell{ display:flex; flex-direction:column; gap:18px; width:100%; }

.settings-panels{ width:100%; order:2; }
.settings-panel{ display:none; }
.settings-panel.active{ display:block; }

.settings-nav{
  order:1; position:static;
  display:flex; flex-direction:row; align-items:stretch; gap:3px;
  background:var(--bg-subtle); border:1px solid var(--border); border-radius:14px;
  padding:5px; box-shadow:var(--shadow-sm);
  overflow-x:auto; scrollbar-width:none;
}
.settings-nav::-webkit-scrollbar{ display:none; }
.settings-nav-label{ display:none; }
.settings-nav-item{
  position:relative; flex:0 0 auto; display:flex; align-items:center; gap:9px;
  padding:9px 16px 9px 10px; border-radius:10px; border:1px solid transparent; background:transparent;
  font-family:inherit; cursor:pointer; white-space:nowrap;
  transition:background-color .14s ease, box-shadow .14s ease;
}
.settings-nav-item:hover{ background:rgba(255,255,255,.6); }
.settings-nav-item.active{ background:var(--bg); border-color:var(--border); box-shadow:var(--shadow-sm); }
.settings-nav-item.active .settings-nav-title{ color:var(--fg); }

.settings-nav-icon{
  display:flex; align-items:center; justify-content:center; flex-shrink:0;
  width:26px; height:26px; border-radius:7px;
  background:var(--accent-bg); color:var(--accent);
}
.settings-nav-text{ display:flex; flex-direction:column; gap:1px; min-width:0; }
.settings-nav-title{ font-size:12.5px; font-weight:700; color:var(--fg-muted); line-height:1.3; }
.settings-nav-sub{ display:none; }
.settings-nav-chevron{ display:none; }

.branding-preview{ display:flex; align-items:center; gap:10px; margin-bottom:8px; }
.branding-preview img{ width:44px; height:44px; object-fit:contain; border:1px solid var(--border-strong); border-radius:8px; background:#fff; padding:4px; }
.branding-remove{ font-size:12px; color:var(--fg-muted); display:flex; align-items:center; gap:5px; font-weight:400; cursor:pointer; }

/* Mobile tab pager — replaces the desktop sidebar with a "< current
   tab >" stepper plus a swipeable slide track for the panels below
   680px. #settingsNav (the desktop tab bar) is simply hidden here; its
   buttons stay in the DOM as the single source of truth for each
   tab's icon/title/accent color, which settings/index.php's script
   copies into the pager on every activate().

   NOTE: `flex:0 0 auto` on #settingsPanels is a defensive reset, not
   decorative — #settingsPanels takes over `order` here, and pinning its
   flex-basis to `auto` keeps it from ever inheriting a stray basis value
   from another rule as the app's CSS evolves. */
.settings-pager{ display:none; }

@media (max-width: 680px){
  .settings-shell{ flex-direction:column; gap:14px; }

  #settingsNav.settings-nav{ display:none; }

  .settings-pager{
    display:flex; flex-direction:column; gap:10px; order:1; width:100%;
  }
  .settings-pager-bar{
    display:flex; align-items:center; justify-content:space-between; gap:10px;
    background:var(--bg); border:1px solid var(--border); border-radius:14px;
    padding:8px; box-shadow:var(--shadow-sm);
  }
  .settings-pager-btn{
    display:flex; align-items:center; justify-content:center; flex-shrink:0;
    width:36px; height:36px; border-radius:50%; padding:0;
    border:1px solid var(--border-strong); background:#fff; color:var(--fg-muted);
    cursor:pointer; transition:transform .12s ease, background-color .12s ease;
  }
  .settings-pager-btn:active{ transform:scale(.92); background:var(--bg-subtle); }
  .settings-pager-btn:disabled{ opacity:.3; cursor:default; }
  .settings-pager-btn:disabled:active{ transform:none; background:#fff; }

  .settings-pager-current{
    flex:1 1 auto; min-width:0;
    display:flex; align-items:center; justify-content:center; gap:8px;
  }
  .settings-pager-icon{
    display:flex; align-items:center; justify-content:center; flex-shrink:0;
    width:26px; height:26px; border-radius:8px;
    background:var(--accent-bg); color:var(--accent);
  }
  .settings-pager-title{
    font-size:13.5px; font-weight:700; color:var(--fg);
    white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  }

  .settings-pager-dots{ display:flex; align-items:center; justify-content:center; gap:6px; }
  .settings-pager-dot{
    width:6px; height:6px; padding:0; border:none; border-radius:50%;
    background:var(--border-strong); cursor:pointer; transition:.2s ease;
  }
  .settings-pager-dot.active{ width:16px; border-radius:4px; background:var(--accent); }

  /* `height` here is set inline by the script (measured off the active
     panel's own card) and animated on tab change — without it, this
     container's auto height would equal its flex row's tallest child
     (Identity, since ResizeObserver aside all 4 panels sit in one row),
     leaving a tall empty gap under any shorter tab like Bank Account before
     the Save/Cancel buttons that follow this element in the DOM. */
  #settingsPanels.settings-panels{
    flex:0 0 auto; order:2; width:100%;
    overflow:hidden; border-radius:var(--radius);
    touch-action:pan-y; /* let vertical page scroll through; JS owns horizontal drags */
    transition:height .32s cubic-bezier(.22,.68,.35,1);
  }
  #settingsTrack.settings-track{
    display:flex; flex-wrap:nowrap; align-items:flex-start; width:400%;
    transition:transform .32s cubic-bezier(.22,.68,.35,1);
  }
  #settingsPanels .settings-panel{
    display:block; flex:0 0 25%; width:25%; max-width:25%; box-sizing:border-box;
  }
}
/* ---------- Discussion / Forum: reply thread ----------
   Each reply is an avatar + body row, reusing the same .avatar-circle
   used in the topbar user menu. Kept intentionally simple (no bubbles/
   borders-per-item) so it reads as a continuation of .card-pad rather
   than a separate widget. */
.forum-reply{ display:flex; gap:12px; padding:14px 0; border-bottom:1px solid var(--border); }
.forum-reply:last-child{ border-bottom:none; padding-bottom:0; }
.forum-reply:first-child{ padding-top:0; }
.forum-reply-body{ flex:1 1 auto; min-width:0; }
.forum-reply-meta{ display:flex; align-items:baseline; gap:8px; font-size:13px; margin-bottom:4px; }
.forum-reply-text{ font-size:13.5px; line-height:1.6; word-break:break-word; }

/* ---------- Discussion / Forum v2: attachments, mentions, threading ---------- */

/* Plain inline text-button — used for "Reply" / a reply's own "Delete"
   action, where a full bordered .btn would be visually heavier than the
   rest of that row calls for. */
.btn-link{
  background:none; border:none; padding:0; margin:0;
  font-size:12.5px; font-weight:600; color:var(--fg-muted);
  cursor:pointer; font-family:inherit;
}
.btn-link:hover{ color:var(--fg); text-decoration:underline; }

/* @mention link inside a rendered post body. */
.mention{ color:var(--blue); font-weight:600; background:var(--blue-bg); padding:0 3px; border-radius:4px; }
.mention:hover{ text-decoration:underline; }

/* File/image attachments under a topic or reply body. */
.forum-attachments{ display:flex; flex-wrap:wrap; gap:8px; margin-top:10px; }
.attachment-thumb{
  display:block; width:96px; height:96px; border-radius:var(--radius);
  overflow:hidden; border:1px solid var(--border); flex-shrink:0;
}
.attachment-thumb img{ width:100%; height:100%; object-fit:cover; display:block; }
.attachment-chip{
  display:inline-flex; align-items:center; gap:6px;
  padding:6px 10px; border:1px solid var(--border); border-radius:999px;
  font-size:12.5px; background:var(--bg-subtle); max-width:100%;
}
.attachment-chip:hover{ border-color:var(--border-strong); background:#f2f2f2; }

/* Existing-attachment checklist shown on the Edit Topic form. */
.existing-attachments{ display:flex; flex-direction:column; gap:6px; margin-top:6px; }
.existing-attachment-row{
  display:flex; align-items:center; gap:8px; font-size:13px;
  padding:6px 8px; border:1px solid var(--border); border-radius:6px; cursor:pointer;
}
.existing-attachment-row input[type="checkbox"]{ width:auto; flex-shrink:0; }
.existing-attachment-row:has(input:checked){ background:var(--red-bg); border-color:var(--red); }

/* Threaded replies: each nesting level is indented (see the inline
   margin-left set per-node in discussion/_reply.php) and gets a faint
   left rule so the thread's shape stays readable at a glance. */
.forum-reply-nested{ border-left:2px solid var(--border); padding-left:12px; }
.reply-quote-ref{
  display:inline-block; font-size:12px; color:var(--fg-subtle);
  margin:2px 0 6px; text-decoration:none;
}
.reply-quote-ref:hover{ color:var(--blue); text-decoration:underline; }

/* Inline "reply to this reply" box, toggled by [data-reply-toggle] in app.js. */
.inline-reply-box{ margin-top:10px; padding-top:10px; border-top:1px dashed var(--border); }
.inline-reply-box textarea{ resize:vertical; }

/* @mention autocomplete dropdown, positioned under a textarea[data-mentions]
   by app.js (initMentionAutocomplete). */
.mention-dropdown{
  position:absolute; z-index:40; background:var(--bg); border:1px solid var(--border);
  border-radius:var(--radius); box-shadow:var(--shadow-md); max-height:180px;
  overflow-y:auto; min-width:200px; display:none;
}
.mention-dropdown.open{ display:block; }
.mention-dropdown-item{
  display:flex; flex-direction:column; padding:7px 12px; cursor:pointer; font-size:13px;
}
.mention-dropdown-item .full-name{ font-weight:600; }
.mention-dropdown-item .username{ font-size:11.5px; color:var(--fg-subtle); }
.mention-dropdown-item:hover, .mention-dropdown-item.active{ background:var(--bg-subtle); }
.mention-textarea-wrap{ position:relative; }

/* ---------- Public user profile page (dataku.test/@username) ---------- */
.profile-head{ display:flex; align-items:center; gap:16px; flex-wrap:wrap; }
.profile-head .avatar-circle{ width:56px; height:56px; font-size:20px; }
.profile-head-meta{ min-width:0; }
.profile-head-name{ font-size:19px; font-weight:700; display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.profile-head-username{ color:var(--fg-subtle); font-size:13.5px; margin-top:2px; }
.profile-meta-row{ display:flex; gap:16px; flex-wrap:wrap; margin-top:10px; font-size:12.5px; color:var(--fg-muted); }
.profile-activity-item{ padding:12px 0; border-bottom:1px solid var(--border); }
.profile-activity-item:last-child{ border-bottom:none; padding-bottom:0; }
.profile-activity-item:first-child{ padding-top:0; }
.profile-activity-title{ font-weight:600; font-size:13.5px; }
.profile-activity-excerpt{ font-size:12.5px; color:var(--fg-muted); margin-top:2px; }

@media (max-width: 700px){
  .profile-head{ gap:12px; }
  .profile-head .avatar-circle{ width:46px; height:46px; font-size:17px; }
  .profile-head-name{ font-size:16.5px; }
}

/* ---------- Sidebar nav unread badge (Messages) ---------- */
.nav-badge{
  margin-left:auto; background:#fff; color:var(--black);
  font-size:10.5px; font-weight:700; line-height:1; padding:2px 6px;
  border-radius:20px; min-width:18px; text-align:center; flex-shrink:0;
}
.sidebar nav a.active .nav-badge{ background:var(--black); color:#fff; }

/* ---------- Direct Messaging ---------- */
.messages-layout{
  display:flex; height:calc(100vh - 150px); min-height:480px;
  border:1px solid var(--border); border-radius:var(--radius);
  background:var(--bg); overflow:hidden; box-shadow:var(--shadow-sm);
}

.messages-list-pane{
  width:300px; flex-shrink:0; border-right:1px solid var(--border);
  display:flex; flex-direction:column;
}
.messages-list-head{
  padding:14px 16px; border-bottom:1px solid var(--border);
  display:flex; align-items:center; justify-content:space-between; gap:8px;
}
.messages-list-head h3{ font-size:14px; margin:0; }
.messages-list-scroll{ flex:1; overflow-y:auto; }

.conversation-row{
  display:flex; align-items:flex-start; gap:10px; padding:12px 16px;
  border-bottom:1px solid var(--border); text-decoration:none; color:inherit;
  cursor:pointer;
}
.conversation-row:hover{ background:var(--bg-subtle); }
.conversation-row.active{ background:#f1f1f1; }
.conversation-row .conv-main{ flex:1; min-width:0; }
.conversation-row .conv-name-row{ display:flex; align-items:center; justify-content:space-between; gap:6px; }
.conversation-row .conv-name{ font-size:13.5px; font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.conversation-row .conv-time{ font-size:11px; color:var(--fg-subtle); flex-shrink:0; }
.conversation-row .conv-preview{
  font-size:12px; color:var(--fg-muted); margin-top:2px;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.conversation-row.has-unread .conv-name{ font-weight:700; color:var(--fg); }
.conversation-row.has-unread .conv-preview{ color:var(--fg); font-weight:600; }
.conv-unread-dot{
  width:8px; height:8px; border-radius:50%; background:var(--black);
  flex-shrink:0; margin-top:5px;
}

.messages-thread-pane{ flex:1; display:flex; flex-direction:column; min-width:0; }
.messages-thread-head{
  padding:12px 18px; border-bottom:1px solid var(--border);
  display:flex; align-items:center; gap:10px;
}
.messages-back-link{ display:none; color:var(--fg-muted); }
.messages-thread-scroll{ flex:1; overflow-y:auto; padding:18px; display:flex; flex-direction:column; gap:10px; }

.msg-bubble-row{ display:flex; align-items:center; gap:6px; }
.msg-bubble-row.own{ justify-content:flex-end; }
.msg-bubble{
  position:relative; max-width:62%; padding:9px 13px; border-radius:14px; font-size:13.5px; line-height:1.5;
  background:#f1f1f1; color:var(--fg);
}
.msg-bubble-row.own .msg-bubble{ background:var(--black); color:#fff; padding-right:26px; }
.msg-bubble .msg-time{ display:flex; align-items:center; justify-content:flex-end; gap:3px; font-size:10.5px; margin-top:4px; opacity:.6; }
.msg-status{ display:inline-flex; align-items:center; line-height:0; }
.msg-status-sent{ color:currentColor; }
.msg-status-read{ color:#34B7F1; opacity:1; }
#threadUserSub em{ font-style:italic; }

/* Deleted message: same bubble shell, muted placeholder text instead of
   the original body — shown to both the sender and the recipient once a
   message has been unsent, rather than the bubble simply vanishing. */
.msg-bubble-deleted{ font-style:italic; opacity:.65; }
.msg-bubble-deleted .msg-deleted-text{ font-style:italic; }

/* Small chevron trigger docked in the top-right corner of an own bubble —
   opens the message action sheet (reuses .modal-overlay/.action-sheet-box)
   instead of a bare "x" button. */
.msg-action-trigger{
  position:absolute; top:5px; right:5px; width:18px; height:18px; padding:0;
  display:inline-flex; align-items:center; justify-content:center;
  border:none; border-radius:50%; background:rgba(255,255,255,.14); color:#fff;
  cursor:pointer; opacity:.7; transition:opacity .15s ease, background-color .15s ease;
}
.msg-action-trigger:hover,
.msg-action-trigger:focus-visible{ opacity:1; background:rgba(255,255,255,.28); }

.messages-compose{ border-top:1px solid var(--border); padding:12px 16px; display:flex; gap:10px; align-items:flex-end; }
.messages-compose textarea{ flex:1; resize:none; min-height:40px; max-height:120px; }

.emoji-picker-wrap{ position:relative; }
.emoji-toggle-btn{
  border:1px solid var(--border); background:#fff; border-radius:8px; cursor:pointer;
  font-size:17px; line-height:1; padding:8px 9px; height:40px;
}
.emoji-toggle-btn:hover{ background:var(--bg-subtle); }
.emoji-popover{
  display:none; position:absolute; bottom:48px; left:0; z-index:20;
  background:#fff; border:1px solid var(--border); border-radius:10px; box-shadow:0 6px 20px rgba(0,0,0,.12);
  padding:8px; grid-template-columns:repeat(4, 1fr); gap:2px; width:168px;
}
.emoji-popover.open{ display:grid; }
.emoji-opt{
  border:none; background:transparent; cursor:pointer; font-size:19px; padding:6px; border-radius:6px;
}
.emoji-opt:hover{ background:var(--bg-subtle); }
.messages-empty-thread{
  flex:1; display:flex; align-items:center; justify-content:center;
  color:var(--fg-subtle); font-size:13px; text-align:center; padding:24px;
}

@media (max-width: 860px){
  .messages-layout{ height:calc(100vh - 130px); }
  .messages-list-pane{ width:100%; border-right:none; }
  .messages-layout.has-active-thread .messages-list-pane{ display:none; }
  .messages-layout:not(.has-active-thread) .messages-thread-pane{ display:none; }
  .messages-back-link{ display:inline-flex; }
  .msg-bubble{ max-width:80%; }
}

/* Notification center */
.notification-trigger{position:relative;display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;margin-right:8px;color:var(--text,#172033);border:1px solid var(--border,#e5e7eb);border-radius:10px;background:#fff;text-decoration:none;transition:.15s}
.notification-trigger:hover{background:#f8fafc;border-color:#d5dae2}
.notification-count{position:absolute;right:-4px;top:-5px;min-width:17px;height:17px;padding:0 4px;border-radius:10px;background:#ef4444;color:#fff;font:700 10px/17px Inter,sans-serif;text-align:center;border:2px solid #fff}
.notification-count.is-hidden{display:none}
/* Notification rows/broadcasts live inside the same .card / .card-head /
   .empty-state shell every other page uses (bookings, discussion, etc.) —
   no page-specific max-width or header component here, so width and
   header styling stay identical to the rest of the app. */
.notification-row{position:relative;display:flex;gap:14px;padding:16px 20px;border-bottom:1px solid var(--border);color:inherit;text-decoration:none;background:var(--bg);transition:background-color .15s ease}
.notification-row:last-child{border-bottom:0}
.notification-row:hover{background:var(--bg-subtle)}
.notification-row.is-unread{background:var(--blue-bg)}
.notification-icon{width:36px;height:36px;flex:0 0 36px;border-radius:10px;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:14px;background:#f1f1f1;color:var(--fg-muted)}
.notification-icon.type-message{background:var(--blue-bg);color:var(--blue)}
.notification-icon.type-mention{background:var(--purple-bg);color:var(--purple)}
.notification-icon.type-booking{background:var(--green-bg);color:var(--green)}
.notification-icon.type-system{background:var(--amber-bg);color:var(--amber)}
.notification-main{display:flex;min-width:0;flex-direction:column;gap:3px}
.notification-title-row{display:flex;align-items:center;gap:7px;flex-wrap:wrap}
.notification-main strong{font-size:13.5px;font-weight:600}
.notification-main span{font-size:13px;color:var(--fg-muted);line-height:1.5}
.notification-main small{font-size:11.5px;color:var(--fg-subtle)}
.notification-readmore{color:var(--blue);font-weight:600;font-size:12px;white-space:nowrap}
.notification-dot{width:7px;height:7px;border-radius:50%;background:var(--blue);margin:8px 0 0 auto;flex:0 0 7px}
.broadcast-list{padding:0}
.broadcast-row{display:flex;align-items:flex-start;justify-content:space-between;gap:20px;padding:16px 20px;border-bottom:1px solid var(--border)}
.broadcast-row:last-child{border-bottom:0}
.broadcast-row p{margin:6px 0;color:var(--fg-muted);font-size:13px;line-height:1.55}
.broadcast-row small{color:var(--fg-subtle);font-size:11.5px}
@media(max-width:680px){.notification-trigger{margin-right:3px}.broadcast-row{flex-direction:column;gap:10px}}
/* ---------- SPA navigation layer (assets/js/spa.js) ----------
   Thin top-of-page loading bar shown only once a navigation has taken
   long enough to notice (see progressStart()'s 150ms delay), so fast
   in-app navigations never flash it. Fixed to the viewport (not the
   swapped #spaApp content) so it survives every content swap untouched. */
.spa-progress{position:fixed;top:0;left:0;height:3px;width:0;background:var(--blue);z-index:9999;opacity:0;pointer-events:none;transition:width .3s ease,opacity .2s ease}
.spa-progress.spa-progress-show{width:75%;opacity:1;transition:width 3.5s cubic-bezier(.1,.6,.2,1),opacity .2s ease}
.spa-progress.spa-progress-done{width:100%;opacity:1;transition:width .2s ease}
.spa-progress.spa-progress-done.spa-progress-show{transition:width .2s ease,opacity .2s ease .2s}
