:root {
  /* Per-user preference now (see the Profile page / dashboard.js's
     applyTheme()), not a static "always dark" — this just declares which
     scheme the DEFAULT (no data-theme attribute, i.e. dark) actually is,
     so native browser chrome (date-picker popups, scrollbars, form
     controls) matches. The light override below sets its own. */
  color-scheme: dark;
  --bg: #0f172a;
  --panel: #1e293b;
  --panel-2: #273548;
  --border: #334155;
  --text: #e2e8f0;
  --muted: #94a3b8;
  /* Brand-derived, not arbitrary: the Awan Kusuma mark is a navy square
     with a white "AK" monogram and nothing else — --bg above already
     echoes that navy directly. --accent takes the same blue hue and turns
     it up in brightness/saturation so it reads as "the logo's own color,
     amplified" wherever the UI needs an actionable accent, rather than an
     unrelated color bolted on. Buttons, active states, outgoing chat
     bubbles, and clickable contact/company names (see .contact-name-link
     below — blue also happens to be the universal "this is a link" color)
     all point here. Kept identical in light mode below — brand color
     shouldn't shift with the theme, only the neutral scaffolding around it. */
  --accent: #3D7FFF;
  --accent-2: #2E63CC;
  --accent-text: #ffffff;
  /* Gold is blue's near-complement on the wheel — distinct on sight from
     --accent above, which is exactly why it's reserved for "needs
     attention" (unread badges, the notification-unread border, Calendar's
     TODAY badge) rather than ordinary buttons/active tabs. It also happens
     to be the classic navy+gold pairing finance/legal branding uses to
     read as trustworthy — a good fit for an NIB/business-registration CRM. */
  --accent-warm: #FFC857;
  --accent-warm-text: #06240f;
  --danger: #ef4444;
  --bubble-out: var(--accent);
  --bubble-in: #334155;
}

/* ---------- Light mode ----------
   Same structural relationships as the dark palette above (elevation,
   contrast, which token is lighter/darker than which), not an unrelated
   set of colors: --bg/--panel/--panel-2 are all built from the same
   neutral cool-gray family (an extension of the slate hue the dark palette
   already uses — --border/--muted/--text above are literally Tailwind's
   slate-700/400/200), just re-ordered for a light surface instead of a
   dark one. In dark mode each step from --bg to --panel to --panel-2 gets
   progressively LIGHTER (bg 0f172a -> panel 1e293b -> panel-2 273548), so
   an input field is the single brightest, most "pick me" surface on the
   page. Light mode keeps that same idea the other way around: --panel
   (white) is the brightest surface — a card lifted off the page — and
   --panel-2 pulls back just slightly toward gray for input fields sitting
   on it, the conventional "slightly recessed, editable" look, while --bg
   sits a shade further into gray still as the page's own backdrop. --text/
   --muted/--border are the same slate family read in reverse (dark text on
   light, instead of light text on dark), tuned to comfortably clear WCAG
   AA contrast against both --bg and --panel. --accent/--accent-2/
   --accent-warm/--accent-warm-text stay exactly as declared above — see
   that block's own notes on why brand color doesn't change with theme. */
:root[data-theme="light"] {
  color-scheme: light;
  --bg: #eef2f7;
  --panel: #ffffff;
  --panel-2: #f4f7fa;
  --border: #d7dee6;
  --text: #1e293b;
  --muted: #5b6b81;
  --danger: #dc2626;
  --bubble-in: #eef1f6;
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
}

body {
  font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg);
  color: var(--text);
}

/* ---------- Scrollbars (applies everywhere, not just the panels that
   happened to get scrollbar-width/-color set individually below) ---------- */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}
*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 999px;
  border: 2px solid var(--bg);
}
*::-webkit-scrollbar-thumb:hover { background: var(--muted); }

/* ---------- Login ---------- */
.login-wrap {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
}

.login-card {
  width: 100%;
  max-width: 360px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 32px;
}

.login-card h1 {
  font-size: 1.25rem;
  margin: 0 0 4px;
}

.login-logo {
  display: block;
  width: 64px;
  height: 64px;
  border-radius: 14px;
  margin: 0 0 12px;
}

.login-card p.subtitle {
  color: var(--muted);
  margin: 0 0 24px;
  font-size: 0.9rem;
}

label {
  display: block;
  font-size: 0.85rem;
  color: var(--muted);
  margin-bottom: 6px;
}

input[type="email"],
input[type="password"],
input[type="text"],
input[type="date"] {
  width: 100%;
  padding: 10px 12px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  font-size: 0.95rem;
  margin-bottom: 16px;
}
/* The date input's own popup calendar follows color-scheme, which is an
   inherited property — :root now declares the right one per theme (see
   the light-mode block above), so this only needs the pointer cursor;
   forcing "dark" here unconditionally would leave a dark calendar popup
   stuck on top of an otherwise light-themed page. */
input[type="date"] {
  cursor: pointer;
}
input[type="date"]:hover { border-color: var(--accent); }

/* A bare <select> with no more specific styling (e.g. the Database panel's
   Jenis Badan Usaha filter) had no color/background/border rule anywhere to
   fall back to, so it rendered as raw browser chrome — a plain white box in
   an otherwise dark app, same problem input[type="date"] had above. Scoped
   selects elsewhere (.users-form select, .order-detail-fields select, etc.)
   already have their own more specific rule and simply override this. */
select {
  padding: 10px 12px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  font-size: 0.95rem;
  cursor: pointer;
}
select:hover { border-color: var(--accent); }

input:focus, select:focus { outline: 2px solid var(--accent); }

button {
  cursor: pointer;
  border: none;
  border-radius: 8px;
  font-size: 0.95rem;
  font-weight: 600;
  padding: 10px 16px;
  /* Nearly every clickable control in this app is a plain <button> (tabs,
     category pills, icon buttons, links styled as buttons — see
     .contact-name-link) — one shared transition here means hover/active
     color changes feel deliberate everywhere at once, rather than the mix
     of instant snaps and one-off transitions that creeps in when each
     component adds its own. Component-specific rules can still override
     this if a particular hover effect calls for something else. */
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease, opacity 0.15s ease;
}

.btn-primary {
  width: 100%;
  background: var(--accent);
  color: var(--accent-text);
}
.btn-primary:hover { background: var(--accent-2); }

.btn-secondary {
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border);
}

.btn-danger { background: var(--danger); color: white; }

.error-text {
  color: var(--danger);
  font-size: 0.85rem;
  min-height: 1.2em;
  margin: -8px 0 12px;
}

/* ---------- Dashboard shell ---------- */
.app-shell {
  display: flex;
  height: 100vh;
  overflow: hidden;
}

.sidebar {
  width: 220px;
  flex-shrink: 0;
  background: var(--panel);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  padding: 20px 0;
  overflow: hidden;
  transition: width 0.15s ease, padding 0.15s ease;
}
.sidebar.collapsed {
  width: 0;
  padding: 0;
  border-right: none;
}

.brand-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 0 20px 20px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 12px;
  white-space: nowrap;
}

.brand {
  font-weight: 700;
  font-size: 1.1rem;
}

.brand-logo {
  width: 36px;
  height: 36px;
  border-radius: 9px;
  flex-shrink: 0;
}

.sidebar-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  white-space: nowrap;
}

/* Scrolls independently of .sidebar-footer below it (pinned there by its
   own margin-top: auto — see .sidebar-footer) — with 15+ tabs now, the list
   can run taller than the window, and it used to just get silently clipped
   with no way to reach the tabs at the bottom instead of scrolling to them. */
.sidebar-tabs {
  overflow-y: auto;
  min-height: 0;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}
.sidebar-tabs::-webkit-scrollbar { width: 6px; }
.sidebar-tabs::-webkit-scrollbar-track { background: transparent; }
.sidebar-tabs::-webkit-scrollbar-thumb { background: var(--border); border-radius: 999px; }
.sidebar-tabs::-webkit-scrollbar-thumb:hover { background: var(--muted); }

/* Sections the 17-tab sidebar is broken into (Messaging/Work/Admin — see
   dashboard.html) so scanning the list doesn't mean reading every single
   item every time. Collapsed state is per-group and persists across
   reloads (see dashboard.js's setupSidebarGroups()) — someone who never
   touches Admin can tuck it away for good. */
.sidebar-group { margin-top: 4px; }
.sidebar-group-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  background: transparent;
  border: none;
  padding: 10px 20px 6px;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  cursor: pointer;
  transition: color 0.15s ease;
}
.sidebar-group-header:hover { color: var(--text); }
.sidebar-group-chevron {
  transition: transform 0.15s ease;
  font-size: 0.65rem;
}
.sidebar-group.collapsed .sidebar-group-chevron { transform: rotate(-90deg); }
.sidebar-group.collapsed .sidebar-group-body { display: none; }

.icon-btn {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  padding: 0;
  border-radius: 6px;
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.75rem;
}
.icon-btn:hover { background: var(--border); }

.sidebar-expand-btn {
  position: fixed;
  top: 20px;
  left: 12px;
  z-index: 5;
}

.tab-btn {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  text-align: left;
  background: transparent;
  color: var(--text);
  padding: 12px 20px;
  font-weight: 500;
  border-radius: 0;
}
.tab-btn:hover { background: var(--panel-2); }
.tab-btn.active { background: var(--panel-2); border-right: 3px solid var(--accent); }
.tab-badge {
  margin-left: auto;
  background: var(--accent-warm);
  color: var(--accent-warm-text);
  font-size: 0.7rem;
  font-weight: 700;
  border-radius: 999px;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.sidebar-footer {
  margin-top: auto;
  padding: 12px 20px 0;
  border-top: 1px solid var(--border);
}

.sidebar-footer .who {
  font-size: 0.8rem;
  color: var(--muted);
  margin-bottom: 10px;
  word-break: break-all;
}

.role-badge {
  display: inline-block;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-text);
  margin-bottom: 8px;
}

.profile-badge {
  display: inline-block;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--border);
  color: var(--text);
  margin-bottom: 8px;
  margin-right: 6px;
}

.main {
  flex: 1;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.panel {
  display: none;
  flex: 1;
  min-height: 0;
  flex-direction: column;
  padding: 24px;
  overflow: auto;
}
.panel.active { display: flex; }

.panel h2 { margin-top: 0; }

.panel-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.panel-header-row h2 { margin-bottom: 0; }

.panel-header-actions {
  display: flex;
  gap: 8px;
}

/* ---------- QR panel ---------- */
.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.85rem;
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  margin-bottom: 20px;
}
.status-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--muted); }
.status-dot.ready { background: var(--accent); }
.status-dot.qr { background: #eab308; }
.status-dot.auth_failure, .status-dot.disconnected { background: var(--danger); }

.qr-box {
  background: white;
  padding: 20px;
  border-radius: 12px;
  display: inline-flex;
  width: fit-content;
}
.qr-box img { width: 260px; height: 260px; display: block; }

/* ---------- Chat panel ---------- */
.chat-layout {
  display: flex;
  flex: 1;
  min-height: 0;
  gap: 0;
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
}

.chat-list-pane {
  width: 300px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--panel);
  border-right: 1px solid var(--border);
}

