/* app-shell-classic.css - the Classic template's page shell: topbar, sidebars,
   content pane, footer, preloader. Loaded by the Classic shell only. */
/* ---------------------------------------------------------------------
   Dashboard shell
   --------------------------------------------------------------------- */
.app-topbar {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: var(--topbar-height);
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 20px;
  z-index: 100;
  box-shadow: var(--shadow);
}
.app-topbar .brand {
  font-weight: 800;
  font-size: 18px;
  letter-spacing: -0.01em;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  text-decoration: none;
  cursor: pointer;
}
.app-topbar .brand .header-brand-logo { height: 28px; width: auto; display: block; }
.app-topbar .brand .header-brand-text {
  background: linear-gradient(135deg, var(--color-primary) 0%, #8f6bff 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.app-topbar .brand:hover { text-decoration: none; opacity: 0.85; }
.app-topbar .user-menu { display: flex; align-items: center; gap: 10px; font-size: 14px; }
.live-stats-bar { display: flex; align-items: center; gap: 18px; font-size: 13px; color: var(--color-muted); }
.live-stats-bar .live-stat { display: flex; align-items: center; gap: 5px; white-space: nowrap; }
.live-stats-bar .live-stat svg { width: 14px; height: 14px; flex-shrink: 0; }
.live-stats-bar .live-stat-value { font-weight: 700; color: var(--color-text); font-variant-numeric: tabular-nums; }
/* (removed: the counters moved out of the header - see render_live_stats_html()) */
.app-topbar .nav-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  background: none;
  border: none;
  border-radius: var(--radius);
  font-size: 20px;
  cursor: pointer;
  color: var(--color-text);
  transition: background 0.15s ease;
}
.app-topbar .nav-toggle:hover { background: var(--color-surface-alt); }

.theme-toggle .icon-light { display: none; }
html[data-theme="dark"] .theme-toggle .icon-dark { display: none; }
html[data-theme="dark"] .theme-toggle .icon-light { display: inline; }

/* ---------------------------------------------------------------------
   Sidebar collapse handles - small tabs anchored to each sidebar's
   outer edge (not inside the sidebar itself, so they stay reachable
   even when the sidebar is fully collapsed off-screen).
   --------------------------------------------------------------------- */
.sidebar-handle {
  position: fixed;
  top: calc(var(--topbar-height) + 14px);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 40px;
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-muted);
  cursor: pointer;
  font-size: 12px;
  z-index: 95;
  transition: left 0.2s ease, right 0.2s ease, background 0.15s ease, color 0.15s ease;
}
.sidebar-handle:hover { background: var(--color-surface-alt); color: var(--color-text); }

.sidebar-handle-left {
  left: 0;
  border-radius: 0 999px 999px 0;
  border-left: none;
}
body.left-open .sidebar-handle-left { left: var(--sidebar-width); }
body.left-open .sidebar-handle-left::before { content: '\2039'; }
.sidebar-handle-left::before { content: '\203A'; }

.sidebar-handle-right {
  right: 0;
  border-radius: 999px 0 0 999px;
  border-right: none;
}
body.right-open .sidebar-handle-right { right: var(--sidebar-width); }
body.right-open .sidebar-handle-right::before { content: '\203A'; }
.sidebar-handle-right::before { content: '\2039'; }

@media (max-width: 800px) {
  .sidebar-handle { top: calc(var(--topbar-height) + 10px); }
}

.app-sidebar {
  position: fixed;
  top: var(--topbar-height);
  bottom: 28px;
  left: 0;
  width: var(--sidebar-width);
  background: var(--color-surface);
  border-right: 1px solid var(--color-border);
  overflow-y: auto;
  transform: translateX(-100%);
  transition: transform 0.2s ease, background 0.2s ease;
  z-index: 90;
}
.app-sidebar.open { transform: translateX(0); box-shadow: var(--shadow-lg); }
/* Same effect as .open, but keyed off <body>'s class instead of the
   sidebar's own - set synchronously before first paint (see the inline
   script right after <body> in includes/layout.php) so the sidebar is
   already in its final position on first paint, with no slide-in flash. */
body.left-open .app-sidebar:not(.app-sidebar-right) { transform: translateX(0); box-shadow: var(--shadow-lg); }
body.right-open .app-sidebar-right { transform: translateX(0); box-shadow: var(--shadow-lg); }
.app-sidebar nav { padding: 10px; }
.app-sidebar nav a {
  display: block;
  padding: 10px 14px;
  margin-bottom: 2px;
  border-radius: var(--radius);
  color: var(--color-muted);
  font-size: 14px;
  font-weight: 500;
  border-left: none;
  transition: background 0.15s ease, color 0.15s ease;
}
.app-sidebar nav a:hover { background: var(--color-surface-alt); color: var(--color-text); text-decoration: none; }
.app-sidebar nav a.active {
  color: var(--color-primary);
  font-weight: 700;
  background: var(--color-primary-soft);
}

