/* =============================================================
   mc-polish.css
   Atmospheric layer for the WPPBX Management Console, matching the
   ambient look of the Reseller Portal and partners.wppbx.com:
   floating gradient orbs, particle mesh, cursor spotlight, Inter/
   Space Grotesk on headings, scroll-reveal, active sub-tab shimmer,
   session-timer strip polish.

   Loaded LAST in mc_base.html so it wins where it overlaps.

   Scope: chrome only. Explicitly does NOT touch:
     - MC tables (.data-table)
     - MC cards (.section-card, .item-card)
     - MC forms / inputs (.field-input, .field-select)
     - MC buttons (.act-btn, .wpbx-btn-*)
     - MC modals, Bootstrap components, badges
   ============================================================= */

/* -------- fonts -------- */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Space+Grotesk:wght@500;600;700&display=swap');

:root {
  --pp-font-display: 'Space Grotesk', 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  --pp-y-glow: rgba(var(--brand-primary-rgb),0.35);
  --pp-ease: cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* Headings get the display face; body copy stays Inter. Base body
   font-family is declared weakly so per-page styles can still override. */
html, body {
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
}
h1, h2, h3, h4, h5, h6,
.wpbx-brand, .brand-logo, .brand-name {
  font-family: var(--pp-font-display);
  letter-spacing: -0.015em;
}

/* -------- scroll reveals -------- */
.reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.8s var(--pp-ease), transform 0.8s var(--pp-ease);
}
.reveal.in {
  opacity: 1;
  transform: translateY(0);
}

/* -------- reduced motion -------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.05s !important;
  }
}

/* ============================================================
   NAVBAR + SESSION TIMER wow-factor polish
   Upgrades the existing MC navbar: group buttons, tab buttons,
   active-tab indicator, and session-timeout strip. Layered on top
   of the inline styles in mc_base.html, so the default styles
   still render if this file fails to load.
   ============================================================ */

/* -------- navbar container: positioning anchor only.
   Per user feedback the brand-coloured underline beneath the entire navbar
   was visually competing with the active-tab shimmer; both the 2px solid
   border-bottom (was on .wpbx-navbar inline) and this gradient ::after have
   been removed. Sub-tab shimmer is now the only animated chrome cue. */
.wpbx-navbar,
.mc-navbar {
  position: relative;
}

/* -------- group buttons: OVERVIEW / ORGANIZATION / DIALING PLAN / etc.
   Ported directly from portal_base.html .nav-group-btn so MC chrome
   matches the Reseller Portal: full-width tab row, light-gray inactive
   text, brand-primary active state with bottom-border + gradient bg,
   and a running shimmer line under the active group (ppTabShimmer). */