.chat-search {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}
.chat-search input { flex: 1; min-width: 0; margin-bottom: 0; }

.chat-unread-filter-btn {
  flex-shrink: 0;
  padding: 8px 12px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--muted);
  font-size: 0.8rem;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  white-space: nowrap;
}
.chat-unread-filter-btn:hover { color: var(--text); }
.chat-unread-filter-btn.active { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }

.chat-list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}

.chat-list-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  transition: background-color 0.15s ease;
}
.chat-list-item:hover { background: var(--panel-2); }
.chat-list-item.active { background: var(--panel-2); }

.chat-avatar {
  position: relative;
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  font-weight: 700;
  font-size: 0.9rem;
  color: var(--accent-text);
  background: var(--accent);
}
.chat-avatar.thread-size { width: 34px; height: 34px; font-size: 0.8rem; }

.team-chat-room-avatar { background: #6366f1; font-size: 1.1rem; }
.team-chat-room-item { border-bottom: 1px solid var(--border); }

.team-chat-bubble-sender {
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--accent);
  margin-bottom: 2px;
}
/* Element+class, not just the class alone — only ever matters for the
   WhatsApp group-chat sender label (a real <button>, clickable to save a
   name — see applyBubbleContent()), so Team Chat's own plain <div> version
   of this same class (unclickable, just a label) is untouched. */
button.team-chat-bubble-sender {
  display: block;
  background: none;
  border: none;
  padding: 0;
  font-family: inherit;
  cursor: pointer;
  text-align: left;
}
button.team-chat-bubble-sender:hover { text-decoration: underline; }
.chat-avatar-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.15s ease;
}
.chat-avatar-img.loaded { opacity: 1; }

.chat-list-item .item-main {
  flex: 1;
  min-width: 0;
}
.chat-list-item .item-top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
}
.chat-list-item .name { font-weight: 600; font-size: 0.9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-list-item .timestamp { color: var(--muted); font-size: 0.72rem; flex-shrink: 0; }
.chat-list-item .preview { color: var(--muted); font-size: 0.8rem; margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chat-list-item .unread-badge {
  flex-shrink: 0;
  background: var(--accent-warm);
  color: var(--accent-warm-text);
  font-size: 0.7rem;
  font-weight: 700;
  border-radius: 999px;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.chat-remove-btn {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  padding: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--muted);
  font-size: 0.8rem;
  line-height: 1;
  opacity: 0;
  transition: opacity 0.1s ease, background 0.1s ease, color 0.1s ease;
}
.chat-list-item:hover .chat-remove-btn { opacity: 1; }
.chat-remove-btn:hover { background: var(--danger); color: #fff; }

.chat-thread {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  background: var(--bg);
}

.thread-header {
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.thread-header-info {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
.thread-header-text { min-width: 0; flex: 1; }
#thread-header-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.thread-header-name-row { display: flex; align-items: center; gap: 8px; min-width: 0; }

.chat-type-badge {
  flex-shrink: 0;
  display: inline-block;
  font-size: 0.65rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--muted);
}
.chat-type-badge.is-group { color: var(--accent); border-color: var(--accent); }

.thread-header-note {
  flex-shrink: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--muted);
  font-size: 0.8rem;
  font-style: italic;
}

.thread-header-actions { display: flex; align-items: center; gap: 10px; flex-shrink: 0; }

.chat-tags {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

.tag-pill {
  display: inline-block;
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--text);
  font-size: 0.7rem;
  font-weight: 600;
  padding: 2px 9px;
  border-radius: 999px;
  white-space: nowrap;
}

.database-history-count {
  display: inline-block;
  color: var(--muted);
  font-size: 0.75rem;
  font-weight: 600;
  margin-left: 6px;
}

.tag-picker-wrap { position: relative; flex-shrink: 0; }

.assignee-picker-wrap { position: relative; }
.assignee-picker-btn {
  width: 100%;
  text-align: left;
  padding: 9px 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  font-size: 0.9rem;
  font-family: inherit;
  cursor: pointer;
}
.assignee-picker-wrap .tag-picker { top: calc(100% + 6px); left: 0; right: 0; width: auto; }

.tag-picker-search {
  width: 100%;
  margin: 0 0 6px 0;
  padding: 7px 9px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  font-size: 0.85rem;
  font-family: inherit;
}

.tag-picker-list { max-height: 180px; overflow-y: auto; }

.tag-picker {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  width: 220px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
  z-index: 10;
}

.tag-picker-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: 6px;
  font-size: 0.85rem;
  font-weight: 500;
  cursor: pointer;
}
.tag-picker-item:hover { background: var(--panel-2); }
.tag-picker-item input { margin: 0; }

.tag-picker-empty {
  padding: 8px;
  color: var(--muted);
  font-size: 0.8rem;
}

.thread-messages {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}

.bubble {
  /* 65% made sense for short chat lines, but this business's messages are
     often long structured summaries (KBLI/OSS data dumps) that wrapped
     into a tall, narrow column at that width — nowhere near how wide
     WhatsApp itself renders the same message. min() keeps it proportional
     on a narrow panel (e.g. the order pane open alongside) while capping
     it at a sane absolute width on a wide one, rather than letting a
     one-line message stretch edge to edge. */
  max-width: min(80%, 620px);
  padding: 8px 12px;
  border-radius: 10px;
  font-size: 0.9rem;
  line-height: 1.35;
}
.bubble.in { align-self: flex-start; background: var(--bubble-in); }
.bubble.out { align-self: flex-end; background: var(--bubble-out); color: var(--accent-text); }
.bubble { position: relative; }
/* A ring rather than a background swap (unlike .order-comment-highlight) —
   a bubble's own background often sits directly behind an image/PDF card
   filling most of it, where recoloring it would just look broken instead
   of drawing attention. */
.bubble-highlight { box-shadow: 0 0 0 2px var(--accent); }

/* Matches WhatsApp's own bolded/colored mention styling — see
   renderMentionsForDisplay(). .bubble.out already sets --accent-text for
   its whole body, so a mention there needs its own contrasting color
   instead — --accent-warm (gold) reads clearly against the blue bubble and
   doubles as "this needs your attention," same job it does everywhere else. */
.mention-chip { font-weight: 700; color: var(--accent); cursor: pointer; }
.mention-chip:hover { text-decoration: underline; }
.bubble.out .mention-chip { color: var(--accent-warm); }
/* Couldn't be resolved to a name from Contacts or this chat's loaded
   participant list (see renderMentionsForDisplay()) — dashed underline
   hints there's more to it than the label shown, same as a leftover of any
   "click to fill in" affordance elsewhere. */
.mention-chip-unresolved { text-decoration: underline dashed; text-underline-offset: 2px; }
.mention-chip-unresolved:hover { text-decoration-style: solid; }

.bubble-quote {
  margin-bottom: 6px;
  padding: 4px 8px;
  border-left: 3px solid rgba(0, 0, 0, 0.25);
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.08);
  font-size: 0.82rem;
  opacity: 0.85;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.bubble-quote-unknown { font-style: italic; }

.bubble-deleted { font-style: italic; opacity: 0.7; }
.bubble-edited { font-size: 0.72rem; opacity: 0.65; margin-left: 4px; }
.bubble-time { margin-top: 2px; text-align: right; font-size: 0.7rem; opacity: 0.65; }

/* A plain <div> collapses newlines and repeated spaces by default — the
   exact opposite of what a structured message (KBLI/OSS data dumps full of
   manually-aligned "Label : value" lines) needs. WhatsApp itself renders
   these with every line break intact; without this, the same message here
   ran together into one long wrapped paragraph, discarding the sender's
   own formatting entirely. pre-wrap keeps both the line breaks and the
   alignment spacing while still wrapping at the bubble's edge (unlike
   plain "pre", which would just overflow instead) — break-word on top
   stops one unbroken long token (a bare URL, say) from stretching the
   bubble past its max-width. */
.bubble-body {
  white-space: pre-wrap;
  word-break: break-word;
}

.bubble-actions {
  display: none;
  position: absolute;
  top: 3px;
  align-items: center;
  height: 20px;
  /* Higher than every other overlay in the app (order/contact detail
     modals, image lightbox, forward picker, even the chat-list right-click
     menu — all 50 or below) so the trigger and its dropdown are never
     hidden behind another panel, no matter what else happens to be open. */
  z-index: 1100;
}
/* WhatsApp Web's actual treatment: the trigger sits inside the bubble's own
   corner, with the message text fading into the bubble's own background
   color behind it (a gradient, not a separate floating panel) — same side
   convention as before (incoming's trigger on the right, outgoing's on the
   left), just anchored inside the bubble now instead of just outside it. */
.bubble.in .bubble-actions {
  right: 2px;
  padding-left: 22px;
  background: linear-gradient(to right, transparent, var(--bubble-in) 65%);
}
.bubble.out .bubble-actions {
  left: 2px;
  padding-right: 22px;
  background: linear-gradient(to left, transparent, var(--bubble-out) 65%);
}
/* Stays visible once its dropdown is open (see openBubbleMenu()), not just
   on :hover — otherwise moving the mouse toward the menu itself would make
   the trigger's own container disappear first. */
.bubble:hover .bubble-actions,
.bubble-actions.menu-open {
  display: flex;
}
.bubble-menu-trigger {
  width: 20px;
  height: 20px;
  padding: 0;
  border: none;
  border-radius: 6px;
  background: none;
  color: inherit;
  font-size: 0.95rem;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.bubble-menu-trigger:hover { background: rgba(0, 0, 0, 0.15); }

.bubble-dropdown-menu {
  /* position:fixed, appended straight to <body> and positioned in JS from
     the trigger's own getBoundingClientRect() (see openBubbleMenu() /
     positionBubbleMenu() in dashboard.js) — NOT nested inside the
     scrollable thread. .thread-messages sets overflow-y: auto, which per
     the CSS spec forces overflow-x to clip too (a plain "auto" on one axis
     can't leave the other as visible) — no z-index could ever fix that,
     since it's a clipping problem, not a stacking one. Rendering at the
     body level sidesteps it entirely.
  */
  position: fixed;
  min-width: 170px;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 4px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
  z-index: 1100;
}
.bubble-dropdown-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  text-align: left;
  padding: 8px 10px;
  border: none;
  background: none;
  color: var(--text);
  border-radius: 6px;
  font-size: 0.85rem;
  font-weight: 500;
  font-family: inherit;
}
.bubble-dropdown-item:hover { background: var(--panel-2); }
.bubble-dropdown-icon { font-size: 1rem; width: 18px; flex-shrink: 0; text-align: center; }

.bubble-select-checkbox {
  display: none;
  position: absolute;
  top: 6px;
  left: -28px;
}
.bubble.out .bubble-select-checkbox { left: auto; right: -28px; }
.thread-messages.selection-mode .bubble-select-checkbox { display: block; }
.thread-messages.selection-mode .bubble-actions { display: none !important; }

.selection-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--panel-2);
  font-size: 0.85rem;
  font-weight: 600;
}
.selection-toolbar-actions { display: flex; gap: 8px; }
.selection-toolbar-actions .btn-secondary { width: auto; padding: 7px 12px; font-size: 0.82rem; }