.app-sidebar-right {
  left: auto;
  right: 0;
  border-right: none;
  border-left: 1px solid var(--color-border);
  transform: translateX(100%);
}
.app-sidebar-heading {
  padding: 16px 18px 6px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-muted);
}
/* Sub-groups within the admin sidebar's own nav (see includes/layout.php)
   - a small uppercase label (same look as .app-sidebar-heading, just
   tighter/nested one level in) above each related cluster of links, with
   a thin divider before every group after the first so the whole menu
   reads as clearly separated sections rather than one long flat list. */
.app-nav-group + .app-nav-group {
  margin-top: 6px;
  padding-top: 10px;
  border-top: 1px solid var(--color-border);
}
.app-nav-group-heading {
  padding: 2px 14px 6px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-muted);
  opacity: 0.7;
}

/* Dynamic menu manager (see includes/menu.php + menu_manager.php): a
   non-clickable "submenu" menu item - expands its children when clicked
   (JS toggles .open, see includes/layout.php's inline script) OR simply
   hovered (pure CSS, no JS needed for that half). */
.app-nav-submenu-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 10px 14px;
  margin-bottom: 2px;
  border-radius: var(--radius);
  color: var(--color-muted);
  font-size: 14px;
  font-weight: 500;
  background: none;
  border: none;
  text-align: left;
  cursor: pointer;
  font-family: inherit;
}
.app-nav-submenu-toggle:hover { background: var(--color-surface-alt); color: var(--color-text); }
.app-nav-submenu-arrow { transition: transform 0.15s ease; font-size: 10px; margin-left: 6px; }
.app-nav-submenu.open > .app-nav-submenu-toggle .app-nav-submenu-arrow,
.app-nav-submenu:hover > .app-nav-submenu-toggle .app-nav-submenu-arrow { transform: rotate(180deg); }
.app-nav-submenu-children {
  display: none;
  padding-left: 14px;
  border-left: 2px solid var(--color-border);
  margin: 0 0 4px 20px;
}
.app-nav-submenu.open > .app-nav-submenu-children,
.app-nav-submenu:hover > .app-nav-submenu-children { display: block; }

/* Admin-only visual marker for a menu item an admin has hidden from
   everyone else (users/team managers) - the admin themselves still sees
   it (with this dimmed/badged look) since is_visible never blocks an
   actual admin, only enforce_menu_visibility()'s page-level check does
   for non-admins. */
.nav-item-hidden { opacity: 0.55; }
.nav-item-hidden-badge { margin-left: 6px; font-size: 10px; opacity: 0.8; }


.app-content {
  position: fixed;
  top: var(--topbar-height);
  bottom: 28px;
  left: 0;
  right: 0;
  padding: 24px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  transition: left 0.2s ease, right 0.2s ease;
}
body.left-open .app-content { left: var(--sidebar-width); }
/* Only reserve room on the right for the admin sidebar when it actually
   exists (has-admin-sidebar, set on <body> only for admins) - otherwise
   "right-open" (the default state) left a permanent blank gap on the
   right edge for non-admin users, who never get an .app-sidebar-right
   rendered at all. */
body.has-admin-sidebar.right-open .app-content { right: var(--sidebar-width); }

.app-footer {
  position: fixed; left: 0; right: 0; bottom: 0; height: 28px; z-index: 50;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 0 16px; font-size: 11px; color: var(--color-muted);
  background: var(--color-surface); border-top: 1px solid var(--color-border);
}
.app-footer-version { color: var(--color-muted); font-weight: 700; }
.app-footer-version:hover { color: var(--color-primary); text-decoration: none; }

@media (max-width: 800px) {
  /* Sidebars are always an overlay on small screens, never push the content. */
  .app-content { left: 0 !important; right: 0 !important; }
}

/* ---------------------------------------------------------------------
   Fullscreen preloader - covers the whole page from the very first paint
   (see the inline <div> right after <body> in includes/layout.php) so
   the sidebar/content layout settling into place is never visible, then
   fades out once the page has fully loaded (assets/js/app.js).
   --------------------------------------------------------------------- */