.nav-groups-row {
  display: flex !important;
  align-items: stretch !important;
  justify-content: stretch !important;
  padding: 0 !important;
  background: linear-gradient(180deg, #0d1117 0%, #0a0e13 100%) !important;
  border-bottom: 1px solid #2d333b !important;
  overflow-x: auto;
  scrollbar-width: none;
  box-shadow: none !important;
}
.nav-groups-row::-webkit-scrollbar { display: none; }
.nav-group-btn {
  position: relative;
  flex: 1 1 0 !important;
  min-width: 0 !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  gap: 0.5rem !important;
  padding: 0.85rem 0.6rem !important;
  margin: 0 !important;
  font-family: inherit !important;
  font-size: 0.88rem !important;
  font-weight: 600 !important;
  letter-spacing: 0.01em !important;
  text-transform: none !important;
  color: #c9d1d9 !important;
  background: none !important;
  border: none !important;
  border-bottom: 2px solid transparent !important;
  border-radius: 0 !important;
  white-space: nowrap;
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.nav-group-btn i {
  font-size: 1rem !important;
  opacity: 0.85;
}
.nav-group-btn:hover {
  color: var(--brand-primary) !important;
  background: rgba(var(--brand-primary-rgb), 0.04) !important;
}
.nav-group-btn.active {
  color: var(--brand-primary) !important;
  border-bottom-color: var(--brand-primary) !important;
  background: linear-gradient(180deg, rgba(var(--brand-primary-rgb),0.08) 0%, rgba(var(--brand-primary-rgb),0.03) 100%) !important;
  box-shadow: none !important;
}
.nav-group-btn.active i { opacity: 1; }

/* Vertical fading divider between buttons — matches the portal's
   .nav-group-btn::after rule. */
.nav-group-btn::after {
  content: "";
  position: absolute;
  right: 0; top: 22%; bottom: 22%;
  width: 1px;
  background: linear-gradient(to bottom,
    transparent 0%,
    rgba(var(--brand-primary-rgb),0.18) 35%,
    rgba(var(--brand-primary-rgb),0.18) 65%,
    transparent 100%);
  pointer-events: none;
}
.nav-group-btn:last-child::after { display: none; }

/* The active group uses just the static brand-primary bottom border for its
   indicator — the running shimmer line is reserved for the sub-tab row, so
   the two nav levels read as distinct. (Matches the portal where group btns
   are static and only sub-tabs animate.) */

/* Legacy <div class="nav-group-sep"> separators are replaced by the
   ::after dividers above; hide the markup to avoid double-rendering. */
.nav-group-sep { display: none !important; }

/* -------- tabs: resting + hover + active
   MC has no wizard sub-tabs (.sub-tab-wizard doesn't exist), so the
   portal's `:not(.sub-tab-wizard)` guards are dropped and the rules
   apply to all .sub-tab elements directly. */
.sub-tab {
  position: relative;
  border-bottom: 2px solid transparent !important;
  transition:
    color 0.22s var(--pp-ease),
    background 0.22s var(--pp-ease),
    transform 0.22s var(--pp-ease);
  border-radius: 6px 6px 0 0;
  overflow: visible !important;
}
.sub-tab i {
  transition: transform 0.22s var(--pp-ease), color 0.22s var(--pp-ease);
  font-size: 0.95rem;
}

/* hover: soft yellow wash + icon lift */
.sub-tab:hover {
  color: var(--brand-primary) !important;
  background: linear-gradient(180deg, rgba(var(--brand-primary-rgb),0.08), rgba(var(--brand-primary-rgb),0.02) 70%, transparent);
}
.sub-tab:hover i {
  transform: translateY(-1px) scale(1.08);
}

/* active tab: shimmering gradient underline + subtle halo. !important on the
   background is needed because mc_base.html's legacy inline .sub-tab.active
   rule (no !important, but later in source order) was setting a strong
   rgba(brand,0.06) pill bg that overrode this gentle gradient. */
.sub-tab.active {
  color: var(--brand-primary) !important;
  border-bottom-color: transparent !important;
  background: linear-gradient(180deg, rgba(var(--brand-primary-rgb),0.10), transparent 85%) !important;
  text-shadow: 0 0 16px rgba(var(--brand-primary-rgb),0.35);
}
.sub-tab.active i {
  color: var(--brand-primary);
  filter: drop-shadow(0 0 6px rgba(var(--brand-primary-rgb),0.55));
}
/* bottom: 1px keeps the shimmer INSIDE the tab — bottom: -2px puts it
   under the tab, which is then clipped by .nav-subtabs-row's overflow-x:auto
   (which implicitly clips overflow-y too). Matches portal-polish.css. */
/* Active sub-tab shimmer — ported verbatim from portal-polish.css.
   Sits at bottom: 1px (inside the tab so .nav-subtabs-row's overflow can't
   clip it). Animated by the shared ppTabShimmer keyframes. */
.sub-tab.active::after {
  content: "";
  position: absolute;
  left: 8%; right: 8%;
  bottom: 1px;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(
    90deg,
    rgba(var(--brand-primary-rgb),0)   0%,
    var(--brand-primary)            25%,
    var(--brand-primary)            50%,
    var(--brand-primary)            75%,
    rgba(var(--brand-primary-rgb),0) 100%
  );
  background-size: 200% 100%;
  animation: ppTabShimmer 3s linear infinite;
  box-shadow: 0 0 10px rgba(var(--brand-primary-rgb),0.6);
  pointer-events: none;
  z-index: 3;
}
@keyframes ppTabShimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: 0% 0; }
}

/* Click feedback */
.sub-tab:active {
  transform: translateY(1px);
}