.forward-picker-overlay {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.6);
  padding: 20px;
}
.forward-picker-modal {
  width: 100%;
  max-width: 380px;
  max-height: 70vh;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border-radius: 12px;
  border: 1px solid var(--border);
  overflow: hidden;
}
.forward-picker-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border);
  font-weight: 700;
}
.forward-picker-list { overflow-y: auto; padding: 6px; }
.forward-picker-item {
  padding: 10px 12px;
  border-radius: 8px;
  font-size: 0.88rem;
  cursor: pointer;
}
.forward-picker-item:hover { background: var(--panel-2); }

.bubble-edit-input {
  width: 100%;
  min-height: 60px;
  margin-bottom: 6px;
  padding: 6px 8px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.9);
  color: #111;
  font-size: 0.88rem;
  font-family: inherit;
  resize: vertical;
}
.bubble-edit-actions { display: flex; justify-content: flex-end; gap: 8px; }
.bubble-edit-actions button { padding: 5px 12px; font-size: 0.8rem; width: auto; }

.attachment {
  /* .bubble-body sets white-space: pre-wrap so a manually-formatted message
     body keeps its line breaks — but that's inherited by every descendant,
     including this one, whose own markup is pure structural HTML (nested
     divs/spans spread across multiple indented lines in the template
     literal that builds it). Under pre-wrap, the newlines and indentation
     *between* those tags stop being collapsible and each renders as a real
     blank line. Resetting to normal here removes that misfire without
     touching pre-wrap for the actual caption text, which is a separate
     sibling element (.attachment-caption). */
  white-space: normal;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: 8px;
  border: none;
  background: rgba(0, 0, 0, 0.12);
  color: inherit;
  text-decoration: none;
  font-family: inherit;
  width: auto;
  text-align: left;
  cursor: pointer;
}
.attachment:hover { background: rgba(0, 0, 0, 0.2); }
.attachment-unavailable {
  cursor: default;
  opacity: 0.65;
  font-style: italic;
}
.attachment-unavailable:hover { background: rgba(0, 0, 0, 0.12); }
.attachment-icon { font-size: 1.2rem; flex-shrink: 0; }
.attachment-name {
  font-size: 0.85rem;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Capped to match .attachment-image/.attachment-pdf-card's own width (both
   260px) — without this, a caption long enough to want more room on one
   line pulls the whole bubble wider than the actual attachment sitting
   above it (bubble sizing is shrink-to-fit off whichever child needs the
   most width — see .attachment-image's own notes), leaving a narrow
   image/PDF card stranded inside a much wider bubble. WhatsApp wraps the
   caption to the attachment's own width instead; this matches that. */
.attachment-caption { margin-top: 6px; font-size: 0.9rem; max-width: 260px; overflow-wrap: break-word; }

.attachment-image {
  /* No "width: 100%" here on purpose — a percentage width on a child of a
     shrink-to-fit bubble (.bubble has no set width of its own; it hugs its
     content) resolves against the *available* space rather than the
     bubble's eventual size, which drags the whole bubble out to nearly
     full width regardless of how small the image actually is. Sizing to
     the image's own intrinsic dimensions (capped by max-width/max-height)
     keeps the bubble hugging the image the way WhatsApp's own does. */
  display: block;
  max-width: 260px;
  max-height: 260px;
  border-radius: 8px;
  object-fit: cover;
  cursor: pointer;
}

/* Same shrink-to-fit reasoning as .attachment-image above, just its own
   class since Team Chat bubbles are a separate template from WhatsApp's
   (see teamChatBubbleHtml()). */
.team-chat-bubble-attachments { display: flex; flex-direction: column; gap: 6px; margin-bottom: 6px; }
.team-chat-attachment-image { display: block; max-width: 260px; max-height: 260px; border-radius: 8px; object-fit: cover; cursor: pointer; }
.team-chat-attachment-file {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: 8px;
  background: rgba(0, 0, 0, 0.12);
  color: inherit;
  text-decoration: none;
  font-size: 0.85rem;
  font-weight: 600;
  white-space: normal;
}
.team-chat-attachment-file:hover { background: rgba(0, 0, 0, 0.2); }

.image-lightbox {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.85);
}
.image-lightbox img {
  max-width: 90vw;
  max-height: 90vh;
  object-fit: contain;
  border-radius: 4px;
}
.image-lightbox-close {
  position: absolute;
  top: 20px;
  right: 20px;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  font-size: 1.1rem;
  border: 1px solid rgba(255, 255, 255, 0.2);
}
.image-lightbox-close:hover { background: rgba(255, 255, 255, 0.22); }

/* A page-1 thumbnail + file info card, matching WhatsApp's own PDF
   attachment rendering — see renderPdfThumbnailCard() in dashboard.js,
   which renders the actual first page into .attachment-pdf-canvas via
   pdf.js. Clicking anywhere on the card opens the file in a new tab
   (plain window.open — no in-app viewer). WhatsApp's own card shows only
   a cropped peek of the page's top, not the whole page shrunk to fit —
   rendering the full page at a fixed *width* made the card as tall as a
   full page (WhatsApp's stays a fixed, modest height regardless of the
   document's own page proportions), so .attachment-pdf-thumb below is a
   fixed-height, overflow:hidden window onto the canvas rather than sizing
   to it. */
.attachment-pdf-card {
  /* Same fix as .attachment above: this card's own markup is spread across
     several indented lines, and .bubble-body's inherited pre-wrap turns
     that whitespace into real blank lines between the thumb, badge, name
     and stats — this is what was inflating the info row's height. */
  white-space: normal;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  width: 260px;
  max-width: 100%;
  border-radius: 8px;
  overflow: hidden;
  background: rgba(0, 0, 0, 0.12);
  cursor: pointer;
  border: none;
  padding: 0;
  font-family: inherit;
  text-align: left;
  color: inherit;
}
.attachment-pdf-thumb {
  width: 100%;
  height: 140px;
  overflow: hidden;
  background: #fff;
}
.attachment-pdf-canvas {
  display: block;
  width: 100%;
  height: auto;
}
/* Shown in place of the canvas until it's finished rendering, or if
   rendering fails outright (e.g. pdf.js couldn't load) — never leaves an
   empty gap where the thumbnail would be. */
.attachment-pdf-canvas-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.08);
  font-size: 1.5rem;
}
.attachment-pdf-info {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 4px 6px;
}
.attachment-pdf-badge {
  flex-shrink: 0;
  width: 24px;
  height: 24px;
  border-radius: 4px;
  background: #dc2626;
  color: #fff;
  font-size: 0.52rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}
.attachment-pdf-meta { min-width: 0; flex: 1; }
/* Tight line-height scoped to this one context only — .attachment-name is
   shared with other attachment types elsewhere that don't need it this
   snug, so it's set here rather than on the shared class itself. */
.attachment-pdf-meta .attachment-name { line-height: 1.15; }
.attachment-pdf-stats { font-size: 0.68rem; opacity: 0.75; line-height: 1.15; margin-top: 0; }

.message-info-overlay {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.6);
  padding: 20px;
}
.message-info-modal {
  width: 100%;
  max-width: 420px;
  max-height: 80vh;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border-radius: 12px;
  border: 1px solid var(--border);
  overflow: hidden;
}
.message-info-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px;
  border-bottom: 1px solid var(--border);
  font-weight: 700;
}
.message-info-body { padding: 14px 16px; overflow-y: auto; }
.message-info-section { margin-bottom: 14px; }
.message-info-section h4 { margin: 0 0 6px; font-size: 0.85rem; color: var(--muted); }
.message-info-section ul { margin: 0; padding-left: 18px; font-size: 0.85rem; }
.message-info-section li { margin-bottom: 4px; }

.composer-reply-preview {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-top: 1px solid var(--border);
  background: var(--panel-2);
  font-size: 0.85rem;
}
.composer-reply-label { flex-shrink: 0; color: var(--muted); font-weight: 600; }
.composer-reply-text {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.composer-attachment {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-top: 1px solid var(--border);
  background: var(--panel-2);
  font-size: 0.85rem;
}
.composer-attachment-thumb {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border-radius: 6px;
  object-fit: cover;
}
#composer-attachment-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.thread-composer {
  display: flex;
  /* Stretch (not center) so Send grows to match the composer textarea's
     own height (now 5 rows tall by default — see #composer-input) instead
     of sitting as a short pill next to a much taller text box. The icon
     buttons below keep their own fixed 40x40 regardless, since an explicit
     height wins over stretch. */
  align-items: stretch;
  gap: 8px;
  padding: 12px;
  border-top: 1px solid var(--border);
}
.thread-composer input { width: 100%; min-width: 0; margin-bottom: 0; }
.thread-composer button { flex: 0 0 auto; width: auto; white-space: nowrap; }
/* The generic .icon-btn size (28x28) reads as undersized next to the taller
   text input/Send button in this row — match their height instead. Fixed
   height here also opts them out of the row's own align-items: stretch. */
.thread-composer .icon-btn { width: 40px; height: 40px; font-size: 1.1rem; align-self: center; }

.composer-input-wrap { position: relative; flex: 1; min-width: 0; }

/* A textarea now (see dashboard.html) so Shift+Enter can insert a real
   newline — plain <input> elements can never hold more than one line no
   matter what key is pressed. Starts at one row's height (see rows="1")
   and grows with the text up to max-height, then scrolls (see
   autoGrowComposerInput() in dashboard.js). Shared by the WhatsApp
   composer (#composer-input) and Team Chat's (#team-chat-composer-input) —
   a class, not an id-specific rule, so both actually get it. */