#pagePreloader {
  position: fixed; inset: 0; z-index: 9999;
  display: flex; align-items: center; justify-content: center;
  background: var(--color-bg);
  opacity: 1; visibility: visible;
  transition: opacity 0.3s ease, visibility 0.3s ease;
}
#pagePreloader.hide { opacity: 0; visibility: hidden; pointer-events: none; }
.preloader-spinner {
  width: 46px; height: 46px; border-radius: 50%;
  border: 4px solid var(--color-border);
  border-top-color: var(--color-primary);
  animation: preloaderSpin 0.8s linear infinite;
}
@keyframes preloaderSpin { to { transform: rotate(360deg); } }

/* Admin-selectable alternative built-in preloader looks (App settings
   page) - see render_preloader_html() in includes/settings.php, which
   picks exactly one of these (or none, for a custom uploaded image). */
.preloader-dots { display: flex; gap: 10px; }
.preloader-dots span {
  width: 14px; height: 14px; border-radius: 50%; background: var(--color-primary);
  animation: preloaderDotBounce 1s ease-in-out infinite;
}
.preloader-dots span:nth-child(2) { animation-delay: 0.15s; }
.preloader-dots span:nth-child(3) { animation-delay: 0.3s; }
@keyframes preloaderDotBounce { 0%, 80%, 100% { transform: scale(0.6); opacity: 0.5; } 40% { transform: scale(1); opacity: 1; } }

.preloader-bars { display: flex; align-items: flex-end; gap: 6px; height: 42px; }
.preloader-bars span {
  width: 8px; height: 100%; background: var(--color-primary); border-radius: 3px;
  animation: preloaderBarStretch 1s ease-in-out infinite;
}
.preloader-bars span:nth-child(2) { animation-delay: 0.12s; }
.preloader-bars span:nth-child(3) { animation-delay: 0.24s; }
.preloader-bars span:nth-child(4) { animation-delay: 0.36s; }
@keyframes preloaderBarStretch { 0%, 100% { transform: scaleY(0.3); } 50% { transform: scaleY(1); } }

.preloader-pulse {
  width: 46px; height: 46px; border-radius: 50%; background: var(--color-primary);
  animation: preloaderPulse 1.2s ease-in-out infinite;
}
@keyframes preloaderPulse {
  0% { transform: scale(0.7); opacity: 1; }
  70% { transform: scale(1.3); opacity: 0; }
  100% { transform: scale(0.7); opacity: 0; }
}

.preloader-custom-img { max-width: 200px; max-height: 200px; }

/* Small inline spinner for use inside buttons/alert boxes (e.g. the
   "Creating droplet..." feedback on servers.php) - uses currentColor so
   it automatically matches whatever text color it's placed in, on any
   background, light or dark. */
.inline-spinner {
  display: inline-block; width: 13px; height: 13px; margin-right: 6px; vertical-align: -2px;
  border: 2px solid currentColor; border-top-color: transparent; border-radius: 50%;
  opacity: 0.85; animation: preloaderSpin 0.7s linear infinite;
}

