/* Backoffice — page-specific styles. Self-contained (doesn't reference
   v2/'s partner-info.css or mfd-tools.css, since this app can be
   deployed at a different path/host) but uses the same tokens/base/
   components as the rest of the site for a consistent look. */

/* — page layout: slim top bar (brand/search/logout) + left sidebar
   accordion nav + main content. Sidebar sections render from
   getModuleRegistry() grouped by category, plus the hardcoded
   Administration / Subscriptions & Billing / Reports & System / Account
   sections — see inc/layout.php. One <details> per section gives
   click-to-toggle with no JS; the inline script in layout.php enforces
   "only one section open at a time" and remembers the last-opened
   section per browser via localStorage (bo_nav_open_section). — */
/* Deliberately wider than the site-wide --max-width (1180px, tuned for
   marketing-page reading width): this is a data-dense admin app with a
   240px sidebar eating into that budget, so tables/grids were being
   squeezed on large monitors. 1800px keeps generous margins up to
   ~1920px screens while still capping line length on ultrawide displays.
   That 1800px cap/centering used to live on .bo-layout itself (the
   whole sidebar+main row) — on anything wider than ~1800px that put
   empty gutters on BOTH sides of the row, visually detaching the
   sidebar from the real left edge of the screen instead of docking it
   there (confirmed: at 2560px wide, the sidebar rendered as a narrow
   floating box roughly centered on the page). The cap now applies to
   .bo-main alone, so the sidebar always spans the true left edge full-
   height, and only the CONTENT area gets centered within whatever
   space remains after it. */
.bo-layout { display: flex; align-items: flex-start; width: 100%; }

.bo-sidebar {
  flex: 0 0 240px;
  width: 240px;
  position: sticky;
  top: 0;
  align-self: flex-start;
  max-height: 100vh;
  overflow-y: auto;
  padding: 20px 12px 40px;
  border-right: 1px solid var(--color-divider);
  background: var(--color-card-bg);
  transition: width 0.18s ease, padding 0.18s ease, border-color 0.18s ease;
  /* Always-visible, theme-aware scrollbar — the default thin/invisible
     browser scrollbar gave no hint there were more sections below the
     fold (worse on mobile, where nothing shows at all until you touch
     it), which is exactly what made "Account" so easy to miss once a
     category above it was expanded. Firefox via scrollbar-width/-color;
     Chrome/Edge/Safari via the ::-webkit-scrollbar rules below. */
  scrollbar-width: thin;
  scrollbar-color: var(--color-accent) transparent;
}
.bo-sidebar::-webkit-scrollbar { width: 8px; }
.bo-sidebar::-webkit-scrollbar-track { background: transparent; }
.bo-sidebar::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--color-accent) 55%, transparent);
  border-radius: 4px;
}
.bo-sidebar::-webkit-scrollbar-thumb:hover { background: var(--color-accent); }
/* Desktop "closable" sidebar — collapses to zero width instead of the
   off-canvas overlay used below 900px. Content isn't unmounted (so
   toggling back open doesn't need a re-render), just clipped and hidden
   from assistive tech while collapsed. */
.bo-sidebar--collapsed {
  flex-basis: 0;
  width: 0;
  padding-left: 0;
  padding-right: 0;
  border-right-color: transparent;
  overflow: hidden;
}
.bo-sidebar--collapsed > * { opacity: 0; pointer-events: none; }
.bo-sidebar__link,
.bo-sidebar__group summary {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: 10px;
  color: var(--color-text) !important;
  cursor: pointer;
  list-style: none;
  user-select: none;
  font-size: 14px;
  border-left: 3px solid transparent;
}
.bo-sidebar__group summary::-webkit-details-marker { display: none; }
.bo-sidebar__link:hover,
.bo-sidebar__group summary:hover { background: var(--color-accent-100); text-decoration: none; }
.bo-sidebar__group[open] > summary { background: var(--color-accent-100); font-weight: 600; }
.bo-sidebar__link.is-active {
  background: var(--color-accent-100);
  color: var(--color-accent-ink) !important;
  font-weight: 600;
  border-left-color: var(--color-accent);
}

.bo-sidebar__icon {
  flex: 0 0 24px;
  width: 24px;
  height: 24px;
  border-radius: 8px;
  background: var(--color-accent-100);
  color: var(--color-accent-ink);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 700;
}
.bo-sidebar__label { flex: 1; }

.bo-sidebar__group summary::after {
  content: "";
  width: 6px;
  height: 6px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
  transition: transform 0.15s ease;
  margin-right: 2px;
}
.bo-sidebar__group[open] summary::after { transform: rotate(-135deg); }

.bo-sidebar__menu { display: flex; flex-direction: column; gap: 2px; padding: 2px 0 6px 30px; }
.bo-sidebar__menu a {
  color: var(--color-text) !important;
  font-size: 13.5px;
  padding: 7px 10px;
  border-radius: 10px;
  border-left: 3px solid transparent;
}
.bo-sidebar__menu a:hover { background: var(--color-accent-100); color: var(--color-accent-ink) !important; text-decoration: none; }
.bo-sidebar__menu a.is-active {
  background: var(--color-accent-100);
  color: var(--color-accent-ink) !important;
  font-weight: 600;
  border-left-color: var(--color-accent);
}

.bo-sidebar__backdrop { display: none; }

.bo-sidebar-toggle {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  width: 32px;
  height: 32px;
  background: transparent;
  border: none;
  cursor: pointer;
  padding: 0;
  flex: 0 0 auto;
}
.bo-sidebar-toggle span { display: block; width: 100%; height: 2px; background: var(--color-text); }

/* Mobile-only close control pinned inside the sidebar panel itself —
   shown via the media query below; hidden here by default since the
   desktop sidebar is inline (not an overlay) and never needs an
   explicit close. */
.bo-sidebar-close { display: none; }

/* Mobile-only "back" button, next to the hamburger — the sidebar covers
   navigation on desktop, but on mobile it's off-canvas (a deliberate
   tap to open), so there was no quick way back to the previous screen
   without the browser's own chrome. Hidden on desktop since the always-
   visible sidebar already serves that purpose there. */
.bo-back-btn {
  display: none;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  background: transparent;
  border: none;
  color: var(--color-text);
  cursor: pointer;
  padding: 0;
  flex: 0 0 auto;
}
@media (max-width: 900px) {
  .bo-back-btn { display: flex; }
}

.bo-main { flex: 1 1 auto; min-width: 0; max-width: 1800px; margin: 0 auto; padding: 24px var(--pad-inline) 60px; }

/* — sidebar/header-icon AJAX navigation (see the script at the bottom of
   renderFooter(), inc/layout.php) — a brief dim+disable on the content
   area only, while header/footer/sidebar stay fully interactive. — */
body.bo-ajax-loading main.bo-main { opacity: 0.45; pointer-events: none; transition: opacity 0.1s ease 0.08s; }

/* Header bar and footer inner width standardized to match the body's
   content width (.bo-layout, 1800px) instead of the site-wide
   --max-width (1180px, tuned for the narrower marketing pages) — see
   components.css. Backoffice-only override; the marketing site is
   untouched since it never loads this stylesheet. */
.site-header__bar,
.site-footer__inner { max-width: 1800px; }

@media (max-width: 900px) {
  .bo-layout { display: block; }
  .bo-sidebar {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    /* A real, pre-existing bug found while chasing something else: with
       height left auto, top:0/bottom:0 alone did NOT clamp this element
       to the viewport (confirmed directly: clientHeight grew to match
       scrollHeight, i.e. no scroll was ever possible) — it silently grew
       past the screen instead, hiding whatever didn't fit with no way to
       reach it. Only reproduces once total content exceeds one screen
       (e.g. any category expanded), so short menus never revealed it.
       An explicit height is what actually makes overflow-y:auto do
       anything; 100dvh (falls back to 100vh where unsupported) accounts
       for a mobile browser's own address-bar chrome showing/hiding. */
    height: 100vh;
    height: 100dvh;
    width: 260px;
    max-height: none;
    transform: translateX(-100%);
    transition: transform 0.2s ease;
    z-index: 200;
    box-shadow: 0 0 24px rgba(0, 0, 0, 0.2);
  }
  .bo-sidebar--open { transform: translateX(0); }
  .bo-sidebar__backdrop--visible {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.4);
    z-index: 150;
  }
  .bo-main { padding: 20px var(--pad-inline) 48px; }
  /* The open sidebar deliberately covers the header (full-height overlay,
     not a "drawer under the header") — two earlier attempts that instead
     tried to keep the header visible above it (raising the header's own
     z-index, then lowering the sidebar's) both missed the actual intent:
     the header staying visible just ate screen space and read as its own
     overlap bug. Real fix: a dedicated close button INSIDE the sidebar
     itself, pinned to the top of its own scroll area (not the page's),
     so it's reachable no matter how far the menu list is scrolled —
     completely independent of the header's hamburger button underneath,
     which is exactly what caused the original bug (tapping that same
     spot again landed on whatever sidebar link rendered there instead of
     closing the menu). */
  .bo-sidebar-close {
    display: flex; align-items: center; justify-content: space-between;
    position: sticky; top: 0; z-index: 5; margin: -20px -12px 12px;
    padding: 14px 16px; background: var(--color-card-bg);
    border-bottom: 1px solid var(--color-divider);
    font-size: 13px; font-weight: 600; color: var(--color-text);
    border-left: none; border-right: none; border-top: none;
    cursor: pointer; width: calc(100% + 24px);
  }
  .bo-sidebar-close svg { flex: 0 0 auto; }
}

/* — header nav search form — plain <form><input></form>, reset out of
   .site-nav's uppercase/letter-spacing/nav-link styling so it reads as
   a normal search box, not a nav link. — */