.composer-textarea {
  width: 100%;
  min-width: 0;
  margin-bottom: 0;
  padding: 6px 12px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  font-size: 0.95rem;
  font-family: inherit;
  line-height: 1.4;
  resize: none;
  max-height: 120px;
  overflow-y: auto;
}
.composer-textarea:focus { outline: 2px solid var(--accent); }
/* The Chat page's own composer specifically (not Team Chat's, whose
   messages are ordinarily short) — customer conversations here regularly
   involve longer structured text (KBLI lists, multi-line instructions),
   which used to hit the shared 120px ceiling after just a few lines and
   force an inner scrollbar almost immediately. */
#composer-input { max-height: 220px; }

/* Typing "@" in a group chat opens this above the composer, filtered as you
   keep typing — WhatsApp Web's own pattern, not a separate mention button. */
.mention-picker {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 0;
  right: 0;
  max-height: 260px;
  overflow-y: auto;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
  padding: 6px;
  z-index: 30;
}
.mention-picker-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 8px;
  cursor: pointer;
}
.mention-picker-item:hover { background: var(--panel-2); }
.mention-picker-item-name { font-weight: 600; font-size: 0.88rem; }
.mention-picker-item-sub { font-size: 0.75rem; color: var(--muted); margin-top: 2px; }
.mention-picker-all-item { border-bottom: 1px solid var(--border); border-radius: 8px 8px 0 0; margin-bottom: 4px; }
.mention-picker-all-icon {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--panel-2);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1rem;
}

/* align-self: center keeps this from stretching to the composer row's full
   height (see .thread-composer's align-items: stretch, added for Send's
   own height) — without it, the emoji button sitting inside just stuck to
   the top of the stretched wrapper instead of lining up with the attach/
   template icon buttons next to it, which are direct flex items and
   already centered on their own. */
.emoji-picker-wrap { position: relative; flex-shrink: 0; align-self: center; }
.emoji-picker {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 0;
  width: 260px;
  max-height: 220px;
  overflow-y: auto;
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
  padding: 6px;
  z-index: 30;
}
.emoji-picker-item {
  background: none;
  border: none;
  border-radius: 6px;
  font-size: 1.25rem;
  line-height: 1;
  padding: 6px 0;
  cursor: pointer;
}
.emoji-picker-item:hover { background: var(--panel-2); }

.order-pane {
  width: 320px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--panel);
  border-left: 1px solid var(--border);
}

.order-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
  font-weight: 600;
}

.order-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 16px 18px;
}
.order-form .field { min-width: 0; }
.order-form label { margin-bottom: 6px; }
.order-form select,
.order-form input,
.order-form textarea {
  width: 100%;
  margin-bottom: 0;
  padding: 9px 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  font-size: 0.9rem;
  font-family: inherit;
  resize: vertical;
}
.order-form input { text-transform: uppercase; }

.order-title-preview {
  margin: 0 18px;
  padding: 10px 12px;
  border-radius: 8px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  font-size: 0.85rem;
  font-weight: 600;
  word-break: break-word;
}

.order-send-chat-toggle {
  margin: 10px 18px 0;
}
.order-submit-row {
  margin: 12px 18px 0;
}
.order-submit-row .btn-primary { width: 100%; }
.order-revise-cancel {
  display: block;
  margin-top: 6px;
  font-size: 0.75rem;
  color: var(--accent);
  text-align: center;
}

.order-status {
  padding: 6px 18px 14px;
  font-size: 0.75rem;
  color: var(--muted);
  min-height: 1.2em;
}

.order-list-header {
  margin: 4px 18px 8px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}

.order-list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 0 18px 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}

.order-list-empty {
  font-size: 0.85rem;
  color: var(--muted);
}

.order-list-item {
  position: relative;
  padding: 10px 56px 10px 12px;
  border-radius: 8px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  cursor: pointer;
  transition: border-color 0.15s ease;
}
.order-list-item:hover { border-color: var(--muted); }
.order-list-item.active { border-color: var(--accent); background: rgba(255, 200, 87, 0.1); }
.order-list-title { font-size: 0.85rem; font-weight: 600; word-break: break-word; }
.order-list-meta { margin-top: 4px; font-size: 0.75rem; color: var(--muted); }

.order-remove-btn,
.order-revise-btn {
  position: absolute;
  top: 8px;
  width: 20px;
  height: 20px;
  padding: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--muted);
  font-size: 0.72rem;
  line-height: 1;
  opacity: 0;
  transition: opacity 0.1s ease, background 0.1s ease, color 0.1s ease;
}
.order-remove-btn { right: 8px; }
.order-revise-btn { right: 32px; font-size: 0.68rem; }
.order-list-item:hover .order-remove-btn,
.order-list-item:hover .order-revise-btn {
  opacity: 1;
}
.order-remove-btn:hover { background: var(--danger); color: #fff; }
.order-revise-btn:hover { background: var(--panel); color: var(--text); }

/* ---------- Pipeline card detail modal ---------- */
.order-detail-overlay {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.6);
  padding: 20px;
}
/* Opened from the To Do board (see openOrderDetailModal()'s anchor param)
   instead of the Pipeline board — same modal, docked to the right edge as a
   full-height panel instead of a centered dialog. */
.order-detail-overlay.anchor-right {
  justify-content: flex-end;
  padding: 0;
  background: rgba(0, 0, 0, 0.4);
}
.order-detail-overlay.anchor-right .order-detail-modal {
  max-width: 640px;
  max-height: 100vh;
  height: 100%;
  border-radius: 0;
  border-width: 0 0 0 1px;
}

/* Used when opened from the Calendar (see openTaskFromLink()) — docks to
   the left edge instead, so the Calendar grid itself stays visible in the
   remaining space rather than being fully covered. */
.order-detail-overlay.anchor-left {
  justify-content: flex-start;
  padding: 0;
  background: rgba(0, 0, 0, 0.4);
}
.order-detail-overlay.anchor-left .order-detail-modal {
  max-width: 640px;
  max-height: 100vh;
  height: 100%;
  border-radius: 0;
  border-width: 0 1px 0 0;
}

.order-detail-modal {
  width: 100%;
  max-width: 560px;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border-radius: 12px;
  border: 1px solid var(--border);
  overflow: hidden;
}

/* Centered (not docked to an edge — see the anchor-right/anchor-left
   overrides above, which stay narrow) gets extra width so Keterangan
   Tambahan's own panel (see .order-detail-keterangan-panel below) has
   somewhere to sit beside the rest of the fields instead of just under
   them — real-world content there (a full OSS registration summary) runs
   30-40 lines, and a cramped 560px column made that unreadable. Scoped to
   #order-detail-overlay specifically — the Contact/Overview detail popups
   reuse the same .order-detail-modal classes for their own, much shorter
   forms and shouldn't also balloon to 920px. */
#order-detail-overlay:not(.anchor-right):not(.anchor-left) .order-detail-modal {
  max-width: 920px;
}

.order-detail-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: 16px 18px;
  border-bottom: 1px solid var(--border);
}
.order-detail-header-text { min-width: 0; }
.order-detail-title { font-size: 1.05rem; font-weight: 700; word-break: break-word; }
.order-detail-subtitle { margin-top: 2px; font-size: 0.85rem; color: var(--muted); }
.order-detail-header-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }

.order-detail-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 16px 18px;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}

.order-detail-meta {
  display: flex;
  align-items: center;
  gap: 24px;
  margin-bottom: 16px;
  font-size: 0.82rem;
}
.order-detail-paid-slot { margin-left: auto; }
.order-detail-meta-label {
  display: block;
  color: var(--muted);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  margin-bottom: 2px;
}
/* "Time per stage" breakdown (see dashboard.js's renderStageDaysBreakdown())
   — sits right under the Created by/Created row, empty (no margin) when
   there's nothing to show yet (a brand-new order with no stageHistory). */
.order-detail-stage-days {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-bottom: 16px;
}
.order-detail-stage-days:empty { margin-bottom: 0; }
.order-detail-stage-days-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-size: 0.8rem;
}
.order-detail-stage-days-row span:first-child { color: var(--text); font-weight: 600; }
.order-detail-stage-days-row span:last-child { color: var(--muted); }

/* Fields on the left, Keterangan Tambahan as its own tall panel on the
   right (see .order-detail-keterangan-panel) — side by side only when
   there's room for it (centered modal, see the max-width override above);
   collapses back to stacked in the docked anchor-right/anchor-left variants,
   which stay narrow on purpose. align-items: stretch is what makes the
   Keterangan panel end up as tall as the fields column next to it, rather
   than needing a hardcoded height guess. */
.order-detail-main {
  display: flex;
  align-items: stretch;
  gap: 20px;
  margin-bottom: 12px;
}
.order-detail-overlay.anchor-right .order-detail-main,
.order-detail-overlay.anchor-left .order-detail-main {
  flex-direction: column;
}

.order-detail-fields {
  flex: 1;
  min-width: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-content: start;
  gap: 12px;
}
.order-detail-field-wide { grid-column: 1 / -1; }
.order-detail-fields .field label { margin-bottom: 6px; }
/* Invoice / Belum Kirim NIB / Revisi stacked in the grid column right next
   to Due date — same row, so they read as "everything about this task's
   status" alongside its date, rather than each manual marker taking a
   whole separate grid row of its own further down the form. */
.order-detail-checkbox-row { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.order-detail-fields select,
.order-detail-fields input,
.order-detail-fields textarea,
.order-detail-keterangan-panel textarea {
  width: 100%;
  padding: 9px 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  font-size: 0.9rem;
  font-family: inherit;
  resize: vertical;
}
.order-detail-fields select[multiple] { resize: vertical; }

.order-detail-keterangan-panel {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.order-detail-keterangan-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 6px;
}
.order-detail-keterangan-header label { margin-bottom: 0; }
.order-detail-keterangan-header .btn-secondary { width: auto; flex-shrink: 0; padding: 6px 14px; font-size: 0.82rem; }
.order-detail-keterangan-panel label { margin-bottom: 6px; }
.order-detail-keterangan-panel .oss-check-status { margin-top: 6px; }
.order-detail-keterangan-panel textarea {
  flex: 1;
  min-height: 260px;
  /* The pasted OSS summaries this field actually holds (see the field's
     placeholder) lean on repeated "──────" divider characters and
     label:value alignment to stay readable — a monospace font is what
     keeps those lined up instead of drifting under a proportional one. */
  font-family: 'Courier New', ui-monospace, monospace;
  line-height: 1.5;
}

/* Checkboxes/radios (e.g. the contact detail modal's tag list) must never
   pick up the 100%-width rule above — that stretches each checkbox across
   the whole row, shoving its label far off to the right instead of sitting
   right next to it. */
.order-detail-fields input[type="checkbox"],
.order-detail-fields input[type="radio"] {
  width: auto;
}

.order-detail-oss-credentials-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-top: 8px;
  padding: 10px;
  border-radius: 8px;
  background: rgba(0, 0, 0, 0.15);
}