/* Temporary template-preview toggle in the header (ui_preview_toggle_html()). */
.ui-preview-toggle { display: inline-flex; align-items: center; gap: 6px; }
.ui-preview-toggle svg { width: 14px; height: 14px; }
.ui-preview-toggle.is-on { border-color: #c9891a; color: #c9891a; }

/* Header template-preview dropdown (ui_preview_toggle_html()). */
.ui-preview-menu { position: relative; display: inline-block; }
.ui-preview-menu > summary { list-style: none; cursor: pointer; display: inline-flex; align-items: center; gap: 6px; user-select: none; }
.ui-preview-menu > summary::-webkit-details-marker { display: none; }
.ui-preview-menu .ui-preview-caret { width: 12px !important; height: 12px !important; opacity: 0.7; transition: transform 0.15s ease; }
.ui-preview-menu[open] .ui-preview-caret { transform: rotate(180deg); }
.ui-preview-list { position: absolute; right: 0; top: calc(100% + 6px); min-width: 190px; background: var(--color-surface); border: 1px solid var(--color-border); border-radius: 10px; box-shadow: var(--shadow-lg, 0 8px 24px rgba(0, 0, 0, 0.18)); padding: 6px; z-index: 1200; }
.ui-preview-item { display: block; padding: 7px 10px; border-radius: 6px; font-size: 13px; font-weight: 500; color: var(--color-text); text-decoration: none; white-space: nowrap; }
.ui-preview-item:hover { background: var(--color-surface-alt); color: var(--color-primary); }
.ui-preview-item.is-current { color: var(--color-muted); }
.ui-preview-item.is-current small { font-size: 11px; opacity: 0.8; margin-left: 4px; }
.ui-preview-item.is-exit { color: #a86f10; border-top: 1px solid var(--color-border); margin-top: 4px; padding-top: 9px; border-radius: 0 0 6px 6px; }

/* Bare pages (page_header(..., ['bare' => true]) - e.g. the Attribute
   Table companion window): no sidebars, content spans the full width. */
body.ui-bare .app-content { left: 0 !important; right: 0 !important; }

/* ---------------------------------------------------------------------
   Dark theme: menu hover/active states
   ---------------------------------------------------------------------
   In dark mode --color-surface-alt (hover) and --color-primary-soft
   (active) both sit a hair away from the panel behind them, so a hovered
   or selected menu item read as "very dark" - barely distinguishable
   from an idle one. These states use plain white overlays instead, which
   keep their contrast whatever the accent colour is, with an inset bar
   in the accent colour marking the active item and near-white text on
   both. Light mode is untouched.
   ------------------------------------------------------------------ */
html[data-theme="dark"] .app-sidebar nav a:hover { background: rgba(255, 255, 255, 0.1); color: #fff; }
html[data-theme="dark"] .app-sidebar nav a.active {
  background: rgba(255, 255, 255, 0.18);
  box-shadow: inset 3px 0 0 var(--color-primary);
  color: #fff;
}
html[data-theme="dark"] .app-nav-submenu-toggle:hover { background: rgba(255, 255, 255, 0.1); color: #fff; }

/* Live admin counters, now at the BOTTOM of the right admin sidebar
   (render_live_stats_html()) rather than in the header: a full-width
   stacked list with a label per row, pushed to the bottom of the panel
   and separated by a rule. */
.app-sidebar .live-stats-bar, .deppy-admin-sidebar .live-stats-bar,
.timis-admin-sidebar .live-stats-bar, .mary-admin-sidebar .live-stats-bar {
  display: flex; flex-direction: column; align-items: stretch; gap: 8px;
  margin-top: auto; padding: 12px 16px 14px;
  border-top: 1px solid var(--color-border); font-size: 12.5px;
}
.app-sidebar .live-stats-bar .live-stat, .deppy-admin-sidebar .live-stats-bar .live-stat,
.timis-admin-sidebar .live-stats-bar .live-stat, .mary-admin-sidebar .live-stats-bar .live-stat {
  display: flex; align-items: center; gap: 8px; white-space: nowrap;
}
.live-stat-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.app-sidebar .live-stats-bar .live-stat-value, .deppy-admin-sidebar .live-stats-bar .live-stat-value,
.timis-admin-sidebar .live-stats-bar .live-stat-value, .mary-admin-sidebar .live-stats-bar .live-stat-value {
  margin-left: auto; font-weight: 700; font-variant-numeric: tabular-nums;
}
/* The panel becomes a column so margin-top:auto can push the counters down. */

/* The admin panel is a fixed column: heading and counters stay put, the
   menu between them scrolls. The panel itself must NOT scroll, or the
   counters ride up out of view with a long menu tree. */
#adminSidebar { display: flex; flex-direction: column; overflow: hidden; }
#adminSidebar > .app-sidebar-heading, #adminSidebar > .deppy-admin-heading,
#adminSidebar > .timis-admin-heading, #adminSidebar > .mary-admin-heading { flex: 0 0 auto; }
#adminSidebar > #adminNav, #adminSidebar > .sidebar-links,
#adminSidebar > .timis-admin-links, #adminSidebar > .mary-admin-links {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  /* The bottom padding these lists carried was there to clear the fixed
     page footer; the counters below now do that job. */
  padding-bottom: 8px;
  /* Scrolls, but shows no scrollbar - the same treatment the sidebars
     themselves already use (scrollbar-width for Firefox, the
     ::-webkit-scrollbar rule below for Chrome/Safari/Edge). */
  scrollbar-width: none;
  -ms-overflow-style: none;
}
#adminSidebar > #adminNav::-webkit-scrollbar, #adminSidebar > .sidebar-links::-webkit-scrollbar,
#adminSidebar > .timis-admin-links::-webkit-scrollbar, #adminSidebar > .mary-admin-links::-webkit-scrollbar {
  width: 0; height: 0; display: none;
}
#adminSidebar > .live-stats-bar { flex: 0 0 auto; margin-top: 0; }

/* Brand text beside the logo: a notch smaller than the 18px brand block
   it sits in, and never wrapped. The rotating list (App settings, comma
   separated) swaps in longer names than the one the header was sized
   for, and a long one pushed the brand onto two lines. It truncates
   rather than growing, so the header buttons never get shoved. */
.header-brand-text {
  font-size: 15px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 220px; min-width: 0;
}