/* -------- SESSION TIMEOUT indicator upgrade --------
   MC and portal both use the SAME .inactivity-timer-bar markup, so this
   block is ported 1:1 from portal-polish.css. Per the latest feedback the
   bar's moving shimmer and the LED-dot pulse are both omitted - keep the
   static gradient, glow, tick-marks, and state colours only; the bar has
   no motion. */
.session-timer-strip {
  height: 22px !important;
  background:
    linear-gradient(180deg, #12161c 0%, #0d1117 100%) !important;
  border-bottom: 1px solid rgba(var(--brand-primary-rgb),0.08) !important;
  position: relative !important;
  z-index: 3 !important;
}

/* Tick-marks along the strip for a "countdown runway" vibe */
.session-timer-strip::before {
  content: "";
  position: absolute; inset: 0;
  background-image: repeating-linear-gradient(
    90deg,
    transparent 0, transparent 59px,
    rgba(var(--brand-primary-rgb),0.08) 59px, rgba(var(--brand-primary-rgb),0.08) 60px
  );
  pointer-events: none;
  opacity: 0.8;
}

/* Progress bar: brand-driven gradient (mirrors portal-polish.css). All three
   stops use --brand-primary-rgb so the bar takes the tenant's brand colour
   instead of the historical WPPBX amber. Warn/critical states below keep
   amber/red - those are semantic, not chrome. */
.inactivity-timer-bar {
  background: linear-gradient(
    90deg,
    rgba(var(--brand-primary-rgb),0.38) 0%,
    rgba(var(--brand-primary-rgb),0.42) 55%,
    rgba(var(--brand-primary-rgb),0.48) 100%
  ) !important;
  border-right: 1px solid rgba(var(--brand-primary-rgb),0.6);
  box-shadow:
    0 0 16px rgba(var(--brand-primary-rgb),0.3),
    inset 0 1px 0 rgba(255,255,255,0.12);
  position: absolute !important;
  overflow: hidden;
}
/* Shimmer streak on the bar intentionally omitted (motion removed). */

/* Label: clean typography + static LED dot (no pulse animation) */
.session-timer-label {
  right: 0.85rem !important;
  font-family: var(--pp-font-display);
  font-size: 0.62rem !important;
  color: #c9d1d9 !important;
  letter-spacing: 0.14em !important;
  opacity: 0.88;
  display: flex !important;
  align-items: center;
  gap: 0.45rem;
}
.session-timer-label::before {
  content: "";
  width: 7px; height: 7px;
  border-radius: 50%;
  background: #7ee787;
  box-shadow: 0 0 0 2px rgba(126,231,135,0.22), 0 0 8px rgba(126,231,135,0.55);
  flex-shrink: 0;
  /* Intentionally NO animation here - latest user feedback: no motion on LED */
}

/* When time is low (<= 25%), the label LED turns amber; <=10% red. Driven
   by data-state attribute the MC JS already exposes (if it does not,
   default green still works). */
.session-timer-strip[data-state="warn"] .session-timer-label::before {
  background: #ffc107;
  box-shadow: 0 0 0 2px rgba(255,193,7,0.22), 0 0 8px rgba(255,193,7,0.55);
}
.session-timer-strip[data-state="critical"] .session-timer-label::before {
  background: #ff6b6b;
  box-shadow: 0 0 0 2px rgba(255,107,107,0.22), 0 0 10px rgba(255,107,107,0.65);
}
.session-timer-strip[data-state="warn"] .inactivity-timer-bar {
  background: linear-gradient(90deg, rgba(255,193,7,0.45), rgba(255,154,0,0.5)) !important;
  box-shadow: 0 0 18px rgba(255,193,7,0.35), inset 0 1px 0 rgba(255,255,255,0.12);
}
.session-timer-strip[data-state="critical"] .inactivity-timer-bar {
  background: linear-gradient(90deg, rgba(255,107,107,0.5), rgba(218,54,51,0.55)) !important;
  box-shadow: 0 0 22px rgba(255,107,107,0.5), inset 0 1px 0 rgba(255,255,255,0.12);
}

/* -------- Inactivity selector dropdown: tighter polish -------- */
.inactivity-selector {
  background: rgba(26,30,36,0.7) !important;
  backdrop-filter: blur(8px);
  border: 1px solid rgba(255,255,255,0.06) !important;
  transition: border-color 0.2s var(--pp-ease), background 0.2s var(--pp-ease);
}
.inactivity-selector:hover {
  border-color: rgba(var(--brand-primary-rgb),0.4) !important;
  background: rgba(26,30,36,0.9) !important;
}

/* ──────────────────────────────────────────────────────────────────────
   Extension presence badge - state indicator (available / ringing /
   on a call / away / dnd / offline / unknown) driven by the engine
   presence poll. "unknown" means the engine could not be asked; it must
   never be rendered as offline.
   ────────────────────────────────────────────────────────────────────── */
.ext-presence {
  display: inline-flex; align-items: center; gap: 0.35rem;
  padding: 0.2rem 0.55rem;
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-radius: 4px;
  border: 1px solid transparent;
  white-space: nowrap;
}
.ext-presence-dot {
  display: inline-block;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: currentColor;
}
.ext-presence-available { color: #3fb950; background: rgba(63,185,80,0.10); border-color: rgba(63,185,80,0.35); }
.ext-presence-ringing   { color: #ffc107; background: rgba(255,193,7,0.10); border-color: rgba(255,193,7,0.40); }
.ext-presence-oncall    { color: #f85149; background: rgba(248,81,73,0.10); border-color: rgba(248,81,73,0.40); }
.ext-presence-away      { color: #ffa657; background: rgba(255,166,87,0.10); border-color: rgba(255,166,87,0.35); }
.ext-presence-dnd       { color: #f85149; background: rgba(248,81,73,0.10); border-color: rgba(248,81,73,0.40); }
.ext-presence-offline   { color: #6e7681; background: rgba(110,118,129,0.10); border-color: rgba(110,118,129,0.30); }
/* Deliberately NOT offline's solid grey. A dashed border and a hollow dot
   read as "no information" rather than "the phone is off", which is the
   whole point: these two states must never be confused at a glance. */
.ext-presence-unknown   { color: #8b93a7; background: rgba(139,147,167,0.08); border-color: rgba(139,147,167,0.45); border-style: dashed; }
.ext-presence-unknown .ext-presence-dot { background: transparent; box-shadow: inset 0 0 0 1.5px currentColor; }

.ext-presence.pulse .ext-presence-dot {
  animation: ext-presence-pulse 1.2s ease-in-out infinite;
}
@keyframes ext-presence-pulse {
  0%   { box-shadow: 0 0 0 0 currentColor; opacity: 1;   }
  70%  { box-shadow: 0 0 0 5px transparent; opacity: 0.55; }
  100% { box-shadow: 0 0 0 0 transparent;  opacity: 1;   }
}

/* ──────────────────────────────────────────────────────────────────────
   Extension avatar (32px, shows user's uploaded profile picture or a
   coloured initial fallback). Used in the Extensions card view and in
   any row that renders _avatarHtml().
   ────────────────────────────────────────────────────────────────────── */
.ext-avatar {
  position: relative;
  display: inline-flex;
  width: 32px; height: 32px;
  border-radius: 50%;
  background: linear-gradient(135deg, #1a1f27, #0d1117);
  border: 1px solid #30363d;
  align-items: center; justify-content: center;
  margin-right: 10px;
  vertical-align: middle;
  overflow: hidden;
  flex-shrink: 0;
}
.ext-avatar-init {
  color: var(--brand-primary);
  font-family: 'Space Grotesk', Inter, sans-serif;
  font-weight: 700;
  font-size: 0.88rem;
}
.ext-avatar img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  border-radius: 50%;
}

/* The settings sheet prints each phone maker's OWN field wording, so it has to
   show that wording the way the phone spells it. The console uppercases field
   labels everywhere else, which would turn "Register Name" into "REGISTER NAME"
   and quietly undercut the one thing this screen is for. Scoped to the sheet,
   so the rest of the console keeps its house style. */
#msLines label.field-label,
#msLines .ext-section-label {
  text-transform: none;
  letter-spacing: normal;
}