/* Lokasi Usaha (Alamat/Kelurahan/Kecamatan/Kabupaten/Provinsi/Kode Pos) —
   same nested-panel look as .order-detail-oss-credentials-grid above, just
   3 columns instead of 2 since 5 short fields (plus Alamat spanning the
   full width via .order-detail-field-wide) divide more evenly that way. */
.order-detail-location-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  margin-top: 8px;
  padding: 10px;
  border-radius: 8px;
  background: rgba(0, 0, 0, 0.15);
}

.oss-credential-row { display: flex; gap: 6px; align-items: center; }
.oss-credential-row input, .oss-credential-row select { flex: 1; min-width: 0; margin-bottom: 0; }
.oss-credential-row .icon-btn, .oss-credential-row .btn-secondary { flex-shrink: 0; }

.oss-check-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 10px;
  padding: 0 10px;
}
.oss-check-row .btn-secondary { width: auto; }
.oss-check-status { font-size: 0.78rem; color: var(--muted); }

.order-detail-paid-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 12px;
  border-radius: 8px;
  background: rgba(255, 200, 87, 0.12);
  border: 1px solid var(--accent);
  color: var(--accent);
  font-size: 0.85rem;
  font-weight: 600;
}
.order-unpaid-btn { flex-shrink: 0; width: auto; padding: 5px 10px; font-size: 0.78rem; }