.bo-nav__search { margin: 0; display: inline-flex; }
.bo-nav__search input[type="search"] {
  text-transform: none;
  letter-spacing: normal;
  font-family: var(--font-body);
  font-size: 13px;
  padding: 8px 14px 8px 34px;
  border: 1px solid var(--color-divider);
  border-radius: 9999px;
  background: var(--page-bg) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%235f6479' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.35-4.35'/%3E%3C/svg%3E") no-repeat 12px center;
  color: var(--color-text);
  width: 220px;
}
.bo-nav__search input[type="search"]::placeholder { color: var(--color-muted); }
.bo-nav__search input[type="search"]:focus {
  outline: none;
  border-color: var(--color-accent);
  background-color: var(--color-card-bg);
}
.bo-nav__search { position: relative; }
.bo-nav__search__results {
  display: none;
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  width: max(280px, 100%);
  max-height: 360px;
  overflow-y: auto;
  background: var(--color-card-bg);
  color: var(--color-text);
  border-radius: 4px;
  box-shadow: 0 8px 24px rgba(0,0,0,.25);
  z-index: 200;
}
.bo-nav__search__results.is-open { display: block; }
.bo-nav__search__group { padding: 6px 12px 2px; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--color-muted, #667); }
.bo-nav__search__item {
  display: block;
  width: 100%;
  text-align: left;
  padding: 8px 12px;
  border: none;
  background: none;
  cursor: pointer;
  font-size: 13.5px;
  color: var(--color-text);
}
.bo-nav__search__item .bo-nav__search__snippet { display: block; font-size: 12px; color: var(--color-muted, #667); margin-top: 2px; }
/* Fixed light lavender regardless of theme — text color must be fixed
   too, not the ambient --color-text token (near-white in dark mode,
   unreadable against this light background). Same class of bug as the
   dashboard's flagship login-summary tiles. */
.bo-nav__search__item:hover, .bo-nav__search__item.is-active { background: #eef2ff; color: #1b2140; }
.bo-nav__search__item:hover .bo-nav__search__snippet, .bo-nav__search__item.is-active .bo-nav__search__snippet { color: #5a6172; }
.bo-nav__search__empty, .bo-nav__search__hint { padding: 10px 12px; font-size: 13px; color: var(--color-muted, #667); }

/* — login / setup pages — */
.bo-center-page { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 20px; }
.bo-login-card { width: min(420px, 100%); padding: 32px; background: var(--color-card-bg); }
.bo-login-title { font-size: 24px; margin: 0 0 4px; }
.bo-login-sub { font-size: 14px; color: color-mix(in srgb, var(--color-text) 70.2%, transparent); margin: 0 0 20px; }

.bo-form { display: flex; flex-direction: column; gap: 16px; }
.bo-form .field label { display: block; font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: color-mix(in srgb, var(--color-text) 60%, transparent); margin-bottom: 6px; font-weight: 600; }

/* .bo-form's gap only spaces its DIRECT children — a .field wrapped one
   level deeper (e.g. a JS show/hide toggle wrapper like account.php's
   #passwordFields, or any conditionally-revealed field group) gets zero
   gap from that flex layout and visually collides with whatever came
   before it. This gives every non-direct-child .field its own spacing,
   while explicitly zeroing it back out for the normal direct-child case
   so existing forms keep their current spacing unchanged. */
.bo-form .field { margin-top: 16px; }
.bo-form > .field { margin-top: 0; }
.bo-form--2col .field { margin-top: 0; }

/* Two-column layout for long forms (e.g. amc-edit.php's ~35 fields) —
   halves the scroll height versus one field per row. h3 section headers,
   full-width elements (textareas, file inputs), and the submit button
   span both columns via .field--full / direct-child selectors. */
.bo-form--2col { display: grid; grid-template-columns: 1fr 1fr; gap: 16px 24px; align-items: start; }
.bo-form--2col > h3 { grid-column: 1 / -1; margin: 8px 0 -4px; }
.bo-form--2col > h3:first-child { margin-top: 0; }
.bo-form--2col > .field--full,
.bo-form--2col > button { grid-column: 1 / -1; }
@media (max-width: 700px) {
  .bo-form--2col { grid-template-columns: 1fr; }
}

/* adv-finplanner.php's client-details/child/goal rows and results grid
   — same 2-column-that-never-collapsed bug as .bo-form--2col had before
   its own breakpoint above, just via an unresponsive inline style
   (including two JS-templated rows) instead of a class. Confirmed
   overflowing ~36px on a 390px phone. */
.fp-2col { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 14px; }
.fp-2col-tight { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 16px; }
@media (max-width: 480px) {
  .fp-2col, .fp-2col-tight { grid-template-columns: 1fr; }
}

/* Calculators (calculators.php, npscalc.php) — form/result/installments
   on the left, chart on the right, instead of everything stacked in one
   long column. Targets the panes' existing direct children by type/class
   rather than requiring new wrapper markup around all ~22 calculators.
   Inline max-width attributes on individual elements predate this and
   are overridden here since they'd otherwise out-specificity the grid. */
.calc-pane {
  display: grid;
  grid-template-columns: minmax(280px, 420px) minmax(260px, 1fr);
  gap: 4px 32px;
  align-items: start;
}
/* .calc-pane[hidden] out-specificities the bare .calc-pane rule above
   (0,0,2,0 vs 0,0,1,0) so the [hidden] attribute actually hides the
   pane — without this, every calculator's `display: grid` beats the
   browser's UA-stylesheet `[hidden] { display: none }` on the tie, and
   all ~22 panes render stacked on top of each other regardless of
   which nav tab is clicked. */
.calc-pane[hidden] {
  display: none;
}
.calc-pane > h3 { grid-column: 1 / -1; margin-top: 0; }
.calc-pane > .bo-form { grid-column: 1; max-width: none !important; }
/* Calculators run 4-14 fields per pane, so the app-wide .input sizing
   (designed for shorter, less repetitive forms elsewhere) makes these
   feel oversized and pushes the chart column further down before it's
   visible. Scoped here only — every other form in the app (Settings,
   GST, user management, etc.) keeps the standard sizing. */
.calc-pane .bo-form { gap: 10px; }
.calc-pane .bo-form .field label { margin-bottom: 3px; }
.calc-pane .bo-form .input { padding: 6px 10px; font-size: 13.5px; }
.calc-pane > .calc-result { grid-column: 1; }
.calc-pane > details.calc-installments { grid-column: 1; }
.calc-pane > canvas {
  grid-column: 2;
  grid-row: 2 / span 3;
  max-width: 100% !important;
  width: 100% !important;
  align-self: start;
  position: sticky;
  top: 88px;
}
.calc-pane > .calc-actions { grid-column: 1 / -1; }
@media (max-width: 900px) {
  .calc-pane { grid-template-columns: 1fr; }
  .calc-pane > canvas { grid-column: 1; grid-row: auto; position: static; }
}

/* Collapsible installment/amortization table — collapsed by default so
   a 20-30 row projection doesn't dominate the page; the chart already
   shows the trend at a glance. */
.calc-installments { margin-top: 12px; }
.calc-installments summary {
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  color: var(--color-accent-700);
  padding: 6px 0;
  list-style: none;
}
.calc-installments summary::-webkit-details-marker { display: none; }
.calc-installments summary::before { content: "▸ "; display: inline-block; transition: transform 0.15s ease; }
.calc-installments[open] summary::before { transform: rotate(90deg); }
.calc-installments .table-scroll { overflow-x: auto; margin-top: 8px; }

/* Native <dialog> (edit modals: user-subscriptions.php, social-accounts.php,
   feedback-management.php, etc.) — no browser UA stylesheet constrains a
   dialog's height, so a form with several fields (date pickers, several
   labeled inputs) easily exceeds the viewport with nothing to fix it:
   the box just overflows top/bottom uncontrolled, with no scrollbar and
   often no visible backdrop dimming either. Pin it to the viewport
   center explicitly and cap its height so it always scrolls internally
   instead. Each page's own inline max-width/width/padding/border still
   apply on top of this (more specific, same properties untouched here). */
dialog {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  margin: 0;
  max-height: calc(100vh - 48px);
  overflow-y: auto;
  /* overflow-y:auto alone computes overflow-x to auto too (CSS spec) —
     the 1px-outside-the-box .blueprint corner brackets (see their own
     comment further down) are just enough overflow to trigger a
     spurious horizontal scrollbar on every dialog in the app. Never
     needed: nothing inside a dialog is intentionally wider than it. */
  overflow-x: hidden;
  border-radius: 4px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.28);
  /* The .blueprint corner brackets' 1px negative-offset poke (see
     components.css — top:-1px/left:-1px etc., by design, to visually
     overlap the border) also registers as VERTICAL overflow content for
     a clipping container, the same way it registered as horizontal
     overflow above — triggering a permanent, spurious scrollbar even on
     dialogs whose real content easily fits. Clipped at the wrapper
     level below instead of loosening overflow-y here, which still needs
     to scroll for genuinely tall dialog content. */
  /* The browser's native <dialog> background/text color (white/black)
     never picked up this app's dark-theme tokens — tokens.css's own
     comment names "dialogs" as in scope for --color-card-bg/--color-text,
     but nothing actually applied them here, so every dialog stayed
     white-on-white-text in dark mode for content (like
     dashboard.php's login-summary tiles) that explicitly colors itself
     with --color-text. Fixes every <dialog> in the app at once. */
  background: var(--color-card-bg, #ffffff);
  color: var(--color-text, #1b2140);
}
dialog::backdrop {
  background: rgba(10, 14, 20, 0.6);
}
/* Clips the corner brackets' 1px poke so it never counts as scrollable
   overflow (see the dialog{} comment above) — every dialog in the app
   wraps its content in a directly-childed .blueprint div. */
dialog > .blueprint {
  overflow: hidden;
}

/* First-time step tour (assets/js/tour.js) — not a native <dialog>,
   since it needs a semi-transparent backdrop AND an outlined highlight
   on the target underneath, both at once. The card is fixed-docked to
   the left side of the screen (see .bo-tour__card below) rather than
   positioned next to whatever's highlighted — only the target scrolls,
   the card never moves, which is also what keeps it reliably on-screen
   on long pages. */
.bo-tour__backdrop {
  position: fixed;
  inset: 0;
  background: rgba(10, 14, 20, 0.35);
  z-index: 300;
}
.bo-tour__card {
  /* Fixed-docked to the left side of the viewport, not positioned next
     to whatever's highlighted — deliberately. The previous approach
     (position: absolute, computed per-step from the target's
     getBoundingClientRect() + a fixed setTimeout after starting a
     *smooth* scrollIntoView) raced against the scroll animation on long
     pages: on mfd-gst.php's 5000+px page, a 500-1000px smooth scroll
     between steps often hadn't finished by the time the position was
     computed, so the card ended up placed relative to a scroll position
     the page then scrolled past — landing far off-screen (confirmed:
     top computed against scrollY=1721 while the page settled at
     scrollY=1953, a ~232px miss, worse on later/farther steps). Docking
     the card at a fixed spot removes the scroll-timing dependency
     entirely — nothing here depends on where the target ends up.
   */
  position: fixed;
  left: 20px;
  top: 50%;
  transform: translateY(-50%);
  z-index: 301;
  width: min(320px, calc(100vw - 40px));
  max-height: calc(100vh - 40px);
  overflow-y: auto;
  background: var(--color-card-bg);
  border-radius: 6px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.3);
  padding: 16px;
}
.bo-tour__step { font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: color-mix(in srgb, var(--color-text) 60%, transparent); font-weight: 700; margin-bottom: 4px; }
.bo-tour__title { margin: 0 0 6px; font-size: 15px; }
.bo-tour__text { margin: 0 0 14px; font-size: 13.5px; color: color-mix(in srgb, var(--color-text) 80%, transparent); }
.bo-tour__actions { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.bo-tour__highlight {
  position: relative;
  z-index: 301;
  outline: 3px solid var(--color-accent, #2f6feb);
  outline-offset: 3px;
  border-radius: 4px;
  background: var(--color-card-bg);
}

/* Native <dialog> close button — an X in the corner instead of a
   full-width "Close dialog" text button competing with the real actions
   (Approve/Reject/etc.) at the bottom. */
.dialog-close {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 28px;
  height: 28px;
  border: 0;
  background: transparent;
  color: color-mix(in srgb, var(--color-text) 60%, transparent);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  border-radius: 50%;
}
.dialog-close:hover { background: var(--color-accent-100); color: var(--color-text); }

/* pay.php plan picker — billing-cycle pills inside each plan card. */
.plan-picker-cycle { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0; }
.plan-picker-cycle-opt {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 5px 10px; border: 1px solid var(--color-divider); border-radius: 999px;
  font-size: 12px; cursor: pointer; user-select: none;
}
.plan-picker-cycle-opt:has(input:checked) {
  background: var(--color-accent-100); border-color: var(--color-accent-700); color: var(--color-accent-ink); font-weight: 600;
}
.plan-picker-cycle-opt input { margin: 0; }

/* — request-access.php's real, selectable plan picker (radio-per-card) — */
.signup-plan-row {
  display: flex; flex-wrap: nowrap; gap: 8px;
  overflow-x: auto; -webkit-overflow-scrolling: touch;
}
.signup-plan-row .signup-plan-card { flex: 1 1 0; min-width: 0; }
.signup-plan-card { transition: border-color .15s ease, box-shadow .15s ease; }
.signup-plan-card:has(input:checked) { border-color: var(--color-accent-700); box-shadow: 0 0 0 2px var(--color-accent-700) inset; }
.signup-plan-card--popular { border-color: var(--color-amber-dark, #c9821a); padding-top: 40px !important; }
/* top/left clear the card's 1px border and the small "+" corner mark (11x11px, see .blueprint > .corner in components.css) — closer than this and the badge visually collides with both. */
.signup-plan-card__popular-tag { position: absolute; top: 14px; left: 16px; font-size: 9px; padding: 2px 7px; }
@media (max-width: 520px) {
  .signup-plan-row { gap: 4px; }
  .signup-plan-card { padding: 6px !important; }
  .signup-plan-card__popular-tag { display: none; }
}
.signup-field-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px 24px; }
@media (max-width: 560px) {
  .signup-field-grid { grid-template-columns: 1fr; }
}

/* — my-regulatory-profile.php's paginated field pages — a plain 3-column
   grid capped at ~5 rows per page (see the PHP-side field grouping),
   rather than one long ~20-field scroll. */
.profile-field-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px 20px; }
@media (max-width: 900px) {
  .profile-field-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 560px) {
  .profile-field-grid { grid-template-columns: 1fr; }
}
.profile-page { display: none; }
.profile-page.is-active { display: block; }
.profile-pager { display: flex; align-items: center; gap: 8px; margin-bottom: 16px; flex-wrap: wrap; }
.profile-pager__dot {
  width: 26px; height: 26px; border-radius: 50%; border: 1.5px solid var(--color-divider);
  background: var(--color-card-bg); color: color-mix(in srgb, var(--color-text) 60%, transparent);
  font-size: 12px; font-weight: 700; cursor: pointer; flex: none;
}
.profile-pager__dot.is-active { background: var(--color-accent); border-color: var(--color-accent); color: #fff; }
.profile-pager__label { font-size: 12px; color: color-mix(in srgb, var(--color-text) 60%, transparent); margin-right: 8px; }
.profile-pager-nav { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 14px 0; padding-top: 12px; border-top: 1px solid var(--color-divider); }

/* — dashboard.php's chart widget row — */
.dash-stat-row {
  display: flex; flex-wrap: wrap; gap: 20px;
  background: var(--color-card-bg); border: 1px solid var(--color-divider); border-radius: 14px;
  padding: 16px 20px;
}
.dash-stat { min-width: 150px; }

.dash-widget-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px;
  align-items: stretch;
}
.dash-widget {
  background: var(--color-card-bg); border: 1px solid var(--color-divider); border-radius: 14px;
  padding: 16px 18px; display: flex; flex-direction: column;
  box-shadow: 0 1px 2px rgba(17, 24, 39, 0.04);
}
.dash-widget--span2 { grid-column: span 2; }
.dash-widget__label { font-size: 12px; font-weight: 600; color: color-mix(in srgb, var(--color-text) 60%, transparent); margin: 0; }
.dash-widget__foot { font-size: 12px; color: color-mix(in srgb, var(--color-text) 60%, transparent); margin: 8px 0 0; text-align: center; }

.dash-widget--donut { align-items: center; text-align: center; }
.dash-widget__ring-wrap { position: relative; width: 120px; height: 120px; margin: 10px auto 0; }
.dash-widget__ring-center {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-size: 20px; color: var(--color-text);
}

.dash-widget__chart-tall { position: relative; height: 170px; margin-top: 10px; max-width: 100%; }
.dash-widget__chart-tall canvas, .dash-activity-row__trend canvas { max-width: 100%; }
/* Chart.js resizes its canvas responsively via its own resize listener,
   which normally works fine — but a LIVE browser resize (shrinking an
   already-loaded wide window down to phone width, not a fresh narrow
   page load) can leave the canvas's actual pixel width wider than its
   now-shrunk flex container, pushing the whole page into horizontal
   scroll. Confirmed directly: reproduces only via live resize, never on
   a fresh load at the same narrow width. max-width:100% is a hard
   backstop regardless of whether Chart.js's own resize logic catches
   that specific case. */
.dash-widget__chart-mid { position: relative; height: 130px; margin-top: 10px; }

.dash-widget--gauge { align-items: center; text-align: center; }
.dash-widget__gauge-wrap { position: relative; width: 160px; height: 90px; margin: 6px auto 0; }
.dash-widget__gauge-value {
  position: absolute; left: 0; right: 0; bottom: 2px; text-align: center;
  font-size: 20px; font-weight: 700; color: var(--color-text);
}

@media (max-width: 900px) {
  .dash-widget-grid { grid-template-columns: repeat(2, 1fr); }
  .dash-widget--span2 { grid-column: span 2; }
}
@media (max-width: 560px) {
  .dash-widget-grid { grid-template-columns: 1fr; }
  .dash-widget--span2 { grid-column: span 1; }
}

/* — dashboard.php's redesigned hero (greeting, KPI row, activity/tasks
   grid) — real data throughout (see dashboard.php's own comments on
   $recentActivity/$todaysTasks/$quickShortcuts/$dashboardAnnouncements),
   just presented with more visual structure than the old flat stat row. */
.dash-greet { display: flex; align-items: flex-end; justify-content: space-between; flex-wrap: wrap; gap: 8px; margin-bottom: 18px; }
.dash-greet__title { font-size: clamp(22px, 3vw, 28px); margin: 0; }
.dash-greet__sub { margin: 4px 0 0; color: color-mix(in srgb, var(--color-text) 60%, transparent); }
.dash-greet__lastlogin { margin: 0; }

/* Compact "Your plan" chip — replaces what used to be a full card with
   an inline progress bar and trial copy; all of that now lives in
   #dashPlanDialog, opened on click, with the same View/Upgrade action
   inside it. */
.dash-plan-chip {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  padding: 10px 14px; border-radius: 10px; border: 1px solid var(--color-divider);
  background: var(--color-card-bg); cursor: pointer; font-family: inherit; font-size: 13px;
  transition: border-color .15s ease;
}
.dash-plan-chip:hover, .dash-plan-chip:focus-visible { border-color: var(--color-accent); }
.dash-plan-chip__label { color: color-mix(in srgb, var(--color-text) 55%, transparent); font-size: 11px; text-transform: uppercase; letter-spacing: .04em; }
.dash-plan-chip__name { font-weight: 700; color: var(--color-text); }
.dash-plan-chip__meta { color: color-mix(in srgb, var(--color-text) 60%, transparent); margin-left: auto; }
.dash-plan-chip__more { color: var(--color-accent); font-weight: 600; }

.dash-plan-dialog { max-width: 640px; width: 92%; }
.dash-plan-picker { display: grid; grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 10px; }
.dash-plan-picker__card {
  border: 1px solid var(--color-divider); border-radius: 10px; padding: 12px; background: var(--color-card-bg);
}
.dash-plan-picker__card.is-current { border-color: var(--color-accent); box-shadow: 0 0 0 1px var(--color-accent) inset; }
.dash-plan-picker__name { font-weight: 700; font-size: 13px; margin: 0; }
.dash-plan-picker__price { font-weight: 700; font-size: 16px; margin: 4px 0 0; }
@media (max-width: 560px) { .dash-plan-picker { grid-template-columns: repeat(2, 1fr); } }

/* Top summary row — 2 icon-stat cards (real usage numbers) + 1
   gradient subscription card (replaces the old plain .dash-plan-chip
   as the row's anchor, same #dashPlanDialog underneath). */
.dash-summary-row { display: grid; grid-template-columns: 1fr 1fr 1.3fr; gap: 16px; }
.dash-stat-card {
  background: var(--color-card-bg); border: 1px solid var(--color-divider); border-radius: 14px;
  padding: 18px; box-shadow: 0 1px 2px rgba(17, 24, 39, 0.04);
}
.dash-stat-card__icon {
  width: 40px; height: 40px; border-radius: 10px; display: inline-flex; align-items: center; justify-content: center;
  font-size: 18px; background: var(--color-accent-100); color: var(--color-accent-ink); margin-bottom: 14px;
}
.dash-stat-card__icon--green { background: #e6f7ee; color: #14532d; }
.dash-stat-card__label { font-size: 13px; font-weight: 600; color: color-mix(in srgb, var(--color-text) 65%, transparent); margin: 0; }
.dash-stat-card__value { font-size: 28px; font-weight: 700; margin: 6px 0 0; font-family: var(--font-heading); }
.dash-stat-card__meta { font-size: 12.5px; color: color-mix(in srgb, var(--color-text) 55%, transparent); margin: 4px 0 0; }

.dash-subscription-card {
  background: var(--color-accent-gradient); color: #fff; border-radius: 14px; padding: 18px;
  display: flex; flex-direction: column; cursor: pointer; text-align: left; font-family: inherit;
  border: 0; width: 100%;
}
.dash-subscription-card__head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.dash-subscription-card__label { font-size: 12px; text-transform: uppercase; letter-spacing: .04em; opacity: .85; margin: 0; }
.dash-subscription-card__name { font-size: 17px; font-weight: 700; margin: 2px 0 0; }
.dash-subscription-card__available { font-size: 11.5px; text-transform: uppercase; letter-spacing: .04em; opacity: .85; margin: 14px 0 0; }
.dash-subscription-card__value { font-size: 30px; font-weight: 700; margin: 4px 0 0; font-family: var(--font-heading); }
.dash-subscription-card__more { font-size: 13px; font-weight: 600; margin-top: 14px; opacity: .95; }
.dash-subscription-card:hover .dash-subscription-card__more { text-decoration: underline; }

@media (max-width: 900px) { .dash-summary-row { grid-template-columns: 1fr; } }

.dash-kpi-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.dash-kpi {
  background: var(--color-card-bg); border: 1px solid var(--color-divider); border-radius: 12px;
  padding: 14px 14px 12px; display: block; text-decoration: none; color: inherit;
  box-shadow: 0 1px 2px rgba(17, 24, 39, 0.04); transition: border-color .15s ease, transform .15s ease;
}
.dash-kpi--link:hover { border-color: var(--color-accent); transform: translateY(-1px); }
.dash-kpi__icon { font-size: 18px; display: block; margin-bottom: 6px; }
.dash-kpi__label { font-size: 11.5px; font-weight: 600; color: color-mix(in srgb, var(--color-text) 60%, transparent); margin: 0; }
.dash-kpi__value { font-size: 22px; font-weight: 700; margin: 4px 0 0; }
.dash-kpi__sub { font-size: 12px; font-weight: 400; color: color-mix(in srgb, var(--color-text) 55%, transparent); }

.dash-hero-grid { display: grid; grid-template-columns: 2fr 1fr; gap: 12px; margin-top: 12px; align-items: start; }
.dash-hero-main, .dash-hero-side { min-width: 0; } /* grid items default to min-width:auto, which lets content (the chart+doughnut flex row, KPI grids) push the track wider than the viewport on mobile once .dash-hero-grid collapses to one column */

.dash-activity-row { display: flex; gap: 16px; align-items: center; }
.dash-activity-row__trend { flex: 1; min-width: 0; }
.dash-activity-row__mix { flex: none; width: 130px; text-align: center; }
@media (max-width: 560px) {
  .dash-activity-row { flex-direction: column; }
  .dash-activity-row__mix { width: auto; }
}
.dash-card {
  background: var(--color-card-bg); border-radius: 14px; box-shadow: 0 1px 2px rgba(17, 24, 39, 0.04);
  padding: 16px !important; /* .bo-card's 24px is too roomy once every dashboard card stacks vertically — this page needs to fit closer to one screen */
}
.dash-card + .dash-card { margin-top: 12px !important; }

.dash-activity-list, .dash-task-list, .dash-announce-list { display: flex; flex-direction: column; gap: 2px; }
.dash-activity-item, .dash-task-item {
  display: flex; align-items: center; gap: 10px; padding: 9px 4px;
  border-top: 1px solid color-mix(in srgb, var(--color-divider) 70%, transparent);
  text-decoration: none; color: inherit;
}
.dash-activity-item:first-child, .dash-task-item:first-child { border-top: 0; }
.dash-activity-item__icon { font-size: 16px; flex: none; width: 24px; text-align: center; }
.dash-activity-item__body { flex: 1; min-width: 0; font-size: 13px; }
.dash-activity-item__body strong { font-weight: 600; }
.dash-activity-item__time { font-size: 11px; flex: none; white-space: nowrap; }

.dash-task-item__check {
  width: 18px; height: 18px; flex: none; border-radius: 5px; border: 1.5px solid var(--color-divider);
}
.dash-task-item:hover .dash-task-item__check { border-color: var(--color-accent); }
.dash-task-item__body { flex: 1; min-width: 0; display: flex; flex-direction: column; font-size: 13px; }
.dash-task-item__body span:first-child { font-weight: 600; }

.dash-shortcut-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.dash-shortcut {
  display: flex; flex-direction: column; align-items: center; gap: 6px; text-align: center;
  padding: 10px 4px; border-radius: 10px; border: 1px solid var(--color-divider);
  text-decoration: none; color: inherit; font-size: 11px; font-weight: 600;
  transition: border-color .15s ease, background .15s ease;
}
.dash-shortcut:hover { border-color: var(--color-accent); background: var(--color-accent-100); }
.dash-shortcut__icon {
  width: 30px; height: 30px; border-radius: 50%; background: var(--color-accent-100); color: var(--color-accent);
  display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 13px;
}

.dash-announce-item { padding: 8px 4px; border-top: 1px solid color-mix(in srgb, var(--color-divider) 70%, transparent); }
.dash-announce-item:first-child { border-top: 0; }
.dash-announce-item__head { display: flex; align-items: center; gap: 6px; font-size: 13px; }

/* Ops-at-a-glance chip strip — replaces what used to be two full
   hub-grid sections (System health, Support at a glance) worth of
   bordered/cornered tiles with one wrapping row of small pills, same
   real numbers, a fraction of the vertical space. */
.dash-ops-strip { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.dash-ops-chip {
  display: inline-flex; align-items: center; gap: 4px; padding: 5px 11px; border-radius: 999px;
  background: var(--color-card-bg); border: 1px solid var(--color-divider); font-size: 12px;
  color: inherit; text-decoration: none; white-space: nowrap;
}
.dash-ops-chip strong { font-weight: 700; }
.dash-ops-chip--warn { border-color: color-mix(in srgb, var(--color-amber-dark, #b5791a) 55%, var(--color-divider)); background: color-mix(in srgb, var(--color-amber-dark, #b5791a) 10%, var(--color-card-bg)); }
.dash-ops-chip--ok { border-color: color-mix(in srgb, var(--color-green, #1f9e6a) 45%, var(--color-divider)); background: color-mix(in srgb, var(--color-green, #1f9e6a) 8%, var(--color-card-bg)); }

/* Module-wise launcher grid — one compact tile per category. Clicking a
   tile opens the full list of that category's real modules as a dialog
   (see #dashModuleDialog + its script in dashboard.php) — no hover
   flyout (removed: it doubled up with the dialog and never worked well
   on touch). */
.dash-module-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(148px, 1fr)); gap: 10px; margin-top: 10px; }
.dash-module-tile { position: relative; }
.dash-module-tile__head {
  width: 100%; display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  padding: 13px 12px; border-radius: 10px; border: 1px solid var(--color-divider);
  background: var(--color-card-bg); cursor: pointer; text-align: left; position: relative;
  font-family: inherit; color: var(--color-text); transition: border-color .15s ease, box-shadow .15s ease;
}
.dash-module-tile__head:hover, .dash-module-tile__head:focus-visible { border-color: var(--color-accent); box-shadow: 0 2px 10px rgba(17, 24, 39, 0.1); }
.dash-module-tile__icon { font-size: 19px; }
.dash-module-tile__label { font-weight: 700; font-size: 13px; }
.dash-module-tile__count { font-size: 10.5px; color: color-mix(in srgb, var(--color-text) 55%, transparent); }
.dash-module-tile__badge { position: absolute; top: 8px; right: 8px; font-size: 9px; }

#dashModuleDialog { max-width: 640px; width: 92%; }
.dash-module-dialog-list { list-style: none; padding: 0; margin: 14px 0 0; display: grid; grid-template-columns: repeat(2, 1fr); gap: 6px; }
.dash-module-dialog-list a {
  display: block; padding: 8px 10px; border-radius: 8px; border: 1px solid var(--color-divider);
  font-size: 13px; text-decoration: none; color: inherit;
}
.dash-module-dialog-list a:hover { border-color: var(--color-accent); background: var(--color-accent-100); }
.dash-module-dialog-list a.is-locked { color: color-mix(in srgb, var(--color-text) 55%, transparent); }
.dash-module-dialog-list__note { margin-top: 3px; font-size: 9.5px; }
@media (max-width: 700px) { .dash-module-dialog-list { grid-template-columns: 1fr; } }

/* User Manual dropdown, greet-header — plain CSS hover/focus dropdown,
   same interaction pattern as the module tiles above. */
.dash-manual-dd { position: relative; }
.dash-manual-dd__btn {
  display: inline-flex; align-items: center; gap: 6px; padding: 8px 14px; border-radius: 8px;
  border: 1px solid var(--color-divider); background: var(--color-card-bg); font-size: 13px; font-weight: 600;
  color: inherit; cursor: pointer; font-family: inherit;
}
.dash-manual-dd__btn:hover, .dash-manual-dd__btn:focus-visible { border-color: var(--color-accent); }
.dash-manual-dd__panel {
  position: absolute; top: calc(100% + 6px); right: 0; min-width: 260px; max-height: 360px; overflow-y: auto;
  background: var(--color-card-bg); border: 1px solid var(--color-divider); border-radius: 10px;
  box-shadow: 0 8px 24px rgba(17, 24, 39, 0.16); padding: 6px; z-index: 30;
  opacity: 0; visibility: hidden; transform: translateY(-4px); transition: opacity .12s ease, transform .12s ease;
}
.dash-manual-dd:hover .dash-manual-dd__panel, .dash-manual-dd:focus-within .dash-manual-dd__panel {
  opacity: 1; visibility: visible; transform: none;
}
@media (max-width: 560px) {
  /* This button sits near the LEFT edge of the page — anchoring the
     panel's right edge to it (as on desktop, where it sits at the far
     right of the greet row) pushes most of a 260px-wide panel off the
     left edge of a narrow screen instead. Anchor left and cap the width
     to the viewport instead. */
  .dash-manual-dd__panel { right: auto; left: 0; min-width: 0; width: min(280px, calc(100vw - 32px)); }
}
.dash-manual-dd__panel a { display: flex; align-items: center; gap: 6px; padding: 8px 10px; border-radius: 6px; font-size: 13px; color: inherit; text-decoration: none; }
.dash-manual-dd__panel a:hover { background: var(--color-accent-100); }
.dash-manual-dd__panel a.is-flagship { background: #fdf6e8; color: #1b2140; font-weight: 700; }
.dash-manual-dd__panel a.is-flagship:hover { background: #fbecc9; }

@media (max-width: 900px) {
  .dash-hero-grid { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  .dash-kpi-row { grid-template-columns: repeat(2, 1fr); }
}

.bo-checkbox-row { margin-bottom: 18px; }
.bo-checkbox-row label { display: inline-flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 500; cursor: pointer; }

.bo-flash { padding: 10px 14px; margin-bottom: 16px; font-size: 14px; border-left: 3px solid; }
.bo-flash--error { background: #fdeceb; border-color: var(--color-red); color: #7a2a22; }
.bo-flash--success { background: var(--color-accent-100); border-color: var(--color-green); color: #14532d; }
.bo-flash--warn { background: #fff8e6; border-color: #92600a; color: #92600a; }

/* Site-wide "any offers" banner (renderOfferBanner(), inc/subscriptions.php) — a slim, single-line strip ABOVE every page's header (same placement/DOM order everywhere: index.php, demo.php, and every signed-in page via inc/layout.php), so it reads as one consistent look site-wide. Deliberately NOT sticky: it sits in normal flow above the header and simply scrolls away with the rest of the page, leaving the header (which IS sticky, its own higher z-index) pinned alone — the same "banner visible only until you scroll" behavior on every page. A single message just sits still. 2+ messages (offer_banners table) are joined into one line and scroll continuously left as a ticker (.bo-offer-banner--ticker) — pure CSS transform animation, nothing ever hidden/shown/swapped, so there's no "cut" moment or layout jolt. */
.bo-offer-banner {
  position: relative; z-index: 8;
  background: linear-gradient(90deg, var(--color-accent, #3b56e0), color-mix(in srgb, var(--color-accent, #3b56e0) 70%, #7c3aed));
  color: #fff; font-size: 13px; font-weight: 600; text-align: center;
  padding: 8px 40px 8px 16px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.bo-offer-banner--ticker { text-align: left; }
.bo-offer-banner__track {
  display: inline-flex;
  width: max-content;
  animation: bo-offer-banner-scroll linear infinite;
  will-change: transform;
}
.bo-offer-banner__msg { display: inline-block; white-space: nowrap; }
@keyframes bo-offer-banner-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .bo-offer-banner__track { animation: none; }
}
.bo-offer-banner__dismiss {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  width: 22px; height: 22px; border-radius: 50%; border: 0;
  background: #ffffff26; color: #fff; font-size: 16px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.bo-offer-banner__dismiss:hover { background: #ffffff40; }
.bo-offer-banner__denied {
  /* Positioned inside the banner's own box, not below it — the banner
     has overflow:hidden (needed for the ticker), which would clip
     anything placed outside its bounds. */
  position: absolute; right: 36px; top: 50%; transform: translateY(-50%);
  background: #16204a; color: #fff;
  border-radius: 6px;
  padding: 4px 10px; font-size: 11px; font-weight: 600; white-space: nowrap;
  box-shadow: 0 2px 8px #00000040;
}

/* Crossed-out base price + current price (renderPlanPriceHtml(), inc/subscriptions.php — and pay.php's own client-side equivalent). */
.plan-price-was { font-weight: 400; font-size: 0.72em; color: color-mix(in srgb, var(--color-text) 55%, transparent); margin-right: 2px; }
.plan-price-now { color: var(--color-green, #1f9e6a); }

/* "Launch pricing — increases to ₹X from <date>" callout (renderPlanOfferNote(), inc/subscriptions.php). */
.plan-offer-note { font-size: 11.5px; font-weight: 600; color: var(--color-amber-dark, #c9821a); margin: 2px 0 8px; }

/* — dashboard tiles (self-contained equivalents of partner-info's hub-* classes) — */
.hub-intro { max-width: 700px; }
.hub-intro p { font-size: 15px; line-height: 1.6; color: color-mix(in srgb, var(--color-text) 80%, transparent); }
.hub-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 16px; }
.hub-card { padding: 20px; background: var(--color-card-bg); position: relative; }
.hub-meta, .bo-meta { font-size: 13px; color: color-mix(in srgb, var(--color-text) 70.2%, transparent); margin: 4px 0; }
.hub-section-head { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px; margin-bottom: 16px; }

/* — chips/links row (AMC "Visit site" links, badge rows) — */
.hub-links { display: flex; flex-wrap: wrap; gap: 8px; }
.hub-chip {
  font-size: 12.5px;
  font-family: var(--font-heading);
  letter-spacing: 0.03em;
  padding: 7px 12px;
  border: 1px solid color-mix(in srgb, var(--color-text) 16.1%, transparent);
  color: var(--color-text);
  text-decoration: none;
}
.hub-chip:hover { border-color: var(--color-accent); color: var(--color-accent); }

/* — two-column form/result layout (finplanner, adv-finplanner) — */
.mfd-grid { display: grid; grid-template-columns: 2fr 1fr; gap: 20px; align-items: start; }
.mfd-grid > * { min-width: 0; } /* grid items default to min-width:auto (content-based) — without this, a child's intrinsic content width can push the track past the viewport once the grid collapses to 1 column on mobile, same trap fixed elsewhere in this file */
.mfd-grid canvas { max-width: 100%; height: auto; } /* a canvas's HTML width/height attributes (its raster resolution) also set its default CSS box size, unconstrained by any parent min-width:0 fix — adv-finplanner.php's cashflow_chart canvas confirmed 11px past the viewport on a 390px phone without this */
.mfd-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 22px; }
/* !important is required here: npscalc.php/finplanner.php/
   adv-finplanner.php/feedback.php each set grid-template-columns via an
   inline style="" (e.g. "1fr 1.5fr") for their desktop ratio — inline
   styles always outrank an external stylesheet rule regardless of media
   query, so without !important this rule silently never applied on
   mobile and those pages kept a squeezed 2-column layout below 900px. */
@media (max-width: 900px) { .mfd-grid { grid-template-columns: 1fr !important; } }

/* — workflow-at-a-glance sequence flow (mfd-gst.php) — plain flexbox
   chain of steps + arrows, not a diagramming library (see the comment
   at its call site for why). Wraps naturally on narrow screens instead
   of needing a separate mobile layout. — */
.mfd-flow { display: flex; flex-wrap: wrap; align-items: stretch; gap: 6px 4px; }
.mfd-flow__node {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  min-width: 96px; padding: 10px 12px; border: 1px solid color-mix(in srgb, var(--color-text) 16.1%, transparent); border-radius: 8px;
  background: var(--color-card-bg); text-decoration: none; color: var(--color-text); text-align: center;
  transition: border-color .15s ease, transform .15s ease;
}
.mfd-flow__node:hover { border-color: var(--color-accent); transform: translateY(-1px); }
.mfd-flow__node--time { border-color: var(--color-accent-100, #eaeeff); background: var(--color-accent-100, #eaeeff); }
.mfd-flow__label { font-size: 12px; font-weight: 600; line-height: 1.3; }
.mfd-flow__time { font-size: 11px; color: var(--color-accent-700, #23306e); font-weight: 700; }
.mfd-flow__arrow { display: flex; align-items: center; font-size: 16px; color: color-mix(in srgb, var(--color-text) 40%, transparent); padding: 0 2px; }
@media (max-width: 700px) { .mfd-flow__arrow { display: none; } .mfd-flow__node { flex: 1 1 45%; } }
.mfd-flow__node--setup { border-style: dashed; background: color-mix(in srgb, var(--color-text) 3.1%, transparent); }

/* — GST Archive folder subfolder legend (mfd-gst.php) — plain <dl>
   describing what each subfolder in the tree above it is for, kept
   outside the <pre> so the tree itself stays a clean, copyable path. — */
.bo-archive-legend { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; margin: 10px 0; font-size: 13px; }
.bo-archive-legend dt { font-family: var(--font-mono, monospace); color: var(--color-accent-700, #23306e); white-space: nowrap; }
.bo-archive-legend dd { margin: 0; color: var(--color-text-muted, color-mix(in srgb, var(--color-text) 65.1%, transparent)); }

.bo-tile { display: block; text-decoration: none; color: inherit; transition: border-color .15s ease; }
.bo-tile:hover { border-color: var(--color-accent); }
.bo-tile h3 { font-size: 17px; margin: 0 0 6px; color: var(--color-text); }
.bo-tile--locked { opacity: .72; }
.bo-tile--locked:hover { opacity: 1; border-color: #92600a; }
.bo-tile__premium { position: absolute; top: 14px; right: 14px; }
.bo-tile__upgrade { display: block; margin-top: 8px; font-size: 12px; font-weight: 600; color: #92600a; }

/* — trial / usage progress bar — */
.bo-progress { height: 6px; background: color-mix(in srgb, var(--color-text) 5.9%, transparent); overflow: hidden; }
.bo-progress__bar { height: 100%; background: var(--color-accent); }

/* — generic content card — */
.bo-card { padding: 24px; background: var(--color-card-bg); position: relative; }
.bo-card h2 { font-size: 19px; margin: 0 0 14px; }
.bo-card h3 { font-size: 15px; margin: 18px 0 10px; }

/* — tables — */
.bo-table { width: 100%; border-collapse: collapse; font-size: 14px; margin-top: 12px; }
.bo-table th { text-align: left; padding: 10px 12px; font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: color-mix(in srgb, var(--color-text) 60%, transparent); border-bottom: 1px solid color-mix(in srgb, var(--color-text) 16.1%, transparent); }
.bo-table td { padding: 10px 12px; border-bottom: 1px solid color-mix(in srgb, var(--color-text) 8.2%, transparent); vertical-align: top; }
/* — compact table modifier + category group-header row, for dense
   settings pickers (e.g. onboarding-popup.php's highlight-modules
   table) where the default row height wastes space across 30+ rows. */
.bo-table--compact th, .bo-table--compact td { padding: 5px 10px; font-size: 13px; }
.bo-table__group-row td {
  padding: 8px 10px 3px; border-bottom: none; font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em; color: color-mix(in srgb, var(--color-text) 55%, transparent);
}
.bo-table__group-row--divider td { padding-top: 18px; border-top: 1px solid color-mix(in srgb, var(--color-text) 16.1%, transparent); }
.bo-mono { font-family: ui-monospace, monospace; font-size: 12px; color: color-mix(in srgb, var(--color-text) 70.2%, transparent); max-width: 320px; overflow-wrap: anywhere; }

/* — badges — */
.bo-badge { display: inline-block; font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase; padding: 3px 9px; background: color-mix(in srgb, var(--color-text) 5.9%, transparent); color: var(--color-text); }
.bo-badge--admin { background: var(--color-accent-100); color: var(--color-accent-ink); }
.bo-badge--employee { background: #fff4e0; color: #92600a; }
.bo-badge--distributor { background: #e6f0ff; color: #1d4ed8; }
.bo-badge--on { background: #e6f7ee; color: #14532d; }
.bo-badge--off { background: color-mix(in srgb, var(--color-text) 5.9%, transparent); color: color-mix(in srgb, var(--color-text) 60%, transparent); }
.bo-badge--warn { background: #fdeceb; color: #7a2a22; }
.bo-badge--muted { background: color-mix(in srgb, var(--color-text) 5.9%, transparent); color: color-mix(in srgb, var(--color-text) 60%, transparent); }
.bo-badge--archived { background: #ede9fe; color: #5b21b6; }

/* — category sub-nav (tabs within a module, e.g. IFA/ND) — */
.category-nav { display: flex; flex-wrap: wrap; gap: 8px; }
.category-nav a {
  font-size: 13px;
  font-family: var(--font-heading);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 7px 14px;
  border: 1px solid color-mix(in srgb, var(--color-text) 16.1%, transparent);
  color: var(--color-text);
  text-decoration: none;
}
.category-nav a:hover { border-color: var(--color-accent); color: var(--color-accent); }
.category-nav a.is-current { background: var(--color-accent); color: #fff; border-color: var(--color-accent); }

/* — search / filter rows — */
.bo-search-row, .bo-filter-row { display: flex; flex-wrap: wrap; gap: 10px; margin: 16px 0; }
.bo-search-row .input, .bo-filter-row .input { width: auto; flex: 1 1 160px; min-width: 0; }
/* width:auto above means "shrink-to-fit content" for a text <input>,
   which is fine — but for a <select>, "auto" means size to its widest
   <option> text specifically, ignoring the container entirely (a long
   option like "admin (admin) — someone@example.com" on
   support-staff-config.php then forces the whole row wider than the
   viewport regardless of any min-width:0 on its ancestors, since the
   select was never trying to fill the container in the first place).
   A <select> needs width:100% instead, same as .input's own default. */
.bo-search-row select.input, .bo-filter-row select.input { width: 100%; min-width: 0; }
/* A second, less common markup shape in this codebase wraps the input
   in its own .field (e.g. subscription-plans.php's Max users/Max
   storage/Max monthly credits row, support-staff-config.php) instead of
   making the input itself the direct flex child. There, .field is what
   should flex/shrink and .input should just fill it — width:auto from
   the rule above sizes a plain number/text input to its OS-default
   intrinsic width (~170px+) regardless of how narrow its real .field
   parent is, which is what actually overflowed subscription-plans.php
   (three such fields, 87px past a 390px viewport). */
.bo-search-row > .field, .bo-filter-row > .field { flex: 1 1 160px; min-width: 0; }
.bo-search-row > .field > .input, .bo-filter-row > .field > .input { width: 100%; flex: none; }

/* — pagination — */
.bo-pagination { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 20px; }
.bo-pagination a { padding: 6px 11px; border: 1px solid color-mix(in srgb, var(--color-text) 16.1%, transparent); font-size: 13px; color: var(--color-text); text-decoration: none; }
.bo-pagination a.is-current { background: var(--color-accent); color: #fff; border-color: var(--color-accent); }

@media (max-width: 640px) {
  .hub-grid { grid-template-columns: 1fr; }
  .bo-table { display: block; overflow-x: auto; }
}

/* — data-tool controls (mf-us-canada, banks-epayeezz: search/filter/sort/paginate/export tables) — */
.bo-tool-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-bottom: 14px; }
.bo-tool-controls .group { display: flex; align-items: center; gap: 6px; }
.bo-tool-controls .group label { font-size: 12px; color: color-mix(in srgb, var(--color-text) 60%, transparent); white-space: nowrap; }
.bo-tool-controls select, .bo-tool-controls input[type="search"] { padding: 7px 10px; border: 1px solid color-mix(in srgb, var(--color-text) 16.1%, transparent); background: var(--color-card-bg); font-size: 13px; font-family: inherit; }
.bo-table th.sortable { cursor: pointer; user-select: none; }
.bo-table th.sortable .caret { opacity: .45; margin-left: 3px; }
/* Server-rendered sort links (users.php) — same visual weight as a
   plain, non-interactive header, not a blue underlined link. */
.bo-table th.sortable a { color: inherit; text-decoration: none; }
.bo-table th.sortable a:hover { text-decoration: underline; }
.bo-table-wrap { overflow-x: auto; }

.pill { display: inline-block; font-size: 11px; letter-spacing: 0.03em; padding: 3px 10px; border: 1px solid color-mix(in srgb, var(--color-text) 16.1%, transparent); color: color-mix(in srgb, var(--color-text) 60%, transparent); cursor: pointer; }
.pill.yes, .pill.live { background: #e6f7ee; color: #14532d; border-color: #b9e6cc; }
.pill.no { background: #fdeceb; color: #7a2a22; border-color: #f4c9c4; }
.pill.active { outline: 2px solid var(--color-accent); outline-offset: 1px; }

.bo-tool-footer { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 10px; margin-top: 14px; }
.bo-pagebtn { padding: 6px 12px; border: 1px solid color-mix(in srgb, var(--color-text) 16.1%, transparent); background: var(--color-card-bg); font-size: 13px; cursor: pointer; }
.bo-pagebtn:hover { border-color: var(--color-accent); color: var(--color-accent); }

/* — narrow side panel + wide main (eKYC PAN checker) — */
.bo-side-layout { display: grid; grid-template-columns: 300px 1fr; gap: 20px; align-items: start; }
.bo-side-layout > * { min-width: 0; } /* same grid min-width:auto trap as .mfd-grid/.dash-hero-grid above — needed once this collapses to 1 column on mobile */
@media (max-width: 900px) { .bo-side-layout { grid-template-columns: 1fr; } }
.bo-side-layout .bo-card { position: sticky; top: 16px; }
@media (max-width: 900px) { .bo-side-layout .bo-card { position: static; } }
.bo-step-list { font-size: 13px; color: color-mix(in srgb, var(--color-text) 70.2%, transparent); line-height: 1.6; padding-left: 18px; margin: 10px 0; }
.bo-btn-stack { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }

/* — radio group (MFD GST: template / input-mode pickers) — */
.bo-radio-group { display: flex; flex-wrap: wrap; gap: 14px; font-size: 14px; }
.bo-radio-group label { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; font-weight: 400; }

/* — loading overlay (client-side PDF signing feedback) — */
.bo-loading-overlay { position: fixed; inset: 0; background: #16204acc; display: none; align-items: center; justify-content: center; flex-direction: column; gap: 14px; z-index: 200; color: #fff; }
.bo-loading-overlay.is-active { display: flex; }
.bo-loader { width: 40px; height: 40px; border: 3px solid #ffffff40; border-top-color: #fff; border-radius: 50%; animation: bo-spin 0.8s linear infinite; }
@keyframes bo-spin { to { transform: rotate(360deg); } }

/* — floating quick-links cluster (bottom-right, every backoffice page) — */
.bo-fab { position: fixed; right: 20px; bottom: 20px; z-index: 120; display: flex; flex-direction: column; align-items: flex-end; gap: 10px; }
.bo-fab__toggle {
  width: 48px; height: 48px; border-radius: 50%; border: none; cursor: pointer;
  background: var(--color-navy, #10213f); color: #fff; font-size: 24px; line-height: 1;
  box-shadow: 0 4px 14px #00000040; transition: transform .15s ease;
}
.bo-fab__toggle:hover { transform: scale(1.06); }
.bo-fab--open .bo-fab__toggle { transform: rotate(45deg); }
.bo-fab__menu {
  display: none; flex-direction: column; gap: 4px; background: var(--color-card-bg); border-radius: 12px;
  padding: 8px; box-shadow: 0 6px 20px #00000030; min-width: 150px;
}
.bo-fab--open .bo-fab__menu { display: flex; }
.bo-fab__menu a { padding: 8px 12px; border-radius: 8px; font-size: 13.5px; color: var(--color-text); text-decoration: none; }
.bo-fab__menu a:hover { background: color-mix(in srgb, var(--color-text) 5.1%, transparent); }

/* — header notification bell + dropdown (every page, replaces the old
   dashboard-only inline banner list) — */
.bo-notif { position: relative; }
.bo-notif__toggle {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 50%; border: 1px solid var(--color-divider); background: var(--color-accent-100);
  color: var(--color-accent-ink); cursor: pointer; transition: background .15s ease;
}
.bo-notif__toggle:hover { background: var(--color-accent-700); color: #fff; }
.bo-notif__badge {
  position: absolute; top: -4px; right: -4px; min-width: 16px; height: 16px; padding: 0 3px;
  border-radius: 999px; background: var(--color-red, #a53f3f); color: #fff;
  font-size: 10px; font-weight: 700; line-height: 16px; text-align: center;
}
.bo-notif__menu {
  display: none; position: absolute; right: 0; top: calc(100% + 10px); z-index: 60;
  width: min(340px, 90vw); max-height: 420px; overflow-y: auto; background: var(--color-card-bg); color: var(--color-text);
  border-radius: 12px; box-shadow: 0 10px 30px #00000030;
}
.bo-notif--open .bo-notif__menu { display: block; }
.bo-notif__header { padding: 12px 16px; font-size: 13px; font-weight: 700; border-bottom: 1px solid color-mix(in srgb, var(--color-text) 7.8%, transparent); }
.bo-notif__list { display: flex; flex-direction: column; }
.bo-notif__item { display: flex; gap: 8px; align-items: flex-start; padding: 12px 16px; border-bottom: 1px solid color-mix(in srgb, var(--color-text) 7.8%, transparent); }
.bo-notif__item:last-child { border-bottom: none; }
.bo-notif__item-body { flex: 1 1 auto; min-width: 0; font-size: 13px; }
.bo-notif__item-body strong { display: block; margin-bottom: 2px; }
.bo-notif__item-body p { margin: 0 0 4px; color: color-mix(in srgb, var(--color-text) 80%, transparent); white-space: pre-wrap; overflow-wrap: anywhere; }
.bo-notif__time { font-size: 11px; color: color-mix(in srgb, var(--color-text) 60%, transparent); }
.bo-notif__dismiss {
  flex: 0 0 auto; border: 0; background: none; cursor: pointer; color: color-mix(in srgb, var(--color-text) 60%, transparent);
  font-size: 16px; line-height: 1; padding: 2px 4px;
}
.bo-notif__dismiss:hover { color: var(--color-red, #a53f3f); }
.bo-notif__empty { padding: 20px 16px; margin: 0; font-size: 13px; color: color-mix(in srgb, var(--color-text) 60%, transparent); text-align: center; }

/* — header pricing icon link — same circular icon-button treatment as
   .bo-notif__toggle/.bo-newfeat__toggle below, but a plain link (no
   dropdown) straight to pricing.php. — */
.bo-header-icon-link {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 50%; border: 1px solid var(--color-divider); background: var(--color-accent-100);
  color: var(--color-accent-ink); cursor: pointer; transition: background .15s ease;
}
.bo-header-icon-link:hover { background: var(--color-accent-700); color: #fff; }
.bo-header-icon-link__new-dot {
  position: absolute; top: -1px; right: -1px; width: 9px; height: 9px; border-radius: 50%;
  background: var(--color-amber, #e2a53a); border: 1.5px solid var(--color-primary, #1b2140);
}

/* — header "New" changelog icon + dropdown (mirrors .bo-notif above,
   but items persist — only the unseen badge clears on open) — */
.bo-newfeat { position: relative; }
.bo-newfeat__toggle {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 50%; border: 1px solid var(--color-divider); background: var(--color-accent-100);
  color: var(--color-accent-ink); cursor: pointer; transition: background .15s ease;
}
.bo-newfeat__toggle:hover { background: var(--color-accent-700); color: #fff; }
.bo-newfeat__badge {
  position: absolute; top: -4px; right: -4px; min-width: 16px; height: 16px; padding: 0 3px;
  border-radius: 999px; background: var(--color-amber-dark, #b5791a); color: #fff;
  font-size: 10px; font-weight: 700; line-height: 16px; text-align: center;
}
.bo-newfeat__menu {
  display: none; position: absolute; right: 0; top: calc(100% + 10px); z-index: 60;
  width: min(360px, 90vw); max-height: 440px; overflow-y: auto; background: var(--color-card-bg); color: var(--color-text);
  border-radius: 12px; box-shadow: 0 10px 30px #00000030;
}
.bo-newfeat--open .bo-newfeat__menu { display: block; }
.bo-newfeat__header { padding: 12px 16px; font-size: 13px; font-weight: 700; border-bottom: 1px solid color-mix(in srgb, var(--color-text) 7.8%, transparent); }
.bo-newfeat__list { display: flex; flex-direction: column; }
.bo-newfeat__item { padding: 12px 16px; border-bottom: 1px solid color-mix(in srgb, var(--color-text) 7.8%, transparent); font-size: 13px; }
.bo-newfeat__item:last-child { border-bottom: none; }
.bo-newfeat__item-head { display: flex; align-items: center; gap: 6px; margin-bottom: 3px; }
.bo-newfeat__item-head strong { flex: 1 1 auto; min-width: 0; }
.bo-newfeat__tag { font-size: 9px; padding: 1px 6px; }
.bo-newfeat__item p { margin: 0 0 6px; color: color-mix(in srgb, var(--color-text) 80%, transparent); }
.bo-newfeat__item-foot { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
.bo-newfeat__time { font-size: 11px; color: color-mix(in srgb, var(--color-text) 60%, transparent); }
.bo-newfeat__empty { padding: 20px 16px; margin: 0; font-size: 13px; color: color-mix(in srgb, var(--color-text) 60%, transparent); text-align: center; }

/* — header favorites star + dropdown (mirrors .bo-notif above) — */
.bo-fav { position: relative; }
.bo-fav__toggle {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 50%; border: 1px solid var(--color-divider); background: var(--color-accent-100);
  color: var(--color-accent-ink); cursor: pointer; transition: background .15s ease;
}
.bo-fav__toggle:hover { background: var(--color-accent-700); color: #fff; }
.bo-fav__toggle.is-favorited { color: var(--color-amber, #e2a53a); }
.bo-fav__badge {
  position: absolute; top: -4px; right: -4px; min-width: 16px; height: 16px; padding: 0 3px;
  border-radius: 999px; background: var(--color-accent, #3b56e0); color: #fff;
  font-size: 10px; font-weight: 700; line-height: 16px; text-align: center;
}
.bo-fav__menu {
  display: none; position: absolute; right: 0; top: calc(100% + 10px); z-index: 60;
  width: min(340px, 90vw); max-height: 460px; overflow-y: auto; background: var(--color-card-bg); color: var(--color-text);
  border-radius: 12px; box-shadow: 0 10px 30px #00000030;
}
.bo-fav--open .bo-fav__menu { display: block; }
.bo-fav__header { padding: 12px 16px; font-size: 13px; font-weight: 700; border-bottom: 1px solid color-mix(in srgb, var(--color-text) 7.8%, transparent); }
.bo-fav__current {
  width: 100%; display: flex; align-items: center; gap: 10px; padding: 12px 16px;
  border: none; border-bottom: 1px solid color-mix(in srgb, var(--color-text) 7.8%, transparent); background: none; cursor: pointer;
  font-size: 13px; color: var(--color-accent, #3b56e0); text-align: left;
}
.bo-fav__current:hover { background: color-mix(in srgb, var(--color-text) 3.9%, transparent); }
.bo-fav__current svg { flex: 0 0 auto; color: var(--color-amber, #e2a53a); }
.bo-fav__picker { display: flex; gap: 8px; padding: 12px 16px; border-bottom: 1px solid color-mix(in srgb, var(--color-text) 7.8%, transparent); }
.bo-fav__picker select { flex: 1 1 auto; min-width: 0; font-size: 13px; padding: 6px 8px; border-radius: 6px; border: 1px solid color-mix(in srgb, var(--color-text) 14.9%, transparent); }
.bo-fav__list { display: flex; flex-direction: column; }
.bo-fav__item { display: flex; gap: 8px; align-items: center; padding: 10px 16px; border-bottom: 1px solid color-mix(in srgb, var(--color-text) 7.8%, transparent); }
.bo-fav__item:last-child { border-bottom: none; }
.bo-fav__item a { flex: 1 1 auto; min-width: 0; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bo-fav__remove {
  flex: 0 0 auto; border: 0; background: none; cursor: pointer; color: color-mix(in srgb, var(--color-text) 60%, transparent);
  font-size: 16px; line-height: 1; padding: 2px 4px;
}
.bo-fav__remove:hover { color: var(--color-red, #a53f3f); }
.bo-fav__empty { padding: 20px 16px; margin: 0; font-size: 13px; color: color-mix(in srgb, var(--color-text) 60%, transparent); text-align: center; }

/* — header profile chip (replaces the old plain "Log out (username)"
   button) — native <details>/<summary>, same lightweight pattern as
   the sidebar groups; no new JS framework. — */
.bo-lang-switcher { margin: 0; }
.bo-lang-switcher select {
  border: 1px solid var(--color-divider); background: var(--page-bg); color: var(--color-text);
  border-radius: 9999px; padding: 6px 10px; font-size: 12.5px; font-family: inherit; cursor: pointer;
}
.bo-lang-switcher select:hover { border-color: var(--color-accent); }

.bo-profile-chip { position: relative; margin-left: 4px; }
.bo-profile-chip > summary {
  display: flex; align-items: center; gap: 8px; padding: 5px 10px 5px 6px;
  border-radius: 9999px; border: 1px solid var(--color-divider); background: var(--page-bg);
  cursor: pointer; list-style: none; color: var(--color-text); font-size: 13.5px; font-weight: 600;
}
.bo-profile-chip > summary::-webkit-details-marker { display: none; }
.bo-profile-chip > summary:hover { background: var(--color-accent-100); }
.bo-profile-chip__avatar {
  flex: 0 0 26px; width: 26px; height: 26px; border-radius: 50%;
  background: var(--color-accent-gradient); color: #fff;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700;
}
.bo-profile-chip__name { max-width: 140px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bo-profile-chip__caret { flex: 0 0 auto; color: var(--color-muted); transition: transform .15s ease; }
.bo-profile-chip[open] > summary .bo-profile-chip__caret { transform: rotate(180deg); }
.bo-profile-chip__menu {
  position: absolute; right: 0; top: calc(100% + 8px); z-index: 60; min-width: 180px;
  background: var(--color-card-bg); color: var(--color-text);
  border-radius: 12px; box-shadow: 0 10px 30px #00000030; padding: 6px; display: flex; flex-direction: column; gap: 2px;
}
.bo-profile-chip__menu a,
.bo-profile-chip__menu button {
  display: block; width: 100%; text-align: left; padding: 9px 10px; border-radius: 8px;
  border: none; background: none; cursor: pointer; font-size: 13.5px; color: var(--color-text);
}
.bo-profile-chip__menu a:hover,
.bo-profile-chip__menu button:hover { background: var(--color-accent-100); color: var(--color-accent-ink); text-decoration: none; }
.bo-profile-chip__menu button { color: var(--color-red, #dd5a4d); }

/* Notifications/New-features/Favorites dropdowns on mobile: each menu
   is `position:absolute; right:0` relative to its own ~34px icon
   button, not the viewport. Below 640px, the header bar wraps
   (site-header__bar has flex-wrap:wrap) and these icons can land near
   the LEFT edge of the screen — "right:0" then anchors a 300px+-wide
   menu off the right edge of that icon, pushing most of it past the
   left edge of the viewport (negative x), effectively invisible/
   unreachable. Pin all three to the viewport instead of their icon. */
@media (max-width: 640px) {
  .bo-notif__menu,
  .bo-newfeat__menu,
  .bo-fav__menu,
  .bo-profile-chip__menu {
    position: fixed;
    left: 12px;
    right: 12px;
    top: 64px;
    width: auto;
    max-height: calc(100vh - 88px);
  }
}

/* Header on narrow phones: the bar wraps into up to 4 stacked rows
   (toggle+brand / search / fav+newfeat+notif / log-out) since every
   item keeps its full-size desktop footprint — that's a lot of chrome
   to scroll past before any page content is visible. Trim what's safe
   to trim: drop the username from "Log out (username)" (an arbitrarily
   long username had no shrink/truncate safeguard here at all) and let
   the search box shrink instead of holding a fixed 150px. */
@media (max-width: 480px) {
  .btn-header-back__user { display: none; }
  .bo-nav__search input[type="search"] { width: 100%; min-width: 0; }
  .bo-nav__search { flex: 1 1 140px; }
}

/* — real, interactive GST filing checklist (period-scoped) — */
.bo-checklist { list-style: none; padding: 0; margin: 12px 0; }
.bo-checklist li { display: flex; align-items: flex-start; gap: 10px; padding: 8px 0; border-bottom: 1px solid color-mix(in srgb, var(--color-text) 8.2%, transparent); font-size: 14px; }
.bo-checklist li:last-child { border-bottom: none; }
.bo-checklist input[type="checkbox"] { margin-top: 3px; width: 16px; height: 16px; flex-shrink: 0; cursor: pointer; }
.bo-checklist .step-label.is-done { text-decoration: line-through; color: color-mix(in srgb, var(--color-text) 50.2%, transparent); }
.bo-checklist .step-meta { display: block; font-size: 12px; color: color-mix(in srgb, var(--color-text) 60%, transparent); margin-top: 2px; }

.bo-signatory-preview { display: flex; align-items: center; gap: 12px; padding: 10px 12px; background: #f6f7fb; border: 1px solid color-mix(in srgb, var(--color-text) 12.5%, transparent); font-size: 13px; margin-bottom: 12px; }
.bo-signatory-preview img { height: 36px; max-width: 100px; object-fit: contain; background: #fff; border: 1px solid color-mix(in srgb, var(--color-text) 12.5%, transparent); padding: 2px; }

/* — Document Library: small thumbnail for an image-type document, in place of the plain filename a PDF/Excel/Word/CSV row gets — */
.bo-doc-thumb { height: 40px; width: 40px; object-fit: cover; border: 1px solid color-mix(in srgb, var(--color-text) 12.5%, transparent); border-radius: 4px; background: #fff; display: block; }

/* — Multisheet: workbook parse summary card — */
.ms-summary { display: none; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 10px; margin-top: 12px; padding: 12px; background: color-mix(in srgb, var(--color-text) 3.9%, transparent); }
.ms-summary__item { display: flex; flex-direction: column; gap: 2px; font-size: 13px; }
.ms-summary__label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: color-mix(in srgb, var(--color-text) 60%, transparent); }

/* — Multisheet: editable spreadsheet grid on multisheet-view.php — */
.ms-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 14px 0; }
.ms-toolbar .group { display: flex; align-items: center; gap: 6px; }
.ms-toolbar select, .ms-toolbar input[type="search"] { padding: 7px 10px; border: 1px solid color-mix(in srgb, var(--color-text) 16.1%, transparent); background: var(--color-card-bg); font-size: 13px; font-family: inherit; }
.ms-toolbar .spacer { flex: 1 1 auto; }
.ms-dirty-dot { display: none; width: 8px; height: 8px; border-radius: 50%; background: var(--color-red, #c0392b); margin-left: 6px; vertical-align: middle; }
.ms-dirty-dot.is-visible { display: inline-block; }

.ms-grid-wrap { overflow: auto; max-height: 70vh; border: 1px solid color-mix(in srgb, var(--color-text) 16.1%, transparent); }
.ms-grid { width: 100%; border-collapse: collapse; font-size: 13px; }
.ms-grid th, .ms-grid td { border: 1px solid color-mix(in srgb, var(--color-text) 12.5%, transparent); padding: 0; white-space: nowrap; }
.ms-grid thead th { background: color-mix(in srgb, var(--color-text) 5.9%, transparent); position: sticky; top: 0; z-index: 2; padding: 6px 8px; font-size: 11px; text-transform: none; text-align: left; }
.ms-grid thead th .ms-colhead { display: flex; align-items: center; gap: 4px; cursor: pointer; user-select: none; }
.ms-grid thead th .ms-colhead .caret { opacity: .5; font-size: 10px; }
.ms-grid thead th .ms-col-del { border: none; background: none; cursor: pointer; color: color-mix(in srgb, var(--color-text) 60%, transparent); font-size: 13px; line-height: 1; padding: 2px 4px; }
.ms-grid thead th .ms-col-del:hover { color: var(--color-red, #c0392b); }
.ms-grid thead tr.ms-filter-row th { position: sticky; top: 27px; background: var(--color-card-bg); padding: 4px 6px; z-index: 1; }
.ms-grid thead tr.ms-filter-row input { width: 100%; box-sizing: border-box; padding: 4px 6px; border: 1px solid color-mix(in srgb, var(--color-text) 16.1%, transparent); font-size: 12px; font-family: inherit; }
.ms-grid td { vertical-align: top; }
.ms-grid td .ms-cell { display: block; padding: 6px 8px; min-width: 60px; outline: none; white-space: pre-wrap; word-break: break-word; }
.ms-grid td .ms-cell:focus { background: var(--color-accent-100, #e8edff); }
.ms-grid td .ms-cell.is-invalid { outline: 2px solid var(--color-red, #c0392b); outline-offset: -2px; background: #fdeceb; }
.ms-grid td.ms-rownum-cell { background: color-mix(in srgb, var(--color-text) 3.9%, transparent); color: color-mix(in srgb, var(--color-text) 60%, transparent); text-align: right; padding: 6px 8px; font-size: 12px; white-space: nowrap; }
.ms-grid td.ms-rowdel-cell { text-align: center; padding: 4px; }
.ms-grid td.ms-rowdel-cell button { border: none; background: none; cursor: pointer; color: color-mix(in srgb, var(--color-text) 60%, transparent); font-size: 13px; }
.ms-grid td.ms-rowdel-cell button:hover { color: var(--color-red, #c0392b); }
.ms-grid tbody tr.is-hidden { display: none; }

.ms-statusbar { display: flex; flex-wrap: wrap; gap: 16px; align-items: center; margin-top: 10px; padding: 8px 12px; background: color-mix(in srgb, var(--color-text) 3.9%, transparent); font-size: 12px; color: color-mix(in srgb, var(--color-text) 60%, transparent); }
.ms-statusbar strong { color: var(--color-text); }

@media (max-width: 640px) {
  .ms-grid-wrap { max-height: 60vh; }
}

/* — Multisheet's own two-pane shell (upload + sheet list on the left,
   content on the right) — restyled from the original prototype's
   aside/section layout (pv1/modules/multisheet/multisheet.html), kept
   visually familiar but rebuilt on this app's real tokens/components
   and, unlike the prototype, backed by multisheet.php's actual
   database persistence rather than an in-memory JS object. — */
.ms-shell { display: flex; align-items: flex-start; gap: 20px; margin-top: 4px; }
.ms-aside {
  flex: 0 0 260px; width: 260px; background: var(--color-bg, #fff);
  border: 1px solid var(--color-divider); border-radius: 10px; padding: 16px;
}
.ms-aside h3 { margin: 0 0 12px; font-size: 16px; color: var(--color-accent-700); }
.ms-aside .bo-meta { margin: 0 0 6px; }

.ms-file-upload { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; }
.ms-file-upload input[type="file"] { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0); }
.ms-file-label {
  display: inline-flex; align-items: center; gap: 6px; padding: 8px 14px;
  border-radius: 6px; font-weight: 600; font-size: 13px; cursor: pointer;
  background: var(--color-accent); color: #fff; transition: background .15s ease;
}
.ms-file-label:hover { background: var(--color-accent-600); }
.ms-file-name { font-size: 12.5px; color: var(--color-text); opacity: .7; word-break: break-all; }

.ms-aside-actions { display: flex; flex-direction: column; gap: 8px; margin-top: 14px; }

.ms-sheet-list { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.ms-sheet-list__empty { font-size: 13px; color: var(--color-text); opacity: .6; margin: 4px 0; }
.ms-sheet-list__item {
  display: flex; align-items: center; gap: 6px; border-radius: 6px;
}
.ms-sheet-list__item:hover { background: var(--color-accent-100); }
.ms-sheet-list__link {
  flex: 1 1 auto; min-width: 0; padding: 8px 8px; font-size: 13.5px;
  color: var(--color-text) !important; text-decoration: none !important;
}
.ms-sheet-list__link:hover { color: var(--color-accent-700) !important; }
.ms-sheet-list__link .ms-sheet-list__count { display: block; font-size: 11.5px; opacity: .6; }
.ms-sheet-list__delete {
  flex: 0 0 auto; border: 0; background: none; cursor: pointer; color: color-mix(in srgb, var(--color-text) 60%, transparent);
  font-size: 15px; line-height: 1; padding: 4px 8px;
}
.ms-sheet-list__delete:hover { color: var(--color-red); }

.ms-content { flex: 1 1 auto; min-width: 0; }

@media (max-width: 900px) {
  .ms-shell { display: block; }
  .ms-aside { width: auto; margin-bottom: 20px; }
}

/* — Common Report Framework: the shared branded print template
   (inc/report_template.php + assets/js/report-print.js). Hidden on
   screen; the ONLY thing visible when printReport() calls
   window.print(), regardless of which page/module triggered it. — */
.report-print-root { display: none; }
@media print {
  body > *:not(#reportPrintRoot) { display: none !important; }
  #reportPrintRoot.report-print-root {
    display: block !important;
    font-family: var(--font-body, Arial, sans-serif);
    color: #1b2140;
    padding: 0;
  }
  @page { margin: 16mm 14mm; }

  .report-print__header {
    display: flex; justify-content: space-between; align-items: flex-start;
    border-bottom: 2px solid #1b2140; padding-bottom: 12px; margin-bottom: 16px;
  }
  .report-print__brand { display: flex; align-items: center; gap: 10px; }
  .report-print__logo { height: 40px; width: auto; }
  .report-print__company { font-size: 17px; font-weight: 700; }
  .report-print__tagline { font-size: 11px; color: #1b2140b3; }
  .report-print__meta { text-align: right; }
  .report-print__title { font-size: 15px; font-weight: 700; }
  .report-print__generated, .report-print__prepared-for { font-size: 11px; color: #1b2140b3; }
  .report-print__client-photo {
    width: 44px; height: 44px; border-radius: 50%; object-fit: cover;
    border: 1px solid #1b214029; margin-left: 12px; flex-shrink: 0;
  }
  .report-print__signature { max-width: 160px; max-height: 50px; display: block; }

  .report-print__section { margin-bottom: 16px; page-break-inside: avoid; }
  .report-print__section h3 {
    font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em;
    border-bottom: 1px solid #1b214029; padding-bottom: 4px; margin: 0 0 8px;
  }
  .report-print__section ul { margin: 0; padding-left: 18px; font-size: 13px; }
  .report-print__result { font-size: 18px; font-weight: 700; }
  .report-print__table { width: 100%; border-collapse: collapse; font-size: 11px; }
  .report-print__table th, .report-print__table td { border: 1px solid #1b214029; padding: 5px 8px; text-align: left; }
  .report-print__table th { background: #1b21400f; }
  .report-print__charts { display: flex; flex-direction: column; gap: 14px; }
  .report-print__chart-figure { margin: 0; page-break-inside: avoid; }
  .report-print__chart-figure figcaption { font-size: 11px; font-weight: 600; color: #1b2140b3; margin-bottom: 4px; }
  .report-print__chart-figure img { max-width: 100%; border: 1px solid #1b214029; }

  .report-print__disclaimer {
    font-size: 10px; color: #1b2140b3; border-top: 1px solid #1b214029;
    padding-top: 8px; margin-bottom: 12px; font-style: italic;
  }
  .report-print__regulatory {
    font-size: 10px; color: #1b2140b3; margin-bottom: 12px;
  }
  .report-print__footer {
    font-size: 10px; color: #1b2140b3; border-top: 2px solid #1b2140;
    padding-top: 8px; display: flex; justify-content: space-between; gap: 16px;
  }
  .report-print__footer-legal { white-space: nowrap; }
}