.order-detail-save-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 20px;
  flex-wrap: wrap;
}
.order-detail-save-status { font-size: 0.78rem; color: var(--muted); }
.order-paid-btn { background: #f59e0b; color: #1a1300; }
.order-paid-btn:hover { background: #d98c08; }

.order-detail-danger-zone {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
  display: flex;
}
.order-detail-danger-zone .btn-danger { flex: 1; font-size: 0.82rem; padding: 9px 12px; }

.order-detail-comments-header {
  padding-top: 14px;
  border-top: 1px solid var(--border);
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  margin-bottom: 10px;
}

.order-detail-comments {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-height: 260px;
  overflow-y: auto;
  margin-bottom: 12px;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}

.order-comment {
  padding: 10px 12px;
  border-radius: 8px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  transition: background-color 0.4s ease, border-color 0.4s ease;
}
/* Briefly flashed when arriving via a "you were mentioned" notification
   (see scrollToAndHighlightComment()) — fades back to normal on its own. */
.order-comment-highlight { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }
.order-comment-head { display: flex; justify-content: space-between; align-items: center; gap: 8px; margin-bottom: 4px; }
.order-comment-author { font-size: 0.82rem; font-weight: 600; }
.order-comment-head-right { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.order-comment-date { font-size: 0.72rem; color: var(--muted); }
.order-comment-edited { margin-left: 4px; font-style: italic; }
.order-comment-edit-btn { width: 22px; height: 22px; font-size: 0.78rem; padding: 0; }
.order-comment-text { font-size: 0.85rem; white-space: pre-wrap; word-break: break-word; }
.order-comment-edit-input {
  width: 100%;
  min-height: 60px;
  margin-bottom: 6px;
  padding: 6px 8px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.9);
  color: #111;
  font-size: 0.85rem;
  font-family: inherit;
  resize: vertical;
}
.order-comment-edit-actions { display: flex; justify-content: flex-end; gap: 8px; }
.order-comment-edit-actions button { padding: 5px 12px; font-size: 0.8rem; width: auto; }
.order-comment-attachments { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.order-comment-attachment-image {
  width: 72px;
  height: 72px;
  border-radius: 6px;
  object-fit: cover;
  cursor: pointer;
}
.order-comment-attachment-file {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 10px;
  border-radius: 6px;
  border: none;
  background: rgba(0, 0, 0, 0.15);
  color: inherit;
  text-decoration: none;
  font-size: 0.8rem;
  font-family: inherit;
  cursor: pointer;
}

.order-detail-comment-composer textarea {
  width: 100%;
  padding: 9px 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  font-size: 0.9rem;
  font-family: inherit;
  resize: vertical;
  margin-bottom: 8px;
}
.order-comment-attach-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.order-comment-attach-row > button { flex-shrink: 0; white-space: nowrap; }
/* #order-comment-submit-btn is a .btn-primary, and that base class sets
   width:100% (meant for buttons that are the only/full-width thing in
   their own row elsewhere in the app — see .order-submit-row). Inside
   *this* flex row, width acts as the item's flex-basis, so it was
   demanding 100% of the row's own width on top of what "Attach" already
   takes — overflowing past the row, and past the modal's own edge
   entirely. flex:1 is the correct way to say "fill the remaining space
   next to Attach," not width:100%. */
#order-comment-submit-btn { width: auto; flex: 1; }

/* A standalone block above the Attach/Post row (not squeezed inside it —
   see the chip styles below for why that used to collide) so any number of
   attachments, wrapped across as many lines as they need, never affects the
   button row's own layout at all. */
.order-comment-attach-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.order-comment-attach-summary-active { margin-bottom: 10px; }

.comment-attach-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px 6px 6px;
  border-radius: 10px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  font-size: 0.8rem;
  color: var(--text);
  max-width: 220px;
}
/* An actual thumbnail, not just a filename — a pasted screenshot's own
   auto-generated name ("screenshot-1770300758123.png") says nothing about
   what's actually in it; seeing the image itself is what makes it possible
   to tell two pasted screenshots apart before posting. */
.comment-attach-chip-thumb {
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  border-radius: 6px;
  object-fit: cover;
  background: var(--border);
}
.comment-attach-chip-icon {
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  border-radius: 6px;
  background: var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.2rem;
}
.comment-attach-chip-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.comment-attach-chip-remove {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: none;
  background: rgba(0, 0, 0, 0.25);
  color: inherit;
  font-size: 0.65rem;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.comment-attach-chip-remove:hover { background: var(--accent); color: var(--accent-text); }

.message-search-input {
  width: 100%;
  margin-bottom: 12px;
}
.message-search-status {
  padding: 16px 4px;
  color: var(--muted);
  font-size: 0.85rem;
  text-align: center;
}
.message-search-results {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.message-search-result {
  display: block;
  width: 100%;
  padding: 8px 10px;
  border-radius: 8px;
  border: none;
  background: var(--panel-2);
  color: inherit;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}
.message-search-result:hover { background: var(--border); }
.message-search-result-chat { font-size: 0.82rem; font-weight: 600; }
.message-search-result-body {
  margin-top: 2px;
  font-size: 0.85rem;
  color: var(--muted);
  overflow-wrap: break-word;
}
.message-search-result-body mark {
  background: var(--accent);
  color: var(--accent-text);
  border-radius: 2px;
  padding: 0 1px;
}
.message-search-result-time { margin-top: 3px; font-size: 0.72rem; color: var(--muted); opacity: 0.8; }

/* ---------- Pipeline panel ---------- */
.pipeline-category-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 16px;
}

.pipeline-category-tab {
  background: var(--panel);
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 7px 16px;
  font-size: 0.85rem;
  font-weight: 600;
  cursor: grab;
}
.pipeline-category-tab:hover { color: var(--text); border-color: var(--accent); }
.pipeline-category-tab.active { background: var(--accent); color: var(--accent-text); border-color: var(--accent); }
.pipeline-category-tab.dragging { opacity: 0.4; }

.pipeline-board {
  display: flex;
  gap: 16px;
  flex: 1;
  min-height: 0;
  overflow-x: auto;
  padding-bottom: 8px;
}

.pipeline-column {
  width: 260px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}

.pipeline-column-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  font-weight: 600;
  font-size: 0.9rem;
  flex-shrink: 0;
}

.pipeline-count {
  background: var(--panel-2);
  color: var(--muted);
  font-size: 0.72rem;
  font-weight: 700;
  padding: 1px 8px;
  border-radius: 999px;
}

.pipeline-column-info {
  padding: 8px 14px;
  font-size: 0.76rem;
  color: var(--muted);
  font-style: italic;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.pipeline-column-body {
  flex: 1;
  min-height: 120px;
  overflow-y: auto;
  padding: 10px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.pipeline-column-body.drag-over { background: var(--panel-2); }

.pipeline-card {
  position: relative;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 28px 10px 12px;
  cursor: grab;
  transition: border-color 0.15s ease;
}
.pipeline-card:hover { border-color: var(--accent); }
.pipeline-card.dragging { opacity: 0.4; }
.pipeline-card-name { font-weight: 600; font-size: 0.88rem; }
.pipeline-card-phone { color: var(--muted); font-size: 0.78rem; margin-top: 2px; }
/* How many calendar days this card has sat on its current stage (see
   dashboard.js's daysInCurrentStage()) — same neutral pill as
   .calendar-day-count for a consistent "small count badge" look app-wide. */
.pipeline-card-days {
  display: inline-block;
  margin-top: 4px;
  font-size: 0.68rem;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--panel);
  border: 1px solid var(--border);
  color: var(--muted);
}
/* Drag-to-reorder has no other visible affordance once a card's dropped
   (see renderPipelineBoard()'s drag handlers) — this grip only earns its
   keep on hover, when the grab cursor is already telling the same story,
   rather than cluttering every card at rest. */
.pipeline-card-grip {
  position: absolute;
  top: 50%;
  right: 8px;
  transform: translateY(-50%);
  color: var(--muted);
  font-size: 0.9rem;
  opacity: 0;
  transition: opacity 0.15s ease;
  pointer-events: none;
}
.pipeline-card:hover .pipeline-card-grip { opacity: 1; }
/* Kirim NIB checkbox in Item Detail (order.kirimNib) — a plain manual
   marker, same idea as .pipeline-card-invoiced right below it. Declared
   BEFORE that one deliberately: when a card carries both classes,
   .pipeline-card-invoiced's own background/border-color (same specificity,
   declared later) wins the cascade, so Invoice's red always shows over
   this gold, never the reverse — see renderPipelineBoard()'s own notes on
   why that's the intended priority. */
.pipeline-card-kirim-nib { background: var(--accent-warm); border-color: var(--accent-warm); }
.pipeline-card-kirim-nib .pipeline-card-name,
.pipeline-card-kirim-nib .pipeline-card-phone { color: var(--accent-warm-text); }
.pipeline-card-kirim-nib .pipeline-card-grip { color: rgba(6, 36, 15, 0.7); }
/* The "Invoice" checkbox in Item Detail (order.invoiceFlag) — see
   renderPipelineBoard()'s own notes on why this is a plain manual marker,
   not tied to a step actually named "Invoice". var(--danger), not a fixed
   hex, so this stays the right shade of red in both themes (see style.css's
   :root[data-theme="light"] block, which deepens --danger for contrast on
   a light card background). */
.pipeline-card-invoiced { background: var(--danger); border-color: var(--danger); }
.pipeline-card-invoiced .pipeline-card-name,
.pipeline-card-invoiced .pipeline-card-phone { color: #ffffff; }
.pipeline-card-invoiced .pipeline-card-grip { color: rgba(255, 255, 255, 0.8); }
/* "Revisi" checkbox in Item Detail (order.revisi) — declared last of the
   three manual markers on purpose: when a card carries more than one of
   these classes, whichever is declared last wins the cascade (same
   specificity throughout), so Revisi's green always shows over both
   Invoice's red and Kirim NIB's gold. Fixed black text (not a --text-ish
   token) since #10B981 is light enough in both themes that black stays
   readable either way — no light/dark swap needed the way --danger gets. */
.pipeline-card-revisi { background: #10B981; border-color: #10B981; }
.pipeline-card-revisi .pipeline-card-name,
.pipeline-card-revisi .pipeline-card-phone { color: #000000; }
.pipeline-card-revisi .pipeline-card-grip { color: rgba(0, 0, 0, 0.6); }
/* Flags a card assigned only to the Global User (see renderPipelineBoard())
   — same 10px dot as .todo-invoice-badge, colored with that person's own
   picked color (see getUserColor()) instead of a fixed one. */
.pipeline-card-owner-badge {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  margin-left: 6px;
  vertical-align: middle;
}

/* ---------- To Do panel ---------- */
.todo-show-done-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.85rem;
  color: var(--muted);
  cursor: pointer;
}

.todo-list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-bottom: 8px;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}

.todo-group { margin-bottom: 6px; }

.todo-group-header {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 8px 10px;
  background: none;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  color: var(--text);
  font-family: inherit;
  text-align: left;
}
.todo-group-header:hover { background: var(--panel-2); }
.todo-group-caret { font-size: 0.7rem; color: var(--muted); transition: transform 0.15s ease; }
.todo-group.collapsed .todo-group-caret { transform: rotate(-90deg); }
.todo-group-label { font-weight: 700; font-size: 0.85rem; }
.todo-group-count {
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--muted);
  background: var(--panel-2);
  padding: 1px 8px;
  border-radius: 999px;
}

.todo-group-body {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}
.todo-group.collapsed .todo-group-body { display: none; }

.todo-row {
  display: grid;
  grid-template-columns: 1fr 180px 150px 160px 110px 110px 130px;
  align-items: center;
  gap: 12px;
  padding: 9px 12px;
  background: var(--panel);
  border-bottom: 1px solid var(--border);
  cursor: pointer;
  font-size: 0.85rem;
}
.todo-row:last-child { border-bottom: none; }
.todo-row:hover { background: var(--panel-2); }

.todo-row-title {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.todo-row-comment-count { flex-shrink: 0; font-size: 0.72rem; font-weight: 500; color: var(--muted); }
.todo-row-contact,
.todo-row-marketing,
.todo-row-assignee,
.todo-row-date,
.todo-row-created {
  color: var(--muted);
  font-size: 0.8rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.todo-paid-badge {
  flex-shrink: 0;
  background: #f59e0b;
  color: #1a1300;
  font-size: 0.65rem;
  font-weight: 700;
  padding: 2px 7px;
  border-radius: 999px;
  letter-spacing: 0.03em;
}

/* The "Invoice" checkbox in Item Detail (order.invoiceFlag) — see
   renderTodoBoard()'s own notes on why this is a plain manual marker, not
   tied to a pipeline step actually named "Invoice". */
.todo-invoice-badge {
  flex-shrink: 0;
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #ff6f61;
}

.todo-status-select {
  flex-shrink: 0;
  padding: 6px 8px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  font-size: 0.78rem;
}

/* ---------- Tags panel ---------- */
.tags-board {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

.tag-card {
  width: 260px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  align-self: flex-start;
}

.tag-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
}

.tag-card-assign {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-bottom: 1px solid var(--border);
  font-size: 0.78rem;
  color: var(--muted);
}
.tag-card-assign label { flex-shrink: 0; }
.tag-card-assign select {
  flex: 1;
  min-width: 0;
  margin-bottom: 0;
  padding: 5px 8px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  font-size: 0.78rem;
}

.tag-card-body {
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-height: 220px;
  overflow-y: auto;
}

.tag-contact { font-size: 0.85rem; padding: 4px 0; cursor: pointer; }
.tag-contact:hover { color: var(--accent); text-decoration: underline; }
.tag-card-empty { color: var(--muted); font-size: 0.8rem; }

/* ---------- Template Chat panel ---------- */
.templates-list {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}
.template-card {
  width: 260px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  align-self: flex-start;
}
.template-card-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
}
.template-card-type-badge {
  flex-shrink: 0;
  font-size: 0.72rem;
  padding: 2px 7px;
  border-radius: 999px;
  background: var(--panel-2);
  color: var(--muted);
}
.template-card-name { font-weight: 600; font-size: 0.9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A fixed height (not just a min/max) is what actually makes every card
   the same overall size regardless of type — a text template's preview
   used to just be as tall as its (often short) text, while an image
   template's was a fixed 140px, so a text and an image card sitting next
   to each other in the wrap never matched. Every preview type below now
   fills this same 140px zone instead of sizing to its own content. */
.template-card-preview {
  padding: 10px 12px;
  height: 140px;
  display: flex;
  flex-direction: column;
}
.template-card-text-preview {
  flex: 1;
  min-height: 0;
  font-size: 0.82rem;
  color: var(--muted);
  white-space: pre-wrap;
  overflow-wrap: break-word;
  overflow: hidden;
}
.template-card-image-preview { display: block; width: 100%; height: 100%; object-fit: cover; border-radius: 6px; }
.template-card-file-preview { flex: 1; display: flex; align-items: center; font-size: 0.85rem; color: var(--muted); }
.template-card-actions {
  display: flex;
  gap: 8px;
  padding: 10px 12px;
  border-top: 1px solid var(--border);
}
.template-card-actions button { flex: 1; width: auto; font-size: 0.8rem; padding: 6px 10px; }
.template-file-current { margin-top: 6px; font-size: 0.78rem; color: var(--muted); }
.template-shortcut-row { display: flex; align-items: center; gap: 0; }
.template-shortcut-prefix {
  flex-shrink: 0;
  padding: 9px 0 9px 10px;
  border: 1px solid var(--border);
  border-right: none;
  border-radius: 8px 0 0 8px;
  background: var(--panel-2);
  color: var(--muted);
  font-family: monospace;
}
.template-shortcut-row input {
  flex: 1;
  min-width: 0;
  margin-bottom: 0;
  border-radius: 0 8px 8px 0;
  font-family: monospace;
}
.template-shortcut-hint { margin-top: 4px; font-size: 0.75rem; color: var(--muted); }
.order-detail-deadline-hint { margin-top: 4px; font-size: 0.75rem; color: var(--muted); }
.order-detail-password-access-notice {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  padding: 8px 12px;
  border-radius: 8px;
  background: rgba(255, 111, 97, 0.12);
  border: 1px solid rgba(255, 111, 97, 0.4);
  font-size: 0.82rem;
  color: var(--muted);
}
.order-detail-password-access-notice button { width: auto; flex-shrink: 0; }
.template-card-shortcut { font-size: 0.72rem; color: var(--muted); font-family: monospace; margin-left: auto; flex-shrink: 0; }

.empty-state {
  color: var(--muted);
  padding: 40px;
  text-align: center;
}

/* ---------- Users panel ---------- */
.users-form {
  display: flex;
  gap: 10px;
  align-items: end;
  flex-wrap: wrap;
  margin-bottom: 20px;
  background: var(--panel);
  border: 1px solid var(--border);
  padding: 16px;
  border-radius: 10px;
}
.users-form .field { min-width: 200px; }
.users-form label { margin-bottom: 6px; }
.users-form input, .users-form select {
  margin-bottom: 0;
  padding: 9px 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
}

.contact-name-link {
  background: none;
  border: none;
  padding: 0;
  color: var(--accent);
  font-weight: 600;
  font-size: inherit;
  font-family: inherit;
  cursor: pointer;
  text-align: left;
}
.contact-name-link:hover { text-decoration: underline; }

.database-filters {
  display: flex;
  gap: 10px;
  margin-bottom: 14px;
}
.database-filters input[type="text"] { flex: 1; min-width: 0; margin-bottom: 0; }
.database-filters select { width: 220px; flex-shrink: 0; margin-bottom: 0; }
.database-columns-wrap { position: relative; flex-shrink: 0; }

.todo-filters { display: flex; gap: 10px; margin-bottom: 12px; }
.todo-filters input[type="text"] { flex: 1; min-width: 0; margin-bottom: 0; }
.todo-filters select { width: 200px; flex-shrink: 0; margin-bottom: 0; }

/* ---------- Usage panel (Global User only) ---------- */
.usage-range-row { align-items: center; }
.usage-range-row label { color: var(--muted); font-size: 0.85rem; }
.usage-range-row input[type="date"] { flex: 0 0 auto; width: 160px; margin-bottom: 0; }

.usage-heatmap-wrap {
  display: flex;
  align-items: flex-start;
  gap: 20px;
  margin-bottom: 20px;
}

.usage-heatmap-scroll {
  flex: 1;
  min-width: 0;
  overflow-x: auto;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}

.usage-heatmap {
  border-collapse: separate;
  border-spacing: 4px;
}
.usage-heatmap th {
  color: var(--muted);
  font-weight: 600;
  font-size: 0.76rem;
  padding-bottom: 6px;
  white-space: nowrap;
}
.usage-heatmap-name-header,
.usage-heatmap-name {
  text-align: left;
  padding-right: 10px;
  white-space: nowrap;
  font-weight: 600;
  font-size: 0.85rem;
}
.usage-heatmap-cell {
  min-width: 48px;
  height: 40px;
  border-radius: 6px;
  font-weight: 700;
  font-size: 0.8rem;
  text-align: center;
}

.usage-heatmap-legend {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 6px 4px;
  font-size: 0.72rem;
  color: var(--muted);
}
.usage-heatmap-legend-bar {
  width: 14px;
  height: 140px;
  border-radius: 4px;
  background: linear-gradient(to top, #dbeafe, #1e3a8a);
}
.usage-heatmap-legend-label {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  margin-top: 8px;
  white-space: nowrap;
}

.usage-table-header {
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  margin-bottom: 8px;
}
.database-delete-btn:hover { background: var(--danger); color: #fff; }

.overview-count-btn {
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--accent);
  font-weight: 700;
  font-size: 0.85rem;
  padding: 4px 12px;
  border-radius: 999px;
  cursor: pointer;
  font-family: inherit;
}
.overview-count-btn:hover { border-color: var(--accent); text-decoration: underline; }

/* Same look as the Chat page's order-pane list items (.order-list-item),
   just without the ✏️/✕ action buttons this read-only popup has no use
   for — those reserve 56px of right padding this overrides back down. */
.overview-item { padding-right: 12px; }

.contact-note-cell {
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--muted);
  font-size: 0.85rem;
}

.contact-detail-phone-row { display: flex; gap: 6px; align-items: center; }
.contact-detail-phone-row input { flex: 1; }

.contact-detail-tags {
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-height: 160px;
  overflow-y: auto;
}

.password-change-input {
  width: 130px;
  padding: 6px 8px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  font-size: 0.85rem;
  margin-right: 4px;
}

table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--border); font-size: 0.9rem; }
th { color: var(--muted); font-weight: 600; }

/* Tighter than the generic th/td padding above — the Database table's rows
   are plain one-line values (name, username, a rupiah figure), not
   multi-line content that needs the extra breathing room, so the default
   10px vertical padding just reads as wasted space at this row count. */
#panel-database td, #panel-database th { padding: 5px 12px; }
#panel-contacts td, #panel-contacts th { padding: 3px 12px; line-height: 1.25; }
/* The 3px td padding above barely matters when the row's actual tallest
   content is a full-size Chat/Remove button (10px vertical padding from
   the base button rule) — shrinking those is what actually tightens row
   height here. */
#panel-contacts td .btn-secondary { padding: 3px 10px; font-size: 0.8rem; }
#panel-overview td, #panel-overview th { padding: 5px 12px; }

/* Header labels ("Jenis Badan Usaha" in particular) are long enough to wrap
   onto two lines at typical column widths, which made that header's row
   taller than its single-line siblings — with the default vertical-align,
   the wrapped label's first line then sat visibly higher than the
   vertically-centered single-line ones next to it. Headers shouldn't wrap at
   all here (the column just needs to be wide enough for its own label), so
   nowrap keeps the whole header row one consistent height. */
#panel-database th { white-space: nowrap; vertical-align: middle; }

.sortable-th { cursor: pointer; user-select: none; }
.sortable-th:hover { color: var(--text); }
.sort-indicator { display: inline-block; width: 12px; margin-left: 2px; opacity: 0.8; }

.user-color-picker { display: flex; flex-wrap: wrap; gap: 4px; max-width: 180px; }
.user-color-swatch {
  width: 20px;
  height: 20px;
  padding: 0;
  border-radius: 50%;
  border: 2px solid transparent;
  cursor: pointer;
}
.user-color-swatch.selected { border-color: var(--text); }
.user-color-swatch-none {
  background: var(--panel-2);
  color: var(--muted);
  font-size: 0.6rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

.hidden { display: none !important; }

.context-menu {
  position: fixed;
  min-width: 180px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 6px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
  z-index: 1000;
}

.context-menu-item {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  color: var(--text);
  padding: 8px 10px;
  border-radius: 6px;
  font-size: 0.85rem;
  font-weight: 500;
  cursor: pointer;
}
.context-menu-item:hover { background: var(--panel-2); }

/* ---------- Settings panel (Global User only) ---------- */
.settings-categories {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

.settings-category-card {
  width: 320px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px;
  align-self: flex-start;
}

.settings-category-header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
}
.settings-category-name-input {
  flex: 1;
  margin-bottom: 0;
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  font-weight: 700;
}

.settings-steps-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 12px;
}

.settings-step-row {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
}
.settings-step-row:last-child { border-bottom: none; padding-bottom: 0; }
.settings-step-row-main {
  display: flex;
  align-items: center;
  gap: 6px;
}
.settings-step-index {
  flex-shrink: 0;
  width: 20px;
  text-align: center;
  font-size: 0.78rem;
  color: var(--muted);
  font-weight: 700;
}
.settings-step-label-input {
  flex: 1;
  min-width: 0;
  margin-bottom: 0;
  padding: 7px 9px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  font-size: 0.85rem;
}
.settings-step-info-input {
  margin: 0 0 0 26px;
  padding: 6px 9px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--muted);
  font-size: 0.78rem;
  font-style: italic;
}
.settings-step-row .icon-btn:disabled { opacity: 0.35; cursor: default; }
.settings-step-responsible-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 2px 0 0 26px;
}
.settings-step-responsible-label { font-size: 0.78rem; color: var(--muted); flex-shrink: 0; }
.settings-step-responsible-row .assignee-picker-wrap { flex: 1; min-width: 0; }
.settings-step-responsible-row .assignee-picker-btn { font-size: 0.8rem; padding: 6px 9px; }

.settings-step-deadline-row { margin: 6px 0 0 26px; }
.settings-step-deadline-toggle {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.78rem;
  color: var(--muted);
  cursor: pointer;
}
.settings-step-deadline-toggle input { margin: 0; }
.settings-step-deadline-config {
  display: flex;
  gap: 6px;
  margin-top: 6px;
}
.settings-step-deadline-config select {
  flex: 1;
  min-width: 0;
  margin-bottom: 0;
  padding: 6px 9px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  font-size: 0.8rem;
}
.settings-step-deadline-config input[type="number"] {
  width: 70px;
  flex-shrink: 0;
  margin-bottom: 0;
  padding: 6px 9px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  font-size: 0.8rem;
}

.settings-category-footer {
  display: flex;
  align-items: center;
  gap: 10px;
}
.settings-category-footer .btn-primary { width: auto; }
.settings-save-status { flex: 1; font-size: 0.78rem; color: var(--muted); text-align: right; }

/* ---------- Notifications panel ---------- */
.notification-category-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 12px;
}
.notification-category-tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--panel);
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 7px 16px;
  font-size: 0.85rem;
  font-weight: 600;
}
.notification-category-tab:hover { color: var(--text); border-color: var(--accent); }
.notification-category-tab[draggable="true"] { cursor: grab; }
.notification-category-tab.dragging { opacity: 0.4; }
.notification-category-tab.active { background: var(--accent); color: var(--accent-text); border-color: var(--accent); }
.notification-category-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--danger);
  color: white;
  font-size: 0.72rem;
  font-weight: 700;
}
.notification-category-tab.active .notification-category-count { background: #06240f; color: white; }

.notifications-list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.notification-item {
  position: relative;
  padding: 12px 14px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--panel);
  cursor: pointer;
  transition: border-color 0.15s ease;
}
.notification-item:hover { border-color: var(--accent); }
.notification-item.unread { background: var(--panel-2); border-left: 3px solid var(--accent-warm); }
.notification-approve-btn { display: block; margin-top: 8px; padding: 6px 12px; font-size: 0.8rem; }
.notification-main {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}
.notification-text { flex: 1; min-width: 0; }
.notification-read-btn {
  flex-shrink: 0;
  padding: 12px 26px;
  border: none;
  border-radius: 8px;
  background: #ff6f61;
  color: white;
  font-size: 1rem;
  font-weight: 700;
  cursor: pointer;
}
.notification-read-btn:hover { opacity: 0.85; }
/* Shared by the Notifications list and any chat-style thread (Team Chat —
   see teamChatBubbleHtml()) that groups its items by calendar day. */
.date-divider {
  align-self: center;
  margin: 6px 0;
  padding: 4px 14px;
  border-radius: 999px;
  background: var(--panel-2);
  color: var(--muted);
  font-size: 0.75rem;
  font-weight: 700;
}
.notification-title { font-weight: 700; font-size: 0.9rem; }
.notification-message { margin-top: 4px; font-size: 0.85rem; color: var(--muted); }
.notification-time { margin-top: 6px; font-size: 0.75rem; color: var(--muted); }

/* ---------- Profile panel ---------- */
.profile-top-row {
  display: flex;
  gap: 24px;
  align-items: flex-start;
  margin-bottom: 24px;
}
.profile-avatar-block {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  width: 140px;
}
.profile-avatar-hint { font-size: 0.72rem; color: var(--muted); text-align: center; }
.profile-avatar-preview {
  width: 120px;
  height: 120px;
  border-radius: 50%;
  background: var(--panel-2) center / cover no-repeat;
  border: 2px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2.2rem;
  font-weight: 700;
  color: var(--muted);
}
.profile-details-form { flex: 1; min-width: 0; margin: 0; }
.profile-password-form { max-width: 640px; margin-bottom: 24px; }

.profile-theme-options {
  display: flex;
  gap: 12px;
  margin-bottom: 24px;
}
.profile-theme-option {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 20px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--panel);
  cursor: pointer;
  font-weight: 600;
  transition: border-color 0.15s ease, background-color 0.15s ease;
}
.profile-theme-option:hover { border-color: var(--accent); }
.profile-theme-option input { margin: 0; }
/* :has() support is universal in every browser this app already targets
   (Chrome/Edge/Firefox/Safari all shipped it well before this was
   written) — simplest way to style the label by its own radio's checked
   state without extra JS just to toggle a class. */
.profile-theme-option:has(input:checked) {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, var(--panel));
}

/* ---------- Custom date picker (see dashboard.js's setupCustomDateField())
   ---------- A native <input type="date">'s own popup calendar is raw
   browser chrome — only color-scheme (dark/light) is stylable, nothing
   else, so it can never actually match this app's own design. Used in
   place of it wherever that matters (currently just the Visit page's Date
   assigned field) — a plain readonly text input showing a formatted date,
   paired with this popup instead of the native one. Same floating-panel
   look as .tag-picker (background/border/radius/shadow), appended to
   <body> and positioned via getBoundingClientRect() rather than an
   absolutely-positioned child, so it's never clipped by a scrolling
   ancestor panel. */
.date-picker-trigger { cursor: pointer; background: var(--panel-2); }
.date-picker-popup {
  width: 240px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
}
.date-picker-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}
.date-picker-month-label { font-weight: 700; font-size: 0.88rem; }
.date-picker-nav {
  width: 26px;
  height: 26px;
  padding: 0;
  border-radius: 6px;
  background: var(--panel-2);
  color: var(--text);
  font-size: 1rem;
  line-height: 1;
}
.date-picker-nav:hover { background: var(--accent); color: var(--accent-text); }
.date-picker-weekdays,
.date-picker-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
}
.date-picker-weekdays {
  margin-bottom: 4px;
  font-size: 0.68rem;
  font-weight: 700;
  color: var(--muted);
  text-align: center;
}
.date-picker-cell {
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--text);
  font-weight: 500;
  font-size: 0.82rem;
}
.date-picker-cell:hover { background: var(--panel-2); }
.date-picker-cell-empty { visibility: hidden; cursor: default; }
.date-picker-cell.is-today { color: var(--accent); font-weight: 700; }
.date-picker-cell.is-selected { background: var(--accent); color: var(--accent-text); }
.date-picker-cell.is-selected:hover { background: var(--accent-2); }
.date-picker-today-btn {
  width: 100%;
  margin-top: 8px;
  padding: 7px;
  border-radius: 8px;
  background: var(--panel-2);
  color: var(--text);
  font-size: 0.8rem;
  font-weight: 600;
}
.date-picker-today-btn:hover { background: var(--accent); color: var(--accent-text); }

/* Quick "save name" popup (see dashboard.js's openSaveNamePrompt()) — reuses
   .date-picker-popup's own floating-panel look (width overridden, it needs
   more room for a name than a calendar's day grid does). */
.save-name-popup { width: 260px; }
.save-name-popup-label { font-size: 0.78rem; color: var(--muted); margin-bottom: 8px; }
.save-name-popup-input { width: 100%; margin-bottom: 10px; }
.save-name-popup-actions { display: flex; gap: 8px; }
.save-name-popup-actions button { flex: 1; width: auto; font-size: 0.82rem; padding: 7px 10px; }
.save-name-popup .error-text { margin-top: 6px; margin-bottom: 0; }

/* ---------- Visit questions (see dashboard.js's renderVisitQuestions()) ----------
   Whoever set up the visit writes the question text; the person it's
   assigned to answers it (see canAnswerVisitQuestions() — the answer
   textarea is read-only for anyone else, styled via .visit-question-answer
   :disabled below so that's visible at a glance, not just enforced
   silently). */
.visit-questions-panel { margin-top: 16px; }
.visit-questions-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 4px;
}
.visit-questions-hint { margin: 0 0 10px; font-size: 0.8rem; color: var(--muted); }
.visit-questions-list { display: flex; flex-direction: column; gap: 10px; }
.visit-question-row {
  padding: 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.15);
}
.visit-question-text-row { display: flex; gap: 8px; align-items: center; margin-bottom: 8px; }
.visit-question-text { flex: 1; min-width: 0; margin-bottom: 0; font-weight: 600; }
.visit-question-answer {
  width: 100%;
  padding: 9px 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  font-size: 0.88rem;
  font-family: inherit;
  resize: vertical;
}
.visit-question-answer:disabled { color: var(--muted); cursor: not-allowed; }
.visit-questions-empty { font-size: 0.85rem; color: var(--muted); }

/* A file attached to Bukti Kunjungan, a question, or its answer — same
   small-pill idea as .tag-pill, just clickable (opens the file) and
   removable. Used both for the visit-level proof row and inside each
   question row below it. */
.visit-attachment-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.visit-attachment-row .btn-secondary { width: auto; flex-shrink: 0; font-size: 0.8rem; padding: 7px 12px; }
.visit-attachment-chip-slot:empty { display: none; }
.visit-attachment-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 6px 4px 10px;
  border-radius: 999px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  font-size: 0.78rem;
  color: var(--text);
  text-decoration: none;
  max-width: 220px;
}
.visit-attachment-chip:hover { border-color: var(--accent); }
.visit-attachment-chip-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.visit-attachment-chip-remove {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: none;
  background: var(--border);
  color: var(--text);
  font-size: 0.6rem;
  line-height: 1;
  padding: 0;
}
.visit-attachment-chip-remove:hover { background: var(--danger); color: #ffffff; }

.visit-question-attachments { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }
.visit-question-attachment-slot { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.visit-question-attachment-label { flex-shrink: 0; font-size: 0.75rem; color: var(--muted); }
.visit-attachment-upload-btn { width: auto; flex-shrink: 0; font-size: 0.75rem; padding: 5px 10px; }

/* Same row as #visit-detail-save-btn (a .btn-primary, width:100% by
   default) — matching its width here rather than #visit-detail-delete-btn
   staying content-sized keeps the two buttons visually equal weight. */
#visit-detail-delete-btn { width: 100%; }

/* ---------- Calendar panel ---------- */
.calendar-nav { display: flex; align-items: center; gap: 12px; }
.calendar-month-label { font-weight: 700; min-width: 140px; text-align: center; }

.calendar-view-toggle {
  display: flex;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 2px;
}
.calendar-view-btn {
  padding: 5px 14px;
  border-radius: 999px;
  background: none;
  color: var(--muted);
  font-size: 0.8rem;
  font-weight: 600;
}
.calendar-view-btn.active { background: var(--accent); color: var(--accent-text); }

.calendar-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 12px;
}
.calendar-legend-item {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.78rem;
  color: var(--muted);
}
.calendar-legend-swatch {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  flex-shrink: 0;
}

.calendar-grid {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  grid-auto-rows: minmax(90px, 1fr);
  gap: 6px;
  overflow-y: auto;
}
.calendar-weekday {
  text-align: center;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--muted);
  padding-bottom: 4px;
}
.calendar-day {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.calendar-day-empty { border: none; background: none; }
.calendar-day-today {
  background: rgba(255, 200, 87, 0.1);
  border-color: var(--accent);
  border-width: 2px;
  padding: 5px;
}
.calendar-day-number { font-size: 0.8rem; font-weight: 700; color: var(--text); display: flex; align-items: center; gap: 6px; }
.calendar-day-today .calendar-day-number { color: var(--accent); }
.calendar-today-badge {
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--accent-warm);
  color: var(--accent-warm-text);
}
/* How many tasks are due that day — same pill shape as .calendar-today-badge
   but neutral-colored so it doesn't compete with it (both can show at once
   on today's cell). Dropped into the existing flex header row in both the
   Month (.calendar-day-number) and Week (.calendar-week-column-date) views. */
.calendar-day-count {
  font-size: 0.62rem;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--muted);
}
.calendar-day-tasks {
  display: flex;
  flex-direction: column;
  gap: 3px;
  overflow-y: auto;
  min-height: 0;
}
.calendar-task-title {
  font-size: 0.72rem;
  font-weight: 700;
  padding: 3px 7px;
  border-radius: 5px;
  background: var(--accent);
  color: var(--accent-text);
  cursor: pointer;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.calendar-task-title:hover { background: var(--accent-2); }
.calendar-task-title.dragging { opacity: 0.4; }
.calendar-task-title-paid { background: #ffffff; color: #000000; }
.calendar-task-title-paid:hover { background: #f0f0f0; }
.calendar-task-title-invoiced { background: #ef4444; color: #ffffff; }
.calendar-task-title-invoiced:hover { background: #dc2626; }
.calendar-day.drag-over, .calendar-week-column.drag-over { background: var(--panel-2); }

.calendar-grid-week {
  grid-template-columns: repeat(7, 1fr);
  grid-auto-rows: 1fr;
}
.calendar-week-column {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 0;
  overflow: hidden;
}
.calendar-week-column-header {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border);
}
.calendar-week-column-weekday {
  font-size: 0.72rem;
  font-weight: 700;
  color: var(--muted);
  letter-spacing: 0.04em;
}
.calendar-week-column-date { font-size: 0.9rem; font-weight: 700; display: flex; align-items: center; gap: 6px; }
.calendar-day-today .calendar-week-column-date { color: var(--accent); }
.calendar-week-column-tasks {
  display: flex;
  flex-direction: column;
  gap: 5px;
  overflow-y: auto;
  min-height: 0;
}
.calendar-week-empty { color: var(--muted); font-size: 0.78rem; text-align: center; padding: 10px 0; }

/* ---------- Daily Report panel ---------- */
.daily-report-form {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px;
  margin-bottom: 16px;
}
.daily-report-form textarea {
  width: 100%;
  padding: 10px 12px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  font-size: 0.9rem;
  font-family: inherit;
  resize: vertical;
  margin-bottom: 10px;
}
.daily-report-form-row { display: flex; align-items: center; justify-content: flex-end; gap: 12px; }
.daily-report-form-row .btn-primary { width: auto; }
.daily-report-save-status { font-size: 0.78rem; color: var(--muted); }

.daily-report-feed {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.daily-report-item { display: flex; gap: 12px; }
.daily-report-avatar { font-weight: 700; }
.daily-report-body {
  flex: 1;
  min-width: 0;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 14px;
}
.daily-report-header { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.daily-report-name { font-weight: 700; font-size: 0.9rem; }
.daily-report-time { font-size: 0.75rem; color: var(--muted); flex-shrink: 0; }
.daily-report-text { margin-top: 6px; font-size: 0.88rem; white-space: pre-wrap; }
.daily-report-edited { display: inline-block; margin-top: 6px; font-size: 0.72rem; color: var(--muted); font-style: italic; }

/* ---------- Holiday panel (Global User only) ---------- */
.holiday-attendance-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 14px;
}
.holiday-attendance-day {
  display: flex;
  align-items: center;
  gap: 6px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px 10px;
  font-size: 0.8rem;
}
.holiday-attendance-day-label { color: var(--muted); }
.holiday-attendance-day-count { font-weight: 700; }

.holiday-table {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.holiday-row {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 16px;
}
.holiday-row-name { min-width: 160px; flex-shrink: 0; }
.holiday-row-name-main {
  display: inline-block;
  font-weight: 700;
  font-size: 0.9rem;
  padding: 2px 8px;
  border-radius: 6px;
}
.holiday-row-email { font-size: 0.75rem; color: var(--muted); margin-top: 3px; }
.holiday-row-days {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  flex: 1;
}
.holiday-day-checkbox {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 0.82rem;
  color: var(--text);
  cursor: pointer;
}
.holiday-day-checkbox input { margin: 0; }
.holiday-save-btn { flex-shrink: 0; width: auto; padding: 7px 14px; font-size: 0.82rem; }
.holiday-save-status { flex-shrink: 0; font-size: 0.75rem; color: var(--muted); min-width: 80px; }

/* ---------- Toast (see dashboard.js's showToast()) ---------- */
.toast-container {
  position: fixed;
  left: 50%;
  bottom: 28px;
  transform: translateX(-50%);
  z-index: 50;
}
.toast {
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 14px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
  animation: toast-in 0.15s ease;
}
@keyframes toast-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}
.toast-message { font-size: 0.85rem; color: var(--text); white-space: nowrap; }
.toast-action-btn {
  flex-shrink: 0;
  background: none;
  border: none;
  padding: 0;
  color: var(--accent);
  font-weight: 700;
  font-size: 0.85rem;
  cursor: pointer;
}
.toast-action-btn:hover { text-decoration: underline; }
.toast-close-btn {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--muted);
  font-size: 0.75rem;
  cursor: pointer;
}
.toast-close-btn:hover { background: var(--border); color: var(--text); }
