- {/* Avatar */}
-
+
{initials}
- {/* Name + Role */}
-
-
- {displayName}
-
-
- {roleLabel} • Logout
-
+
+ {displayName}
+ {roleLabel} • Logout
-
+
diff --git a/src/config/navigation.ts b/src/config/navigation.ts
index 4254ed7..f023ffc 100644
--- a/src/config/navigation.ts
+++ b/src/config/navigation.ts
@@ -14,7 +14,10 @@ import {
PhoneCall,
Navigation,
ShoppingCart,
- LayoutGrid
+ LayoutGrid,
+ Video,
+ FileText,
+ TrendingUp
} from 'lucide-react';
export interface NavItem {
@@ -37,10 +40,10 @@ export const NAVIGATION_CONFIG: NavItem[] = [
},
{
id: 'overview',
- label: 'Admin Dashboard',
+ label: 'Dashboard',
icon: LayoutDashboard,
path: '/',
- roles: ['CURESELECT_ADMIN']
+ roles: ['CURESELECT_ADMIN', 'HOSPITAL_ADMIN']
},
{
id: 'incidents',
@@ -90,7 +93,18 @@ export const NAVIGATION_CONFIG: NavItem[] = [
label: 'Hospital Ops',
icon: Monitor,
path: '/hospital-console',
- roles: ['CURESELECT_ADMIN', 'HOSPITAL_ADMIN', 'ED_DOCTOR', 'COORDINATOR', 'EMT']
+ roles: ['CURESELECT_ADMIN', 'HOSPITAL_ADMIN', 'ED_DOCTOR', 'COORDINATOR', 'EMT'],
+ subItems: [
+ { id: 'hosp-ed', label: 'ED Monitor', icon: Monitor, path: '/hospital-console?tab=ED_MONITOR', roles: ['CURESELECT_ADMIN', 'HOSPITAL_ADMIN', 'ED_DOCTOR', 'COORDINATOR', 'EMT'] },
+ { id: 'hosp-bookings', label: 'Trip Management', icon: Activity, path: '/hospital-console?tab=BOOKINGS', roles: ['CURESELECT_ADMIN', 'HOSPITAL_ADMIN', 'ED_DOCTOR', 'COORDINATOR', 'EMT'] },
+ { id: 'hosp-fleet', label: 'Fleet Visibility', icon: Truck, path: '/hospital-console?tab=FLEET', roles: ['CURESELECT_ADMIN', 'HOSPITAL_ADMIN', 'ED_DOCTOR', 'COORDINATOR', 'EMT'] },
+ { id: 'hosp-telelink', label: 'TeleLink Hub', icon: Video, path: '/hospital-console?tab=TELELINK', roles: ['CURESELECT_ADMIN', 'HOSPITAL_ADMIN', 'ED_DOCTOR', 'COORDINATOR', 'EMT'] },
+ { id: 'hosp-epcr', label: 'ePCR Records', icon: FileText, path: '/hospital-console?tab=EPCR', roles: ['CURESELECT_ADMIN', 'HOSPITAL_ADMIN', 'ED_DOCTOR', 'COORDINATOR', 'EMT'] },
+ { id: 'hosp-history', label: 'Patient Archive', icon: Database, path: '/hospital-console?tab=HISTORY', roles: ['CURESELECT_ADMIN', 'HOSPITAL_ADMIN', 'ED_DOCTOR', 'COORDINATOR', 'EMT'] },
+ { id: 'hosp-reports', label: 'Analytics', icon: TrendingUp, path: '/hospital-console?tab=REPORTS', roles: ['CURESELECT_ADMIN', 'HOSPITAL_ADMIN', 'ED_DOCTOR', 'COORDINATOR', 'EMT'] },
+ { id: 'hosp-referrals', label: 'Referral Hub', icon: Hospital, path: '/hospital-console?tab=REFERRALS', roles: ['CURESELECT_ADMIN', 'HOSPITAL_ADMIN', 'ED_DOCTOR', 'COORDINATOR', 'EMT'] },
+ { id: 'hosp-setup', label: 'Account & Setup', icon: Settings, path: '/hospital-console?tab=SETUP', roles: ['CURESELECT_ADMIN', 'HOSPITAL_ADMIN', 'ED_DOCTOR', 'COORDINATOR', 'EMT'] },
+ ]
},
{
id: 'master-data',
diff --git a/src/index.css b/src/index.css
index b3f65de..f142a0f 100644
--- a/src/index.css
+++ b/src/index.css
@@ -1,19 +1,62 @@
-@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Space+Grotesk:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap');
+@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=Space+Grotesk:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap');
:root {
- --base-bg: #F8FAFC;
- --card-bg: #FFFFFF;
- --card-border: rgba(59, 130, 246, 0.15);
- --accent-cyan: #3B82F6;
- --accent-green: #10B981;
- --alert-red: #EF4444;
- --warning-amber: #F59E0B;
- --text-primary: #1E293B;
- --text-secondary: #64748B;
- --glass-bg: rgba(255, 255, 255, 0.8);
- --glass-blur: blur(12px);
+ /* --- HSL DESIGN TOKENS (PROFESSIONAL MEDICAL PALETTE) --- */
+ --hull-h: 220;
+ --hull-s: 16%;
+ --hull-l: 97%;
+
+ --hull-dark-h: 222;
+ --hull-dark-s: 47%;
+ --hull-dark-l: 11%;
+
+ /* Accents */
+ --accent-cyan-h: 199;
+ --accent-cyan-s: 89%;
+ --accent-cyan-l: 48%;
+
+ --accent-purple-h: 262;
+ --accent-purple-s: 83%;
+ --accent-purple-l: 58%;
+
+ --accent-green-h: 160;
+ --accent-green-s: 84%;
+ --accent-green-l: 39%;
+
+ /* Semantic Mappings */
+ --base-bg: #f8f9fb;
+ --card-bg: #ffffff;
+ --card-border: #e5e7eb;
+ --glass-bg: rgba(255, 255, 255, 0.6);
+
+ --accent-cyan: hsl(var(--accent-cyan-h), var(--accent-cyan-s), var(--accent-cyan-l));
+ --accent-cyan-soft: hsla(var(--accent-cyan-h), var(--accent-cyan-s), var(--accent-cyan-l), 0.07);
+ --accent-cyan-glow: hsla(var(--accent-cyan-h), var(--accent-cyan-s), var(--accent-cyan-l), 0.25);
+
+ --accent-purple: hsl(var(--accent-purple-h), var(--accent-purple-s), var(--accent-purple-l));
+ --accent-purple-soft: hsla(var(--accent-purple-h), var(--accent-purple-s), var(--accent-purple-l), 0.08);
+
+ --accent-green: hsl(var(--accent-green-h), var(--accent-green-s), var(--accent-green-l));
+ --accent-green-soft: hsla(var(--accent-green-h), var(--accent-green-s), var(--accent-green-l), 0.08);
+
+ --alert-red: hsl(4, 90%, 58%);
+ --warning-amber: hsl(38, 92%, 50%);
+
+ --text-primary: #1e293b;
+ --text-secondary: #64748b;
+ --text-muted: #94a3b8;
+
+ /* Effects */
+ --hull-glass: rgba(255, 255, 255, 0.85);
+ --glass-blur: blur(16px);
+ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.04);
+ --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.06);
+ --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.08);
+ --shadow-premium: 0 20px 40px -12px rgba(0, 0, 0, 0.08);
+ --transition-snappy: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
+
--sidebar-width: 260px;
- --topbar-height: 70px;
+ --topbar-height: 64px;
}
* {
@@ -23,16 +66,14 @@
}
body {
- font-family: 'Inter', sans-serif;
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
background-color: var(--base-bg);
- background-image:
- linear-gradient(rgba(59, 130, 246, 0.05) 1px, transparent 1px),
- linear-gradient(90deg, rgba(59, 130, 246, 0.05) 1px, transparent 1px);
- background-size: 40px 40px;
color: var(--text-primary);
height: 100vh;
overflow: hidden;
-webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ text-rendering: optimizeLegibility;
}
h1, h2, h3, h4 {
@@ -107,10 +148,17 @@ h1, h2, h3, h4 {
border-radius: 10px;
}
-/* Grid Layouts */
+/* 4K UI Limits Wrapper */
+.page-content-wrapper {
+ max-width: 1920px;
+ margin: 0 auto;
+ width: 100%;
+}
+
+/* Responsive Grid Layouts */
.stats-bar {
display: grid;
- grid-template-columns: repeat(6, 1fr);
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 16px;
margin-bottom: 24px;
}
@@ -119,13 +167,49 @@ h1, h2, h3, h4 {
display: grid;
grid-template-columns: 1fr 1.5fr 1fr;
gap: 24px;
- height: calc(100% - 140px);
+ height: auto;
+ min-height: calc(100% - 140px);
}
.main-grid > * {
min-width: 0;
}
+/* Responsive Breakpoints */
+@media (max-width: 1400px) {
+ .main-grid {
+ grid-template-columns: 1fr 1fr;
+ }
+ .main-grid > *:last-child {
+ grid-column: span 2;
+ }
+}
+
+@media (max-width: 1024px) {
+ :root {
+ --sidebar-width: 72px;
+ }
+ .sidebar-label {
+ display: none !important;
+ }
+ .main-grid {
+ grid-template-columns: 1fr;
+ }
+ .main-grid > *:last-child {
+ grid-column: span 1;
+ }
+}
+
+@media (max-width: 768px) {
+ .page-container {
+ padding: 16px;
+ }
+ .stats-bar {
+ grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
+ gap: 12px;
+ }
+}
+
/* Pulse Animation */
@keyframes pulse-red {
0% { transform: scale(1); opacity: 1; }
@@ -250,3 +334,214 @@ select, select option {
background-color: var(--card-bg);
}
+/* ═══════════════════════════════════════════════════════════════════════════ */
+/* ─── PREMIUM ADMIN DASHBOARD STYLES ─── */
+/* ═══════════════════════════════════════════════════════════════════════════ */
+
+.dashboard-header-premium {
+ position: relative;
+ padding: 24px;
+ border-radius: 16px;
+ background: linear-gradient(135deg, hsla(210, 40%, 98%, 0.8), hsla(0, 0%, 100%, 0.95));
+ backdrop-filter: blur(20px);
+ border: 1px solid var(--card-border);
+ box-shadow: 0 4px 24px -6px rgba(0, 0, 0, 0.03);
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 16px;
+ margin-bottom: 24px;
+}
+
+.dashboard-header-premium h2 {
+ font-size: 1.8rem;
+ font-weight: 850;
+ letter-spacing: -0.02em;
+ background: linear-gradient(to right, var(--text-primary), var(--accent-cyan));
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ margin-bottom: 4px;
+}
+
+.premium-stat-card {
+ position: relative;
+ background: #fff;
+ border-radius: 16px;
+ padding: 20px;
+ border: 1px solid var(--card-border);
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.02);
+ display: flex;
+ flex-direction: column;
+ transition: all 0.3s cubic-bezier(0.2, 0.8, 0.2, 1);
+ overflow: hidden;
+}
+
+.premium-stat-card:hover {
+ transform: translateY(-4px);
+ box-shadow: 0 12px 24px rgba(0, 0, 0, 0.06);
+ border-color: rgba(59, 130, 246, 0.2);
+}
+
+.premium-stat-icon-wrap {
+ width: 42px;
+ height: 42px;
+ border-radius: 12px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-bottom: 16px;
+}
+
+.premium-stat-label {
+ font-size: 0.75rem;
+ color: var(--text-secondary);
+ text-transform: uppercase;
+ font-weight: 750;
+ letter-spacing: 0.02em;
+ margin-bottom: 4px;
+}
+
+.premium-stat-value {
+ font-size: 2rem;
+ font-weight: 850;
+ color: var(--text-primary);
+ line-height: 1;
+ letter-spacing: -0.03em;
+ display: flex;
+ align-items: baseline;
+ gap: 6px;
+}
+
+.premium-stat-sub {
+ font-size: 0.9rem;
+ color: var(--text-muted);
+ font-weight: 600;
+}
+
+.dashboard-primary-grid {
+ display: grid;
+ grid-template-columns: 2fr 1fr;
+ gap: 24px;
+ margin-bottom: 24px;
+}
+
+.dashboard-secondary-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 24px;
+ margin-bottom: 24px;
+}
+
+.premium-health-card {
+ background: hsla(210, 40%, 98%, 0.8);
+ border: 1px solid var(--card-border);
+ border-radius: 16px;
+ padding: 24px;
+ transition: all 0.3s ease;
+ position: relative;
+ overflow: hidden;
+}
+
+.premium-health-card:hover {
+ background: #fff;
+ border-color: var(--accent-cyan);
+ box-shadow: 0 8px 32px rgba(59, 130, 246, 0.08);
+}
+
+.health-status-badge {
+ padding: 4px 10px;
+ border-radius: 20px;
+ font-size: 0.65rem;
+ font-weight: 850;
+ letter-spacing: 0.05em;
+ display: flex;
+ align-items: center;
+ gap: 6px;
+}
+
+@media (max-width: 1200px) {
+ .dashboard-primary-grid, .dashboard-secondary-grid {
+ grid-template-columns: 1fr;
+ }
+}
+/* ==========================================================================
+ GLOBAL SIDEBAR (PROFESSIONAL LIGHT DESIGN)
+ ========================================================================== */
+.sidebar-premium {
+ background: #ffffff !important;
+ border-right: 1px solid #edf2f7 !important;
+ box-shadow: 1px 0 8px rgba(0, 0, 0, 0.03);
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
+}
+
+.sidebar-logo-text {
+ background: linear-gradient(135deg, #0ea5e9, #2563eb);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ font-weight: 800;
+ letter-spacing: -0.5px;
+}
+
+.sidebar-nav-item {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding: 10px 20px;
+ margin: 2px 12px;
+ text-decoration: none;
+ color: #475569;
+ font-weight: 500;
+ font-size: 0.875rem;
+ border-radius: 8px;
+ border: none;
+ border-left: none;
+ transition: all 0.15s ease;
+ position: relative;
+}
+
+.sidebar-nav-item:hover {
+ background: #f1f5f9;
+ color: #1e293b;
+}
+
+.sidebar-nav-item.active {
+ background: var(--accent-cyan-soft);
+ color: var(--accent-cyan);
+ font-weight: 600;
+}
+
+.sidebar-nav-item.active::before {
+ display: none;
+}
+
+.sidebar-sub-item {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 8px 20px 8px 48px;
+ margin: 1px 12px;
+ text-decoration: none;
+ font-size: 0.825rem;
+ font-weight: 500;
+ color: #64748b;
+ border-radius: 6px;
+ transition: all 0.15s ease;
+ border: none;
+ border-left: none;
+}
+
+.sidebar-sub-item:hover {
+ background: #f1f5f9;
+ color: #1e293b;
+}
+
+.sidebar-sub-item.active {
+ background: var(--accent-cyan-soft);
+ color: var(--accent-cyan);
+ font-weight: 600;
+}
+
+.sidebar-sub-item.active::before {
+ display: none;
+}
diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx
index 0dac9cf..0d305b1 100644
--- a/src/pages/Dashboard.tsx
+++ b/src/pages/Dashboard.tsx
@@ -285,6 +285,54 @@ const CustomChartTooltip = ({ active, payload }: any) => {
return null;
};
+// --- PREMIUM COMPONENTS ---
+const PremiumStatCard: React.FC<{
+ label: string;
+ value: string | number;
+ subValue?: string;
+ icon: any;
+ trend?: { value: string; isUp: boolean };
+ glowColor: 'cyan' | 'green' | 'red' | 'amber';
+ pulse?: boolean;
+}> = ({ label, value, subValue, icon: Icon, trend, glowColor, pulse }) => {
+ const colors = {
+ cyan: { bg: 'rgba(59, 130, 246, 0.1)', text: 'var(--accent-cyan)' },
+ green: { bg: 'rgba(16, 185, 129, 0.1)', text: 'var(--accent-green)' },
+ red: { bg: 'rgba(239, 68, 68, 0.1)', text: 'var(--alert-red)' },
+ amber: { bg: 'rgba(245, 158, 11, 0.1)', text: 'var(--warning-amber)' },
+ };
+ const theme = colors[glowColor];
+
+ return (
+
+
+
{label}
+
+ {value}
+ {subValue && / {subValue}}
+
+ {trend && (
+
+ {trend.isUp ? '↑' : '↓'} {trend.value} vs last hour
+
+ )}
+
+ );
+};
+
export const Dashboard: React.FC = () => {
const [incidents, setIncidents] = useState
([]);
const [users, setUsers] = useState([]);
@@ -306,7 +354,8 @@ export const Dashboard: React.FC = () => {
const token = localStorage.getItem('teleems_token') || '';
const roles = Array.isArray(user.roles) ? user.roles : [];
const isFleetOp = roles.includes('FLEET_OPERATOR');
- const orgName = user.metadata?.organization?.company_name || 'Fleet Operator';
+ const isHospitalAdmin = roles.some((r: string) => r.toUpperCase() === 'HOSPITAL_ADMIN' || r.toUpperCase() === 'HOSPITAL ADMIN');
+ const orgName = user.metadata?.organization?.company_name || (isHospitalAdmin ? 'Hospital' : 'Fleet Operator');
const [isAddModalOpen, setIsAddModalOpen] = useState(false);
const [clickCoords, setClickCoords] = useState<{ lat: number, lng: number } | null>(null);
@@ -418,34 +467,34 @@ export const Dashboard: React.FC = () => {
})) : [];
return (
-
+
{/* Header Section */}
-
+
-
- {isFleetOp ? `${orgName} Command` : 'Super Admin Command Center'}
+
+ {isFleetOp ? `${orgName} Command` : isHospitalAdmin ? `${orgName} Administration` : 'Super Admin Command Center'}
-
+
-
+
Live platform telemetry synchronized at {lastUpdated.toLocaleTimeString()}
-
{/* Primary Stats Bar */}
-
-
+ {
pulse={activeIncidents.length > 0}
trend={{ value: '14%', isUp: true }}
/>
-
-
-
- u.roles?.includes('CCE')).length || 4}
icon={Video}
glowColor="cyan"
/>
-
- {/* Main Operational Grid */}
-
+ {/* Main Operational Grid: 2 Columns */}
+
{/* Real-time Heatmap */}
-
+
+
+
Global Incident Explorer
+
System-wide incident history and live telemetry
+
- {/* Legend Overlay (Absolute in Card) */}
-
-
+
+
-
+
-
ACTIVE (L/M)
+
ACTIVE (L/M)
- {/* Governance Feed */}
-
-
-
- {incidents.slice(0, 8).map((inc) => (
-
-
-
- {inc.id.split('-').pop()}
- {inc.address}
-
-
{inc.status}
-
-
-
{inc.eta_seconds ? `${Math.floor(inc.eta_seconds / 60)}m` : '--'}
-
ETA
-
-
- ))}
- {incidents.length === 0 &&
No active incidents
}
-
-
-
-
{/* Global Distribution & Health */}
-
-
+
-
-
+
+
{
|
))}
@@ -583,35 +595,71 @@ export const Dashboard: React.FC = () => {
textAlign: 'center',
pointerEvents: 'none'
}}>
- Total
-
+
Total
+
{fleetStatusData.reduce((acc, curr) => acc + curr.value, 0)}
-
ASSETS
+
ASSETS
-
+
{fleetStatusData.map(item => {
const total = fleetStatusData.reduce((acc, curr) => acc + curr.value, 0);
const percentage = total > 0 ? Math.round((item.value / total) * 100) : 0;
return (
-
+
-
-
{item.name}
+
+
{item.name}
-
{percentage}%
+
{percentage}%
);
})}
-
+
+
-
-
-
+ {/* Secondary Grid: Governance Feed and Performance */}
+
+ {/* Governance Feed */}
+
+
+ {incidents.slice(0, 8).map((inc) => (
+
+
+
+ #{inc.id.split('-').pop()}
+ {inc.address}
+
+
{inc.status}
+
+
+
{inc.eta_seconds ? `${Math.floor(inc.eta_seconds / 60)}m` : '--'}
+
ETA
+
+
+ ))}
+ {incidents.length === 0 &&
No active incidents
}
+
+
+
+
+
+
@@ -622,78 +670,89 @@ export const Dashboard: React.FC = () => {
-
+
-
-
+
{/* Platform DNA Section */}
-
-
-
-
+
+
+
+
+
-
- SYNCED
+
+
+ SYNCED
+
-
Master Data
-
482 Triage rules active.
-
-
MANAGE DNA
+
Master Data
+
482 Triage rules active.
+
+
MANAGE DNA
-
+
+
-
- 100%
+
+
+ 100%
+
-
Compliance
-
HIPAA / ABDM verified.
-
-
AUDIT LOGS
+
Compliance
+
HIPAA / ABDM verified.
+
+
AUDIT LOGS
-
+
+
-
- STABLE
+
+
+ STABLE
+
-
System Logic
-
SLA thresholds active.
-
-
CONFIGURE
+
System Logic
+
SLA thresholds active.
+
+
CONFIGURE
-
+
+
-
- ACTIVE
+
+
+ ACTIVE
+
-
Network Hub
-
Multi-zone sync active.
-
-
NODES MAP
+
Network Hub
+
Multi-zone sync active.
+
+
NODES MAP
-
-
+
+
{[
{ label: 'Blood Link', status: 'Healthy', color: 'var(--accent-green)' },
{ label: 'Organ Registry', status: 'Healthy', color: 'var(--accent-green)' },
{ label: 'Mortuary Sync', status: 'Delayed', color: 'var(--warning-amber)' },
{ label: 'Police V-Link', status: 'Healthy', color: 'var(--accent-green)' },
].map((r, i) => (
-
+
-
{r.label}
-
{r.status}
+
{r.label}
+
{r.status}
-
+
))}
@@ -702,8 +761,8 @@ export const Dashboard: React.FC = () => {
{/* SLA Ticker & Progress */}
-
-
+
+
{[
{ label: 'Foundation', progress: 100 },
{ label: 'MVP Core', progress: 100 },
@@ -712,11 +771,11 @@ export const Dashboard: React.FC = () => {
{ label: 'Compliance', progress: 100 },
].map((phase, i) => (
-
-
{phase.label}
-
{phase.progress}%
+
+ {phase.label}
+ {phase.progress}%
-
+
{
style={{
height: '100%',
background: phase.progress === 100 ? 'var(--accent-green)' : 'var(--accent-cyan)',
- boxShadow: `0 0 10px ${phase.progress === 100 ? 'rgba(0,255,136,0.3)' : 'rgba(0,212,255,0.3)'}`
+ boxShadow: `0 0 10px ${phase.progress === 100 ? 'rgba(0,255,136,0.5)' : 'rgba(0,212,255,0.5)'}`
}}
>
@@ -733,26 +792,35 @@ export const Dashboard: React.FC = () => {
-
-
SLA TICKER
-
+
SLA TICKER
+
- HIPAA COMPLIANT ✅ | ABDM SYNCED ✅ | ISO 27001 AUDIT PASSED ✅ | PHI ENCRYPTED ✅ | DPDP ACT ALIGNED ✅ | END-TO-END TLS 1.3 ACTIVE ✅
+ HIPAA COMPLIANT ✅ |
+ ABDM SYNCED ✅ |
+ ISO 27001 AUDIT PASSED ✅ |
+ PHI ENCRYPTED ✅ |
+ DPDP ACT ALIGNED ✅ |
+ END-TO-END TLS 1.3 ACTIVE ✅
+
diff --git a/src/pages/FleetDispatch.tsx b/src/pages/FleetDispatch.tsx
index 498c01b..4f7fd3f 100644
--- a/src/pages/FleetDispatch.tsx
+++ b/src/pages/FleetDispatch.tsx
@@ -469,7 +469,7 @@ const LocationPickerMap: React.FC<{
setIsLocating(false);
if (accuracy > 100) {
- notify('GPS Warning', 'Location accuracy is low. Please manually adjust the pin.', 'info');
+ console.log('GPS Warning', 'Location accuracy is low. Please manually adjust the pin.', 'info');
}
},
(error) => {
@@ -478,7 +478,7 @@ const LocationPickerMap: React.FC<{
if (error.code === 1) msg = 'Location permission denied.';
else if (error.code === 3) msg = 'Location request timed out.';
- notify('GPS Error', msg, 'error');
+ console.log('GPS Error', msg, 'error');
setIsLocating(false);
},
{
@@ -1931,7 +1931,7 @@ const BrandRegistrationForm: React.FC<{ onSubmit: (data: any) => void; loading?:
});
const [showPassword, setShowPassword] = useState(false);
- const handleChange = (e: React.ChangeEvent
) => {
+ const handleChange = (e: React.ChangeEvent) => {
setFormData({ ...formData, [e.target.name]: e.target.value });
};
@@ -2079,7 +2079,7 @@ const StationRegistrationForm: React.FC<{
phone: ''
});
- const handleChange = (e: React.ChangeEvent) => {
+ const handleChange = (e: React.ChangeEvent) => {
setFormData({ ...formData, [e.target.name]: e.target.value });
};
@@ -2440,7 +2440,7 @@ export const FleetDispatch: React.FC = () => {
const roles = u.roles?.map((r: any) => String(r).trim().toUpperCase()) || [];
const isOp = roles.includes('FLEET_OPERATOR') ||
roles.includes('FLEET OPERATOR') ||
- roles.some(r => r.includes('FLEET') && r.includes('OPERATOR'));
+ roles.some((r: string) => r.includes('FLEET') && r.includes('OPERATOR'));
if (!isOp) return false;
@@ -2559,13 +2559,13 @@ export const FleetDispatch: React.FC = () => {
}
console.log('Registration Success:', result);
- notify('Brand Registered', `Organisation "${data.metadata.organization.company_name}" has been onboarded.`, 'success');
+ console.log('Brand Registered', `Organisation "${data.metadata.organization.company_name}" has been onboarded.`, 'success');
setRefreshKey(prev => prev + 1);
setIsModalOpen(false);
} catch (error: any) {
console.error('Registration failed:', error);
const isExpired = error.message.includes('Token has expired');
- notify('Registration Failed', error.message, 'error');
+ console.log('Registration Failed', error.message, 'error');
if (isExpired) {
localStorage.removeItem('teleems_auth');
@@ -2596,13 +2596,13 @@ export const FleetDispatch: React.FC = () => {
}
console.log('Dispatch: Station Created Successfully:', stationId);
- notify('Station Created', `Station "${data.name}" is now active in the system.`, 'success');
+ console.log('Station Created', `Station "${data.name}" is now active in the system.`, 'success');
setRefreshKey(prev => prev + 1); // Trigger re-fetch of fleet owners/stations
setIsModalOpen(false);
} catch (error: any) {
console.error('Dispatch: Station Creation Failed:', error);
- notify('Station Error', error.message, 'error');
+ console.log('Station Error', error.message, 'error');
} finally {
setIsSubmitting(false);
}
@@ -2628,13 +2628,13 @@ export const FleetDispatch: React.FC = () => {
throw new Error(result.message || `Failed to ${data.id ? 'update' : 'create'} vehicle.`);
}
- notify('Vehicle Updated', `Vehicle "${data.registration_number}" telemetry is now synced.`, 'success');
+ console.log('Vehicle Updated', `Vehicle "${data.registration_number}" telemetry is now synced.`, 'success');
setRefreshKey(prev => prev + 1);
setIsModalOpen(false);
setEditingVehicle(null);
} catch (error: any) {
console.error(`Dispatch: Vehicle ${data.id ? 'Update' : 'Creation'} Failed:`, error);
- notify('Vehicle Error', error.message, 'error');
+ console.log('Vehicle Error', error.message, 'error');
} finally {
setIsSubmitting(false);
}
@@ -2658,12 +2658,12 @@ export const FleetDispatch: React.FC = () => {
}
console.log('Dispatch: Staff Registered Successfully');
- notify('Staff Registered', `Personnel file for "${data.name}" has been created.`, 'success');
+ console.log('Staff Registered', `Personnel file for "${data.name}" has been created.`, 'success');
setRefreshKey(prev => prev + 1);
setIsModalOpen(false);
} catch (error: any) {
console.error('Dispatch: Staff Registration Failed:', error);
- notify('Staff Error', error.message, 'error');
+ console.log('Staff Error', error.message, 'error');
} finally {
setIsSubmitting(false);
}
@@ -2682,11 +2682,11 @@ export const FleetDispatch: React.FC = () => {
throw new Error(result.message || 'Failed to create roster.');
}
- notify('Roster Created', 'Crew assignment has been finalized.', 'success');
+ console.log('Roster Created', 'Crew assignment has been finalized.', 'success');
setIsModalOpen(false);
} catch (error: any) {
console.error('Dispatch: Roster Creation Failed:', error);
- notify('Roster Error', error.message, 'error');
+ console.log('Roster Error', error.message, 'error');
} finally {
setIsSubmitting(false);
}
@@ -2705,12 +2705,12 @@ export const FleetDispatch: React.FC = () => {
throw new Error(result.message || 'Failed to start shift.');
}
- notify('Shift Started', 'Vehicle is now LIVE and tracking telemetry.', 'success');
+ console.log('Shift Started', 'Vehicle is now LIVE and tracking telemetry.', 'success');
setIsModalOpen(false);
setRefreshKey(prev => prev + 1);
} catch (error: any) {
console.error('Dispatch: Shift Start Failed:', error);
- notify('Shift Error', error.message, 'error');
+ console.log('Shift Error', error.message, 'error');
} finally {
setIsSubmitting(false);
}
diff --git a/src/pages/HospitalConsole.css b/src/pages/HospitalConsole.css
index 2c969d4..1251109 100644
--- a/src/pages/HospitalConsole.css
+++ b/src/pages/HospitalConsole.css
@@ -1,16 +1,34 @@
:root {
- --base-bg: #F8FAFC;
- --card-bg: #FFFFFF;
- --card-border: rgba(0, 0, 0, 0.06);
- --accent-cyan: #3B82F6;
- --accent-purple: #c084fc;
- --accent-green: #10B981;
- --alert-red: #EF4444;
- --warning-amber: #F59E0B;
- --text-primary: #1E293B;
- --text-secondary: #64748B;
- --glass-blur: blur(40px);
- --shadow-premium: 0 20px 50px rgba(0, 0, 0, 0.05);
+ /* --- Sophisticated HSL Palettes --- */
+ --hull-bg: hsl(210, 40%, 98%);
+ --hull-glass: hsla(210, 40%, 98%, 0.85);
+
+ --accent-cyan: hsl(199, 89%, 48%);
+ --accent-cyan-soft: hsla(199, 89%, 48%, 0.1);
+ --accent-cyan-glow: hsla(199, 89%, 48%, 0.3);
+
+ --accent-purple: hsl(262, 83%, 58%);
+ --accent-green: hsl(152, 69%, 31%);
+ --accent-green-soft: hsla(152, 69%, 31%, 0.1);
+
+ --alert-red: hsl(0, 84%, 60%);
+ --warning-amber: hsl(38, 92%, 50%);
+
+ --text-primary: hsl(222, 47%, 11%);
+ --text-secondary: hsl(215, 25%, 27%);
+ --text-muted: hsl(215, 16%, 47%);
+
+ --card-bg: hsl(0, 0%, 100%);
+ --card-border: hsla(215, 32%, 17%, 0.08);
+ --glass-border: hsla(0, 0%, 100%, 0.4);
+
+ --glass-blur: blur(24px);
+ --shadow-premium:
+ 0 4px 6px -1px hsla(222, 47%, 11%, 0.05),
+ 0 10px 15px -3px hsla(222, 47%, 11%, 0.1),
+ 0 20px 40px -12px hsla(222, 47%, 11%, 0.15);
+
+ --transition-snappy: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
--transition-smooth: all 0.5s cubic-bezier(0.2, 0.8, 0.2, 1);
}
@@ -68,6 +86,471 @@
.hospital-selection-overlay { padding: 40px 20px; }
}
+/* ═══════════════════════════════════════════════════════════════════════════ */
+/* ─── PREMIUM CONSOLE HEADER V2 ─── */
+/* ═══════════════════════════════════════════════════════════════════════════ */
+
+.console-header-premium {
+ position: relative;
+ z-index: 1000;
+ display: flex;
+ flex-direction: column;
+ color: var(--text-primary);
+ background: #ffffff;
+ border-bottom: 1px solid #edf2f7;
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
+}
+
+.header-glass-layer {
+ position: absolute;
+ inset: 0;
+ background: linear-gradient(180deg, hsla(0, 0%, 100%, 0.5) 0%, transparent 100%);
+ pointer-events: none;
+}
+
+/* ── Top Row: Brand + Utility ─────────────── */
+.header-content-wrap {
+ width: 100%;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 24px;
+ padding: 0 32px;
+ height: 56px;
+ min-height: 56px;
+ position: relative;
+ z-index: 2;
+}
+
+.brand-section-interactive {
+ display: flex;
+ align-items: center;
+ gap: 14px;
+ cursor: pointer;
+ padding: 6px 14px 6px 8px;
+ border-radius: 12px;
+ transition: var(--transition-snappy);
+ flex-shrink: 0;
+}
+
+.brand-section-interactive:hover {
+ background: hsla(199, 89%, 48%, 0.06);
+}
+
+.node-indicator {
+ position: relative;
+ width: 10px;
+ height: 10px;
+ flex-shrink: 0;
+}
+
+.pulse-dot {
+ width: 100%;
+ height: 100%;
+ background: var(--accent-cyan);
+ border-radius: 50%;
+ box-shadow: 0 0 8px var(--accent-cyan-glow);
+}
+
+.pulse-ring {
+ position: absolute;
+ inset: -4px;
+ border: 2px solid var(--accent-cyan);
+ border-radius: 50%;
+ animation: hdr-pulse-ring 2.5s infinite;
+ opacity: 0.4;
+}
+
+@keyframes hdr-pulse-ring {
+ 0% { transform: scale(0.6); opacity: 0.7; }
+ 100% { transform: scale(2.8); opacity: 0; }
+}
+
+.hospital-brand-stack {
+ display: flex;
+ flex-direction: column;
+ min-width: 0;
+}
+
+.hospital-name-glow {
+ font-size: 1rem;
+ font-weight: 900;
+ margin: 0;
+ letter-spacing: -0.4px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ line-height: 1.2;
+}
+
+.protocol-status-row {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ font-size: 0.6rem;
+ font-weight: 800;
+ color: var(--text-muted);
+ letter-spacing: 0.06em;
+}
+
+.status-tag {
+ color: var(--accent-green);
+}
+
+/* ── Header Right Utility ─────────────── */
+.header-utility-actions {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ flex-shrink: 0;
+}
+
+.realtime-clock {
+ font-family: 'JetBrains Mono', monospace;
+ font-size: 0.78rem;
+ font-weight: 700;
+ color: var(--text-secondary);
+ background: hsla(210, 30%, 94%, 0.8);
+ padding: 5px 12px;
+ border-radius: 8px;
+ letter-spacing: 0.03em;
+ border: 1px solid var(--card-border);
+}
+
+.mobile-toggle-btn {
+ display: none;
+ background: transparent;
+ border: none;
+ color: var(--text-primary);
+ cursor: pointer;
+ padding: 6px;
+ border-radius: 8px;
+ transition: var(--transition-snappy);
+}
+
+.mobile-toggle-btn:hover {
+ background: hsla(0, 0%, 0%, 0.05);
+}
+
+/* ── Navigation Bar Strip ─────────────── */
+.premium-nav-bar {
+ position: relative;
+ z-index: 1;
+ border-top: 1px solid hsla(215, 32%, 17%, 0.04);
+ padding: 0 24px;
+ overflow: hidden;
+}
+
+.nav-scroll-wrap {
+ display: flex;
+ align-items: center;
+ gap: 2px;
+ overflow-x: auto;
+ overflow-y: hidden;
+ scrollbar-width: none;
+ -ms-overflow-style: none;
+ padding: 0 4px;
+}
+
+.nav-scroll-wrap::-webkit-scrollbar {
+ display: none;
+}
+
+.nav-group {
+ display: flex;
+ gap: 2px;
+ flex-shrink: 0;
+}
+
+.nav-spacer {
+ flex: 1;
+ min-width: 16px;
+ flex-shrink: 1;
+}
+
+.nav-group.secondary {
+ border-left: 1px solid var(--card-border);
+ margin-left: 4px;
+ padding-left: 8px;
+}
+
+.nav-item-premium {
+ background: transparent;
+ border: none;
+ padding: 10px 14px;
+ border-radius: 0;
+ color: var(--text-muted);
+ font-size: 0.78rem;
+ font-weight: 500;
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ cursor: pointer;
+ position: relative;
+ transition: color 0.15s ease, background 0.15s ease;
+ white-space: nowrap;
+ flex-shrink: 0;
+}
+
+.nav-item-premium:hover {
+ color: var(--text-primary);
+ background: #f8fafc;
+}
+
+.nav-item-premium.active {
+ color: var(--accent-cyan);
+ font-weight: 600;
+}
+
+.active-underline {
+ position: absolute;
+ bottom: 0;
+ left: 14px;
+ right: 14px;
+ height: 2px;
+ background: var(--accent-cyan);
+ border-radius: 2px 2px 0 0;
+}
+
+/* ── MOBILE OVERLAY BACKDROP ─────────── */
+.mobile-nav-backdrop {
+ display: none;
+}
+
+/* ── MOBILE BOTTOM NAV ─────────────── */
+.mobile-bottom-nav {
+ display: none;
+}
+
+/* ═══════════════════════════════════════════════════════════════════════════ */
+/* ─── RESPONSIVE: TABLET (≤ 1100px) ─── */
+/* ═══════════════════════════════════════════════════════════════════════════ */
+@media (max-width: 1100px) {
+ .header-content-wrap {
+ padding: 0 20px;
+ height: 52px;
+ min-height: 52px;
+ }
+
+ .hospital-name-glow {
+ font-size: 0.92rem;
+ }
+
+ .show-desktop {
+ display: none !important;
+ }
+
+ .mobile-toggle-btn {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ /* ── Nav drawer: slide from right ─── */
+ .premium-nav-bar {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: auto;
+ width: 300px;
+ max-width: 85vw;
+ background: hsla(210, 40%, 99%, 0.98);
+ backdrop-filter: blur(40px) saturate(1.8);
+ border-top: none;
+ border-left: 1px solid var(--card-border);
+ box-shadow: -20px 0 60px hsla(222, 47%, 11%, 0.12);
+ padding: 0;
+ overflow: hidden;
+ z-index: 2000;
+ transform: translateX(100%);
+ transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
+ }
+
+ .premium-nav-bar.mobile-open {
+ transform: translateX(0);
+ }
+
+ .nav-scroll-wrap {
+ flex-direction: column;
+ align-items: stretch;
+ gap: 0;
+ padding: 72px 16px 24px;
+ overflow-x: visible;
+ overflow-y: auto;
+ height: 100%;
+ }
+
+ .nav-group {
+ flex-direction: column;
+ gap: 2px;
+ }
+
+ .nav-group.secondary {
+ border-left: none;
+ border-top: 1px solid var(--card-border);
+ margin-left: 0;
+ margin-top: 8px;
+ padding-left: 0;
+ padding-top: 12px;
+ }
+
+ .nav-spacer {
+ display: none;
+ }
+
+ .nav-item-premium {
+ padding: 13px 16px;
+ border-radius: 12px;
+ font-size: 0.85rem;
+ gap: 12px;
+ color: var(--text-secondary);
+ }
+
+ .nav-item-premium:hover {
+ background: hsla(199, 89%, 48%, 0.06);
+ }
+
+ .nav-item-premium.active {
+ background: hsla(199, 89%, 48%, 0.08);
+ color: var(--accent-cyan);
+ }
+
+ .active-underline {
+ display: none;
+ }
+
+ /* ── Backdrop overlay ─── */
+ .mobile-nav-backdrop {
+ display: block;
+ position: fixed;
+ inset: 0;
+ background: hsla(222, 47%, 11%, 0.4);
+ backdrop-filter: blur(4px);
+ z-index: 1999;
+ opacity: 0;
+ pointer-events: none;
+ transition: opacity 0.3s ease;
+ }
+
+ .mobile-nav-backdrop.visible {
+ opacity: 1;
+ pointer-events: auto;
+ }
+
+ /* ── Mobile bottom nav bar ─── */
+ .mobile-bottom-nav {
+ display: flex;
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 64px;
+ background: hsla(210, 40%, 99%, 0.96);
+ backdrop-filter: blur(24px) saturate(1.6);
+ border-top: 1px solid var(--card-border);
+ box-shadow: 0 -4px 20px hsla(222, 47%, 11%, 0.06);
+ z-index: 1500;
+ padding: 0 8px;
+ align-items: center;
+ justify-content: space-around;
+ }
+
+ .bottom-nav-item {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 3px;
+ padding: 6px 8px;
+ border: none;
+ background: transparent;
+ color: var(--text-muted);
+ cursor: pointer;
+ border-radius: 10px;
+ transition: color 0.2s ease;
+ flex: 1;
+ max-width: 72px;
+ position: relative;
+ }
+
+ .bottom-nav-item span {
+ font-size: 0.58rem;
+ font-weight: 750;
+ letter-spacing: 0.02em;
+ white-space: nowrap;
+ }
+
+ .bottom-nav-item.active {
+ color: var(--accent-cyan);
+ }
+
+ .bottom-nav-item.active::after {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 50%;
+ transform: translateX(-50%);
+ width: 20px;
+ height: 2.5px;
+ background: var(--accent-cyan);
+ border-radius: 0 0 4px 4px;
+ box-shadow: 0 2px 8px var(--accent-cyan-glow);
+ }
+
+ /* Adjust main content for bottom nav */
+ .console-main {
+ padding-bottom: 80px;
+ }
+}
+
+/* ═══════════════════════════════════════════════════════════════════════════ */
+/* ─── RESPONSIVE: SMALL MOBILE (≤ 600px) ─── */
+/* ═══════════════════════════════════════════════════════════════════════════ */
+@media (max-width: 600px) {
+ .header-content-wrap {
+ padding: 0 14px;
+ height: 48px;
+ min-height: 48px;
+ gap: 10px;
+ }
+
+ .brand-section-interactive {
+ gap: 10px;
+ padding: 4px 8px 4px 4px;
+ }
+
+ .hospital-name-glow {
+ font-size: 0.82rem;
+ max-width: 160px;
+ }
+
+ .protocol-status-row {
+ display: none;
+ }
+
+ .premium-nav-bar {
+ width: 280px;
+ }
+
+ .nav-item-premium {
+ font-size: 0.82rem;
+ padding: 12px 14px;
+ }
+
+ .bottom-nav-item {
+ max-width: 60px;
+ }
+
+ .bottom-nav-item span {
+ font-size: 0.52rem;
+ }
+
+ .mobile-bottom-nav {
+ height: 60px;
+ }
+}
+
.selection-background {
position: absolute;
inset: 0;
@@ -133,6 +616,7 @@
background: linear-gradient(180deg, #1E293B 30%, rgba(30, 41, 59, 0.6) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
+ background-clip: text;
margin-bottom: 24px;
letter-spacing: -3px;
line-height: 0.9;
@@ -503,32 +987,31 @@
.nav-tab {
padding: 7px 10px;
- border-radius: 9px;
- color: var(--text-secondary);
- font-weight: 700;
- font-size: 0.73rem;
+ border-radius: 7px;
+ color: var(--text-muted);
+ font-weight: 500;
+ font-size: 0.75rem;
display: flex;
align-items: center;
gap: 6px;
- transition: all 0.3s cubic-bezier(0.2, 1, 0.2, 1);
+ transition: all 0.15s ease;
position: relative;
border: none;
background: transparent;
cursor: pointer;
white-space: nowrap;
flex-shrink: 0;
- letter-spacing: 0.01em;
}
.nav-tab:hover {
color: var(--text-primary);
- background: rgba(0, 0, 0, 0.03);
+ background: #f1f5f9;
}
.nav-tab.active {
- background: rgba(59, 130, 246, 0.12);
+ background: var(--accent-cyan-soft);
color: var(--accent-cyan);
- box-shadow: inset 0 0 12px rgba(59, 130, 246, 0.08);
+ font-weight: 600;
}
.search-mini {
@@ -575,13 +1058,23 @@
/* --- MODULE CONTENT --- */
.console-main {
flex: 1;
- padding: 24px 32px;
+ padding: 20px 24px;
overflow-y: auto;
- background: radial-gradient(circle at top left, rgba(59, 130, 246, 0.03), transparent 40%);
+ background: #f8f9fb;
}
-@media (max-width: 768px) {
- .console-main { padding: 16px; }
+@media (max-width: 1100px) {
+ .console-main {
+ padding: 20px 16px;
+ padding-bottom: 80px;
+ }
+}
+
+@media (max-width: 600px) {
+ .console-main {
+ padding: 14px 10px;
+ padding-bottom: 76px;
+ }
}
.module-content {
@@ -616,6 +1109,1342 @@
.ed-ops-side-panel { position: static !important; }
}
+/* --- PREMIUM FLEET VIEW --- */
+.fleet-visibility-grid-premium {
+ display: grid;
+ grid-template-columns: 1fr 400px;
+ gap: 24px;
+ height: calc(100vh - 180px);
+}
+
+.map-command-surface {
+ position: relative;
+ background: #0a0e14;
+ border-radius: 32px;
+ overflow: hidden;
+ border: 1px solid var(--card-border);
+ box-shadow: var(--shadow-premium);
+}
+
+.map-overlay-vignette {
+ position: absolute;
+ inset: 0;
+ background: radial-gradient(circle, transparent 40%, rgba(0,0,0,0.6) 100%);
+ pointer-events: none;
+ z-index: 5;
+}
+
+.map-scan-lines {
+ position: absolute;
+ inset: 0;
+ background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.25) 50%), linear-gradient(90deg, rgba(255, 0, 0, 0.06), rgba(0, 255, 0, 0.02), rgba(0, 0, 255, 0.06));
+ background-size: 100% 4px, 3px 100%;
+ pointer-events: none;
+ z-index: 4;
+ opacity: 0.1;
+}
+
+.map-placeholder-premium {
+ width: 100%;
+ height: 100%;
+ position: relative;
+}
+
+.map-coordinate-grid {
+ position: absolute;
+ inset: 0;
+ background-image:
+ linear-gradient(rgba(59, 130, 246, 0.05) 1px, transparent 1px),
+ linear-gradient(90deg, rgba(59, 130, 246, 0.05) 1px, transparent 1px);
+ background-size: 40px 40px;
+}
+
+.node-marker-premium {
+ position: absolute;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 8px;
+ cursor: pointer;
+ z-index: 10;
+}
+
+.marker-core {
+ width: 40px;
+ height: 40px;
+ background: #fff;
+ border-radius: 12px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: var(--text-primary);
+ box-shadow: 0 0 20px rgba(0,0,0,0.3);
+ position: relative;
+ z-index: 2;
+ transition: var(--transition-snappy);
+}
+
+.node-marker-premium.status-running .marker-core { background: var(--accent-cyan); color: #fff; }
+.node-marker-premium.status-idle .marker-core { background: var(--text-muted); color: #fff; }
+.node-marker-premium.status-breakdown .marker-core { background: var(--alert-red); color: #fff; }
+
+.marker-ping {
+ position: absolute;
+ inset: -10px;
+ border: 1px solid currentColor;
+ border-radius: 50%;
+ animation: marker-ping 2s infinite;
+}
+
+@keyframes marker-ping {
+ 0% { transform: scale(0.5); opacity: 1; }
+ 100% { transform: scale(2.5); opacity: 0; }
+}
+
+.marker-label-premium {
+ background: rgba(15, 23, 42, 0.9);
+ backdrop-filter: blur(8px);
+ padding: 4px 12px;
+ border-radius: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 2px;
+ border: 1px solid rgba(255,255,255,0.1);
+}
+
+.marker-label-premium .id { font-size: 0.7rem; font-weight: 950; color: #fff; }
+.marker-label-premium .type { font-size: 0.5rem; font-weight: 700; color: var(--accent-cyan); }
+
+.map-hud-controls {
+ position: absolute;
+ bottom: 24px;
+ right: 24px;
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ z-index: 20;
+}
+
+.hud-group {
+ background: rgba(15, 23, 42, 0.8);
+ backdrop-filter: blur(12px);
+ border: 1px solid rgba(255,255,255,0.1);
+ border-radius: 16px;
+ padding: 6px;
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+}
+
+.hud-btn {
+ width: 40px;
+ height: 40px;
+ border: none;
+ background: transparent;
+ color: #fff;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ border-radius: 12px;
+ transition: var(--transition-snappy);
+}
+
+.hud-btn:hover { background: hsla(0, 0%, 100%, 0.1); }
+
+.fleet-mission-sidebar {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+
+.sidebar-head {
+ padding: 12px 0;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ border-bottom: 1px solid var(--card-border);
+}
+
+.sidebar-head h4 { margin: 0; font-size: 0.9rem; font-weight: 900; }
+.sidebar-head p { margin: 4px 0 0; font-size: 0.65rem; font-weight: 700; color: var(--text-muted); }
+
+.status-summary-mini {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ background: var(--accent-cyan-soft);
+ padding: 4px 12px;
+ border-radius: 20px;
+}
+
+.status-summary-mini .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent-cyan); }
+.status-summary-mini .val { font-size: 0.8rem; font-weight: 900; color: var(--accent-cyan); }
+
+.fleet-unit-stack {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+ overflow-y: auto;
+ padding-bottom: 100px;
+}
+
+.unit-mission-card {
+ background: var(--card-bg);
+ border: 1px solid var(--card-border);
+ border-radius: 24px;
+ padding: 20px;
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+ transition: var(--transition-snappy);
+ position: relative;
+ overflow: hidden;
+}
+
+.unit-mission-card.critical { border-color: var(--alert-red); }
+
+.unit-card-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.type-badge {
+ font-size: 0.6rem;
+ font-weight: 900;
+ color: var(--text-muted);
+ letter-spacing: 0.1em;
+}
+
+.status-pill {
+ padding: 4px 10px;
+ border-radius: 20px;
+ font-size: 0.65rem;
+ font-weight: 800;
+}
+.status-pill.running { background: var(--accent-cyan-soft); color: var(--accent-cyan); }
+.status-pill.idle { background: hsla(0, 0%, 0%, 0.05); color: var(--text-secondary); }
+.status-pill.breakdown { background: hsla(0, 84%, 60%, 0.1); color: var(--alert-red); }
+
+/* --- ePCR & DOCUMENTATION MODULE --- */
+.epcr-stats-strip {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+ gap: 16px;
+ margin-bottom: 24px;
+}
+
+.pcr-modal-overlay {
+ position: fixed;
+ inset: 0;
+ background: hsla(var(--hull-dark-h), var(--hull-dark-s), 5%, 0.8);
+ backdrop-filter: blur(8px);
+ z-index: 2000;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 40px;
+}
+
+.pcr-detail-card {
+ width: 100%;
+ max-width: 900px;
+ max-height: 90vh;
+ background: #fff;
+ border-radius: 24px;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ box-shadow: 0 40px 100px -20px hsla(0, 0%, 0%, 0.5);
+ border: 1px solid var(--card-border);
+}
+
+.pcr-detail-header {
+ padding: 24px 32px;
+ border-bottom: 1px solid var(--card-border);
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ background: var(--hull-glass);
+}
+
+.pcr-id-badge {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ font-weight: 850;
+ color: var(--text-primary);
+ font-family: var(--font-header);
+ letter-spacing: -0.01em;
+}
+
+.pcr-detail-content {
+ flex: 1;
+ overflow-y: auto;
+ padding: 32px;
+ display: flex;
+ flex-direction: column;
+ gap: 32px;
+}
+
+.pcr-section {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+}
+
+.section-label {
+ font-size: 0.65rem;
+ font-weight: 950;
+ color: var(--text-muted);
+ letter-spacing: 0.1em;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ text-transform: uppercase;
+}
+
+.bio-grid {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 16px;
+ background: hsla(var(--hull-h), var(--hull-s), 50%, 0.03);
+ padding: 20px;
+ border-radius: 16px;
+ border: 1px solid var(--card-border);
+}
+
+.bio-item .label {
+ font-size: 0.75rem;
+ color: var(--text-secondary);
+ font-weight: 600;
+}
+
+.bio-item .value {
+ font-size: 0.875rem;
+ font-weight: 750;
+ color: var(--text-primary);
+ margin-left: 8px;
+}
+
+.pcr-row-split {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 24px;
+}
+
+.vitals-trend-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
+ gap: 12px;
+}
+
+.trend-item {
+ background: #fff;
+ border: 1px solid var(--card-border);
+ padding: 16px;
+ border-radius: 12px;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ transition: var(--transition-snappy);
+}
+
+.trend-item:hover {
+ transform: translateY(-4px);
+ border-color: var(--accent-cyan);
+ box-shadow: 0 10px 20px -5px hsla(var(--accent-cyan-h), 100%, 50%, 0.1);
+}
+
+.trend-item .label {
+ font-size: 0.6rem;
+ font-weight: 800;
+ color: var(--text-muted);
+}
+
+.trend-item .value {
+ font-size: 1.25rem;
+ font-weight: 900;
+ color: var(--text-primary);
+}
+
+.sparkline-placeholder {
+ height: 24px;
+ background: linear-gradient(90deg, transparent, hsla(var(--accent-cyan-h), 100%, 50%, 0.1), transparent);
+ border-radius: 4px;
+ position: relative;
+ overflow: hidden;
+}
+
+.sparkline-placeholder::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background: url("data:image/svg+xml,%3Csvg width='100' height='20' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 10 L20 15 L40 5 L60 18 L80 12 L100 15' fill='none' stroke='%233b82f6' stroke-width='2'/%3E%3C/svg%3E");
+ background-size: cover;
+ opacity: 0.4;
+}
+
+.med-list-full {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+
+.med-item {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ font-size: 0.8125rem;
+ font-weight: 600;
+ color: var(--text-primary);
+ background: hsla(0, 0%, 0%, 0.02);
+ padding: 8px 12px;
+ border-radius: 8px;
+}
+
+.med-item.highlight {
+ background: var(--accent-cyan-soft);
+ color: var(--accent-cyan);
+}
+
+.sign-off-panel {
+ background: var(--accent-cyan-soft);
+ border: 1px dashed var(--accent-cyan);
+ border-radius: 16px;
+ padding: 24px;
+ text-align: center;
+}
+
+.pending-sign-area p {
+ font-size: 0.875rem;
+ color: var(--text-secondary);
+ font-weight: 600;
+ margin-bottom: 20px;
+}
+
+.confirm-sign-btn {
+ background: var(--accent-cyan);
+ color: #fff;
+ border: none;
+ padding: 12px 32px;
+ border-radius: 12px;
+ font-weight: 850;
+ font-size: 0.875rem;
+ cursor: pointer;
+ transition: var(--transition-snappy);
+}
+
+/* --- CLINICAL INTELLIGENCE / ANALYTICS V2 --- */
+.analytics-v2 {
+ background: transparent;
+ padding: 0;
+}
+
+.clinical-intel-badge {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ background: var(--accent-cyan-soft);
+ color: var(--accent-cyan);
+ padding: 4px 12px;
+ border-radius: 99px;
+ font-size: 0.65rem;
+ font-weight: 850;
+ letter-spacing: 0.05em;
+ margin-bottom: 8px;
+}
+
+.intel-filters {
+ display: flex;
+ background: var(--hull-glass);
+ border: 1px solid var(--card-border);
+ padding: 4px;
+ border-radius: 12px;
+ gap: 4px;
+}
+
+.intel-filter-btn {
+ padding: 8px 16px;
+ border-radius: 8px;
+ border: none;
+ background: transparent;
+ color: var(--text-secondary);
+ font-size: 0.75rem;
+ font-weight: 800;
+ cursor: pointer;
+ transition: var(--transition-snappy);
+}
+
+.intel-filter-btn.active {
+ background: #fff;
+ color: var(--text-primary);
+ box-shadow: 0 4px 12px hsla(0, 0%, 0%, 0.05);
+}
+
+.intelligence-grid {
+ display: flex;
+ flex-direction: column;
+ gap: 24px;
+ margin-top: 24px;
+}
+
+.kpi-strip {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
+ gap: 20px;
+}
+
+.kpi-card-modern {
+ background: #fff;
+ border: 1px solid var(--card-border);
+ border-radius: 20px;
+ padding: 24px;
+ display: flex;
+ align-items: center;
+ gap: 20px;
+ position: relative;
+ overflow: hidden;
+ transition: var(--transition-snappy);
+}
+
+.kpi-card-modern:hover {
+ transform: translateY(-4px);
+ box-shadow: var(--shadow-premium);
+}
+
+.kpi-icon {
+ width: 56px;
+ height: 56px;
+ border-radius: 16px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: hsla(0, 0%, 0%, 0.03);
+ color: var(--text-primary);
+}
+
+.neon-blue .kpi-icon { background: hsla(210, 100%, 50%, 0.05); color: #3b82f6; }
+.neon-purple .kpi-icon { background: hsla(270, 100%, 50%, 0.05); color: #8b5cf6; }
+.neon-green .kpi-icon { background: hsla(142, 100%, 50%, 0.05); color: #10b981; }
+.neon-amber .kpi-icon { background: hsla(38, 100%, 50%, 0.05); color: #f59e0b; }
+
+.kpi-info label {
+ font-size: 0.65rem;
+ font-weight: 900;
+ color: var(--text-muted);
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+ margin-bottom: 4px;
+ display: block;
+}
+
+.kpi-value-wrap {
+ display: flex;
+ align-items: baseline;
+ gap: 8px;
+}
+
+.kpi-value-wrap .value {
+ font-size: 1.5rem;
+ font-weight: 950;
+ color: var(--text-primary);
+ letter-spacing: -0.02em;
+}
+
+.kpi-value-wrap .trend {
+ font-size: 0.75rem;
+ font-weight: 850;
+}
+
+.trend.positive { color: #10b981; }
+.trend.neutral { color: var(--text-muted); }
+
+.analytics-body-layout {
+ display: grid;
+ grid-template-columns: 1fr 340px;
+ gap: 24px;
+}
+
+.intel-card {
+ background: #fff;
+ border: 1px solid var(--card-border);
+ border-radius: 24px;
+ padding: 32px;
+ display: flex;
+ flex-direction: column;
+}
+
+.intel-card.large {
+ min-height: 400px;
+}
+
+.card-top {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ margin-bottom: 24px;
+}
+
+.card-title {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ font-size: 0.875rem;
+ font-weight: 950;
+ color: var(--text-primary);
+ letter-spacing: -0.01em;
+}
+
+.legend-mini {
+ display: flex;
+ align-items: center;
+ gap: 16px;
+ font-size: 0.7rem;
+ font-weight: 800;
+ color: var(--text-muted);
+}
+
+.l-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
+.l-dot.current { background: var(--accent-cyan); }
+.l-dot.base { background: var(--text-muted); opacity: 0.5; }
+
+.viewport-chart.donut {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.donut-center-label {
+ position: absolute;
+ top: 100px;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ text-align: center;
+ pointer-events: none;
+}
+
+.donut-center-label .v {
+ display: block;
+ font-size: 1.75rem;
+ font-weight: 950;
+ color: var(--text-primary);
+ line-height: 1;
+}
+
+.donut-center-label .l {
+ font-size: 0.6rem;
+ font-weight: 900;
+ color: var(--text-muted);
+ letter-spacing: 0.1em;
+}
+
+.pie-legend-v2 {
+ margin-top: 24px;
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+/* --- ED MONITOR V2 & TRIAGE BOARD --- */
+.ed-monitor-v2 {
+ background: transparent;
+ padding: 0;
+}
+
+.triage-scroll-area-modern {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+ margin-top: 24px;
+ max-height: calc(100vh - 200px);
+ overflow-y: auto;
+ padding-right: 8px;
+}
+
+.patient-triage-card {
+ background: #fff;
+ border: 1px solid #e5e7eb;
+ border-radius: 10px;
+ display: flex;
+ overflow: hidden;
+ transition: all 0.15s ease;
+ position: relative;
+}
+
+.patient-triage-card:hover {
+ border-color: var(--accent-cyan);
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
+}
+
+.triage-sidebar {
+ width: 4px;
+ flex-shrink: 0;
+}
+
+.triage-sidebar.critical, .triage-sidebar.Red { background: var(--alert-red); }
+.triage-sidebar.emergent, .triage-sidebar.Yellow { background: #f59e0b; }
+.triage-sidebar.standard, .triage-sidebar.Green { background: #10b981; }
+
+.t-card-main {
+ flex: 1;
+ display: grid;
+ grid-template-columns: 100px 1fr 1fr 200px;
+ align-items: center;
+ padding: 14px 20px;
+}
+
+.t-unit-hex {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
+ border-right: 1px solid var(--card-border);
+ padding-right: 20px;
+}
+
+.unit-id {
+ font-size: 0.875rem;
+ font-weight: 950;
+ color: var(--text-primary);
+ font-family: var(--font-header);
+}
+
+.eta-block {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ font-size: 0.65rem;
+ font-weight: 850;
+ color: var(--accent-cyan);
+ margin-top: 4px;
+}
+
+.t-patient-info {
+ padding: 0 24px;
+}
+
+.p-name-row {
+ display: flex;
+ align-items: baseline;
+ gap: 12px;
+ margin-bottom: 4px;
+}
+
+.p-name-row h4 {
+ font-size: 1rem;
+ font-weight: 900;
+ color: var(--text-primary);
+ margin: 0;
+}
+
+.p-id {
+ font-size: 0.65rem;
+ color: var(--text-muted);
+ font-weight: 800;
+}
+
+.p-bio {
+ font-size: 0.75rem;
+ color: var(--text-secondary);
+ font-weight: 600;
+}
+
+.clinical-status-pill {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ font-size: 0.65rem;
+ font-weight: 850;
+ padding: 2px 8px;
+ border-radius: 4px;
+ margin-top: 8px;
+ text-transform: uppercase;
+}
+
+.clinical-status-pill.critical, .clinical-status-pill.Red { background: hsla(0, 84%, 60%, 0.1); color: var(--alert-red); }
+.clinical-status-pill.emergent, .clinical-status-pill.Yellow { background: hsla(38, 92%, 50%, 0.1); color: #f59e0b; }
+.clinical-status-pill.standard, .clinical-status-pill.Green { background: hsla(142, 70%, 45%, 0.1); color: #10b981; }
+
+.t-vitals-stream {
+ display: flex;
+ gap: 20px;
+ padding: 0 24px;
+ border-left: 1px solid var(--card-border);
+}
+
+.v-stream-node {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+
+.v-stream-node.hr { color: var(--accent-cyan); }
+.v-stream-node.o2 { color: #10b981; }
+
+.v-stream-node .val {
+ display: block;
+ font-size: 1.125rem;
+ font-weight: 950;
+ line-height: 1;
+}
+
+.v-stream-node .val-bp {
+ display: block;
+ font-size: 0.875rem;
+ font-weight: 950;
+ color: var(--text-primary);
+}
+
+.v-stream-node .lab {
+ font-size: 0.55rem;
+ font-weight: 900;
+ color: var(--text-muted);
+ text-transform: uppercase;
+}
+
+.t-card-actions {
+ display: flex;
+ gap: 8px;
+ justify-content: flex-end;
+}
+
+.intel-action-btn {
+ padding: 8px 12px;
+ border-radius: 8px;
+ border: 1px solid var(--card-border);
+ font-size: 0.75rem;
+ font-weight: 850;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ background: #fff;
+ transition: var(--transition-snappy);
+}
+
+.intel-action-btn.video { color: var(--accent-cyan); border-color: var(--accent-cyan-soft); background: var(--accent-cyan-soft); }
+.intel-action-btn.video:hover { background: var(--accent-cyan); color: #fff; border-color: var(--accent-cyan); }
+
+.intel-action-btn.admit { background: var(--text-primary); color: #fff; border: none; }
+.intel-action-btn.admit:hover { transform: translateY(-2px); box-shadow: 0 4px 12px hsla(0, 0%, 0%, 0.2); }
+
+.more-btn {
+ background: transparent;
+ border: none;
+ color: var(--text-muted);
+ cursor: pointer;
+ padding: 4px;
+}
+
+/* Side Panel */
+.ed-intel-sidebar {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+
+.hub-card.high-intensity {
+ background: var(--text-primary);
+ color: #fff;
+ border-radius: 20px;
+ padding: 24px;
+}
+
+.hub-label {
+ font-size: 0.6rem;
+ font-weight: 950;
+ letter-spacing: 0.1em;
+ opacity: 0.5;
+ margin-bottom: 16px;
+}
+
+.hub-body {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.broadcast-btn {
+ display: flex;
+ align-items: center;
+ gap: 16px;
+ padding: 16px;
+ border-radius: 12px;
+ border: none;
+ background: hsla(0, 0%, 100%, 0.1);
+ color: #fff;
+ cursor: pointer;
+ text-align: left;
+ transition: var(--transition-snappy);
+}
+
+.broadcast-btn:hover { background: hsla(0, 0%, 100%, 0.2); transform: scale(1.02); }
+
+.broadcast-btn.code-red { border: 1px solid var(--alert-red); }
+.broadcast-btn.code-red .b-icon { color: var(--alert-red); }
+
+.broadcast-btn.code-trauma { border: 1px solid #f59e0b; }
+.broadcast-btn.code-trauma .b-icon { color: #f59e0b; }
+
+.b-text strong { display: block; font-size: 1rem; font-weight: 950; }
+.b-text span { font-size: 0.65rem; font-weight: 750; opacity: 0.7; }
+
+.intel-side-card {
+ background: #fff;
+ border: 1px solid var(--card-border);
+ border-radius: 20px;
+ padding: 20px;
+}
+
+.card-lbl {
+ font-size: 0.65rem;
+ font-weight: 950;
+ color: var(--text-muted);
+ margin-bottom: 16px;
+ letter-spacing: 0.05em;
+}
+
+.meter-row { margin-bottom: 16px; }
+.m-info { display: flex; justify-content: space-between; font-size: 0.75rem; font-weight: 850; color: var(--text-primary); margin-bottom: 6px;}
+
+.m-bar { height: 6px; background: hsla(0, 0%, 0%, 0.05); border-radius: 3px; overflow: hidden; }
+.m-fill { height: 100%; border-radius: 3px; }
+.m-fill.warning { background: #f59e0b; }
+.m-fill.critical { background: var(--alert-red); }
+
+.hms-sync-trigger {
+ width: 100%;
+ padding: 10px;
+ background: hsla(0, 0%, 0%, 0.03);
+ border: 1px dashed var(--card-border);
+ border-radius: 8px;
+ font-size: 0.65rem;
+ font-weight: 850;
+ color: var(--text-muted);
+ cursor: pointer;
+}
+
+.intel-log-list { display: flex; flex-direction: column; gap: 12px; }
+.log-item { display: flex; gap: 10px; }
+.log-item .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--card-border); margin-top: 6px; flex-shrink: 0; }
+.log-item .dot.pulse-blue { background: var(--accent-cyan); box-shadow: 0 0 10px var(--accent-cyan); animation: pulse-dot 2s infinite; }
+.log-item p { margin: 0; font-size: 0.7rem; font-weight: 700; color: var(--text-secondary); line-height: 1.4; }
+
+@keyframes pulse-dot {
+ 0% { transform: scale(1); opacity: 1; }
+ 50% { transform: scale(1.5); opacity: 0.5; }
+ 100% { transform: scale(1); opacity: 1; }
+}
+
+@media (max-width: 1200px) {
+ .t-card-main { grid-template-columns: 100px 1fr 1fr; }
+ .t-card-actions { grid-column: span 3; margin-top: 16px; border-top: 1px solid var(--card-border); padding-top: 12px; }
+ .analytics-body-layout { grid-template-columns: 1fr; }
+ .intelligence-footer-grid { grid-template-columns: 1fr; }
+}
+
+@media (max-width: 768px) {
+ .t-card-main { grid-template-columns: 1fr; gap: 16px; }
+ .t-unit-hex { border-right: none; border-bottom: 1px solid var(--card-border); padding: 0 0 16px 0; width: 100%; }
+ .t-patient-info { padding: 0; }
+ .t-vitals-stream { padding: 16px 0; border-left: none; border-top: 1px solid var(--card-border); width: 100%; justify-content: space-between; }
+ .t-card-actions { grid-column: span 1; justify-content: space-between; }
+ .kpi-strip { grid-template-columns: 1fr; }
+ .card-top { flex-direction: column; gap: 12px; }
+ .pcr-modal-overlay { padding: 12px; }
+ .pcr-row-split { grid-template-columns: 1fr; }
+ .bio-grid { grid-template-columns: 1fr; }
+}
+
+.legend-row {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 8px 12px;
+ background: hsla(0, 0%, 0%, 0.02);
+ border-radius: 12px;
+}
+
+.l-side {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.l-name {
+ font-size: 0.75rem;
+ font-weight: 850;
+ color: var(--text-secondary);
+}
+
+.l-val {
+ font-size: 0.8125rem;
+ font-weight: 950;
+ color: var(--text-primary);
+}
+
+.intelligence-footer-grid {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ gap: 24px;
+}
+
+.intel-card.no-bg { background: transparent; border: 1px dashed var(--card-border); }
+
+.dept-load-stack {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+
+.dept-progress-block {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+
+.d-info {
+ display: flex;
+ justify-content: space-between;
+ font-size: 0.75rem;
+ font-weight: 850;
+}
+
+.d-name { color: var(--text-primary); }
+.d-val { color: var(--text-muted); }
+
+.d-bar-bg {
+ height: 8px;
+ background: hsla(0, 0%, 0%, 0.05);
+ border-radius: 4px;
+ overflow: hidden;
+}
+
+.d-bar-fill {
+ height: 100%;
+ border-radius: 4px;
+ transition: width 1s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.card-title.alert-mode {
+ color: var(--alert-red);
+}
+
+.anomaly-list {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.anomaly-item {
+ padding: 12px 16px;
+ background: hsla(0, 0%, 0%, 0.02);
+ border-radius: 12px;
+ border-left: 3px solid var(--accent-cyan);
+}
+
+.anomaly-item.warning {
+ border-left-color: var(--alert-red);
+ background: hsla(0, 84%, 60%, 0.02);
+}
+
+.anomaly-item .time {
+ font-size: 0.65rem;
+ font-weight: 950;
+ color: var(--text-muted);
+ display: block;
+ margin-bottom: 4px;
+}
+
+.anomaly-item p {
+ font-size: 0.75rem;
+ font-weight: 700;
+ color: var(--text-secondary);
+ line-height: 1.4;
+ margin: 0;
+}
+
+.signed-at {
+ font-size: 0.7rem;
+ color: var(--text-muted);
+}
+
+.pcr-detail-footer {
+ padding: 20px 32px;
+ background: var(--hull-glass);
+ border-top: 1px solid var(--card-border);
+ display: flex;
+ justify-content: flex-end;
+ gap: 16px;
+}
+
+.pcr-action-btn {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 10px 20px;
+ border-radius: 10px;
+ font-weight: 750;
+ font-size: 0.8125rem;
+ border: 1px solid var(--card-border);
+ background: #fff;
+ cursor: pointer;
+ transition: var(--transition-snappy);
+}
+
+.pcr-action-btn.primary {
+ background: var(--text-primary);
+ color: #fff;
+ border: none;
+}
+
+@media (max-width: 768px) {
+ .pcr-modal-overlay { padding: 12px; }
+ .pcr-row-split { grid-template-columns: 1fr; }
+ .bio-grid { grid-template-columns: 1fr; }
+}
+
+.unit-card-body h3 {
+ margin: 0 0 12px;
+ font-size: 1.5rem;
+ font-weight: 1000;
+ letter-spacing: -0.5px;
+}
+
+.unit-stats-row {
+ display: flex;
+ gap: 16px;
+}
+
+.u-stat {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ font-size: 0.75rem;
+ font-weight: 700;
+ color: var(--text-secondary);
+}
+
+.highlight-cyan { color: var(--accent-cyan); }
+
+.mission-active-indicator {
+ margin-top: 12px;
+ background: hsla(262, 83%, 58%, 0.05);
+ padding: 12px;
+ border-radius: 12px;
+ border-left: 3px solid var(--accent-purple);
+}
+
+.m-label { font-size: 0.55rem; font-weight: 900; color: var(--accent-purple); margin-bottom: 2px; }
+.m-id { font-size: 0.85rem; font-weight: 950; color: var(--text-primary); }
+
+.unit-card-footer {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding-top: 16px;
+ border-top: 1px dashed var(--card-border);
+}
+
+.crew-mini {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 0.7rem;
+ font-weight: 600;
+ color: var(--text-muted);
+}
+
+.unit-action-btn {
+ width: 32px;
+ height: 32px;
+ border-radius: 10px;
+ border: 1px solid var(--card-border);
+ background: transparent;
+ color: var(--text-secondary);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ transition: var(--transition-snappy);
+}
+
+.unit-action-btn:hover { background: var(--text-primary); color: #fff; border-color: var(--text-primary); }
+
+.unit-card-alert {
+ background: var(--alert-red);
+ color: #fff;
+ padding: 6px 12px;
+ font-size: 0.6rem;
+ font-weight: 900;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ position: absolute;
+ bottom: 0; left: 0; right: 0;
+}
+
+@media (max-width: 1400px) {
+ .fleet-visibility-grid-premium { grid-template-columns: 1fr; grid-template-rows: auto 1fr; height: auto; }
+ .map-command-surface { height: 500px; }
+}
+
+/* --- PREMIUM ANALYTICS MODULE --- */
+.analytics-display-grid-premium {
+ display: flex;
+ flex-direction: column;
+ gap: 32px;
+}
+
+.analytics-stats-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+ gap: 24px;
+}
+
+.stat-node-premium {
+ background: var(--card-bg);
+ border: 1px solid var(--card-border);
+ border-radius: 24px;
+ padding: 24px;
+ position: relative;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+ transition: var(--transition-snappy);
+}
+
+.stat-node-premium:hover {
+ border-color: var(--accent-cyan-soft);
+ transform: translateY(-4px);
+ box-shadow: var(--shadow-premium);
+}
+
+.node-accent-top {
+ position: absolute;
+ top: 0; left: 0; right: 0;
+ height: 4px;
+ background: var(--accent-cyan);
+ opacity: 0.2;
+}
+
+.node-accent-top.purple { background: var(--accent-purple); }
+.node-accent-top.green { background: var(--accent-green); }
+
+.node-head {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+}
+
+.node-icon-soft {
+ width: 40px;
+ height: 40px;
+ background: var(--accent-cyan-soft);
+ color: var(--accent-cyan);
+ border-radius: 12px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.node-icon-soft.purple { background: hsla(262, 83%, 58%, 0.1); color: var(--accent-purple); }
+.node-icon-soft.green { background: var(--accent-green-soft); color: var(--accent-green); }
+
+.node-head label {
+ font-size: 0.65rem;
+ font-weight: 900;
+ color: var(--text-muted);
+ letter-spacing: 0.05em;
+}
+
+.node-value {
+ font-size: 2rem;
+ font-weight: 1000;
+ color: var(--text-primary);
+ letter-spacing: -1px;
+}
+
+.node-value small { font-size: 0.8rem; font-weight: 700; opacity: 0.5; margin-left: 4px; }
+
+.trend-indicator {
+ padding: 4px 10px;
+ border-radius: 20px;
+ font-size: 0.7rem;
+ font-weight: 800;
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ width: fit-content;
+}
+
+.trend-indicator.up { background: var(--accent-green-soft); color: var(--accent-green); }
+.trend-indicator.down { background: rgba(239, 68, 68, 0.1); color: var(--alert-red); }
+.trend-indicator.neutral { background: hsla(0, 0%, 0%, 0.05); color: var(--text-muted); }
+
+.analytics-charts-container {
+ display: grid;
+ grid-template-columns: 1.5fr 1fr;
+ gap: 24px;
+}
+
+.premium-chart-card {
+ background: var(--card-bg);
+ border: 1px solid var(--card-border);
+ border-radius: 28px;
+ padding: 32px;
+ display: flex;
+ flex-direction: column;
+ gap: 24px;
+}
+
+.chart-header-modern {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+}
+
+.title-stack h4 { margin: 0; font-size: 1.1rem; font-weight: 900; color: var(--text-primary); }
+.title-stack p { margin: 4px 0 0; font-size: 0.6rem; font-weight: 800; color: var(--text-muted); letter-spacing: 0.1em; }
+
+.chart-type-icon { color: var(--text-muted); opacity: 0.3; }
+
+.chart-viewport { flex: 1; min-height: 300px; display: flex; }
+.chart-viewport.flex-col { flex-direction: column; }
+
+.premium-pie-legend {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 16px;
+ padding-top: 24px;
+ border-top: 1px solid var(--card-border);
+}
+
+.p-legend-item {
+ flex: 1;
+ min-width: 100px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ background: hsla(0, 0%, 0%, 0.02);
+ padding: 10px 14px;
+ border-radius: 12px;
+}
+
+.indicator-wrap { display: flex; align-items: center; gap: 8px; }
+.p-dot { width: 8px; height: 8px; border-radius: 50%; }
+.p-label { font-size: 0.6rem; font-weight: 900; color: var(--text-muted); }
+.p-val { font-size: 0.8rem; font-weight: 950; color: var(--text-primary); }
+
+@media (max-width: 1200px) {
+ .analytics-charts-container { grid-template-columns: 1fr; }
+}
+
.module-header-modern {
display: flex;
justify-content: space-between;
@@ -630,6 +2459,7 @@
background: linear-gradient(180deg, #1E293B 40%, rgba(30, 41, 59, 0.6) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
+ background-clip: text;
margin: 0 0 12px 0;
}
@@ -796,20 +2626,313 @@
margin-bottom: 12px;
letter-spacing: 0.02em;
}
-
-.t-status {
- display: flex;
- align-items: center;
- gap: 8px;
- font-size: 0.75rem;
- font-weight: 800;
- text-transform: uppercase;
- letter-spacing: 0.05em;
+/* --- PREMIUM ED MONITOR --- */
+.ed-grid-modern {
+ display: grid;
+ grid-template-columns: 1fr 380px;
+ gap: 32px;
+ align-items: start;
}
-.t-status.RED { color: var(--alert-red); }
-.t-status.YELLOW { color: var(--warning-amber); }
-.t-status.GREEN { color: var(--accent-green); }
+.triage-feed-container {
+ display: flex;
+ flex-direction: column;
+ gap: 24px;
+}
+
+.patient-alert-card.premium {
+ background: var(--card-bg);
+ border: 1px solid var(--card-border);
+ border-radius: 24px;
+ padding: 0;
+ overflow: hidden;
+ display: flex;
+ position: relative;
+ transition: var(--transition-snappy);
+ box-shadow: 0 4px 20px rgba(0,0,0,0.03);
+}
+
+.patient-alert-card.premium:hover {
+ transform: translateX(8px);
+ border-color: var(--accent-cyan-soft);
+ box-shadow: var(--shadow-premium);
+}
+
+.triage-accent {
+ width: 8px;
+ height: auto;
+}
+.triage-accent.RED { background: var(--alert-red); }
+.triage-accent.YELLOW { background: var(--alert-yellow); }
+.triage-accent.GREEN { background: var(--accent-green); }
+
+.alert-grid {
+ flex: 1;
+ display: grid;
+ grid-template-columns: 120px 1.2fr 1.5fr 180px;
+ padding: 24px;
+ align-items: center;
+ gap: 24px;
+}
+
+.unit-info {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ align-items: center;
+ border-right: 1px dashed var(--card-border);
+ padding-right: 24px;
+}
+
+.ambulance-badge {
+ background: var(--text-primary);
+ color: #fff;
+ padding: 4px 10px;
+ border-radius: 8px;
+ font-family: 'JetBrains Mono', monospace;
+ font-size: 0.7rem;
+ font-weight: 900;
+}
+
+.eta-container {
+ text-align: center;
+}
+
+.eta-value {
+ font-size: 1.6rem;
+ font-weight: 1000;
+ color: var(--accent-cyan);
+ line-height: 1;
+}
+
+.eta-label {
+ font-size: 0.55rem;
+ font-weight: 900;
+ color: var(--text-muted);
+ letter-spacing: 0.1em;
+}
+
+.patient-details h4 {
+ margin: 0 0 4px;
+ font-size: 1.1rem;
+ font-weight: 900;
+ color: var(--text-primary);
+}
+
+.p-sub {
+ font-size: 0.75rem;
+ font-weight: 700;
+ color: var(--text-muted);
+ margin-bottom: 8px;
+}
+
+.t-status {
+ padding: 4px 12px;
+ border-radius: 20px;
+ font-size: 0.65rem;
+ font-weight: 800;
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ width: fit-content;
+}
+
+.t-status.RED { background: rgba(239, 68, 68, 0.1); color: var(--alert-red); }
+.t-status.YELLOW { background: rgba(245, 158, 11, 0.1); color: var(--alert-yellow); }
+.t-status.GREEN { background: var(--accent-green-soft); color: var(--accent-green); }
+
+.vital-telemetry-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 12px;
+}
+
+.vital-cell {
+ background: hsla(0, 0%, 0%, 0.02);
+ padding: 10px 14px;
+ border-radius: 12px;
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ border: 1px solid transparent;
+}
+
+.vital-cell.critical {
+ background: hsla(0, 84%, 60%, 0.05);
+ border-color: var(--alert-red);
+ animation: pulse-critical 2s infinite;
+}
+
+@keyframes pulse-critical {
+ 0% { opacity: 1; }
+ 50% { opacity: 0.7; }
+ 100% { opacity: 1; }
+}
+
+.vital-cell .v-val {
+ font-size: 1.1rem;
+ font-weight: 900;
+ color: var(--text-primary);
+ line-height: 1.1;
+}
+
+.vital-cell .v-label {
+ font-size: 0.55rem;
+ font-weight: 800;
+ color: var(--text-muted);
+}
+
+.card-actions-area {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+}
+
+.telelink-btn-premium, .assign-btn-premium {
+ padding: 10px;
+ border-radius: 12px;
+ font-size: 0.75rem;
+ font-weight: 900;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ cursor: pointer;
+ transition: var(--transition-snappy);
+}
+
+.telelink-btn-premium {
+ background: var(--accent-cyan);
+ color: #fff;
+ border: none;
+}
+
+.telelink-btn-premium:hover {
+ background: #00b8e6;
+ box-shadow: 0 4px 12px var(--accent-cyan-glow);
+}
+
+.assign-btn-premium {
+ background: transparent;
+ border: 1.5px solid var(--text-primary);
+ color: var(--text-primary);
+}
+
+.assign-btn-premium:hover {
+ background: var(--text-primary);
+ color: #fff;
+}
+
+/* --- ED OPS HUB --- */
+.ed-ops-side-panel {
+ display: flex;
+ flex-direction: column;
+ gap: 24px;
+ position: sticky;
+ top: 100px;
+}
+
+.hub-card.premium-ops {
+ background: #000;
+ color: #fff;
+ border-radius: 28px;
+ padding: 28px;
+ box-shadow: 0 20px 40px rgba(0,0,0,0.2);
+}
+
+.hub-card.premium-ops h4 {
+ color: #fff;
+ margin: 0 0 12px;
+ font-size: 1.1rem;
+ font-weight: 900;
+ letter-spacing: -0.5px;
+}
+
+.hub-desc {
+ font-size: 0.75rem;
+ color: hsla(0, 0%, 100%, 0.6);
+ line-height: 1.5;
+ margin-bottom: 24px;
+}
+
+.codes-stack {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.code-btn-modern {
+ border: none;
+ border-radius: 16px;
+ padding: 16px 20px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ cursor: pointer;
+ transition: var(--transition-snappy);
+}
+
+.code-btn-modern:hover { transform: scale(1.02); }
+
+.code-btn-modern.red { background: var(--alert-red); color: #fff; }
+.code-btn-modern.blue { background: #3b82f6; color: #fff; }
+.code-btn-modern.trauma { background: var(--accent-purple); color: #fff; }
+
+.c-info { text-align: left; }
+.c-info strong { display: block; font-size: 1.1rem; font-weight: 1000; }
+.c-info span { font-size: 0.65rem; font-weight: 700; opacity: 0.8; }
+
+.sync-btn-modern {
+ width: 100%;
+ padding: 14px;
+ background: hsla(0, 0%, 0%, 0.04);
+ border: 1px solid var(--card-border);
+ border-radius: 12px;
+ font-size: 0.7rem;
+ font-weight: 900;
+ color: var(--text-muted);
+ cursor: pointer;
+ transition: var(--transition-snappy);
+ margin-top: 16px;
+}
+
+.sync-btn-modern:hover { background: hsla(0, 0%, 0%, 0.08); color: var(--text-primary); }
+
+.operational-clock-card {
+ background: var(--hull-glass);
+ backdrop-filter: var(--glass-blur);
+ padding: 24px;
+ border-radius: 24px;
+ border: 1px solid var(--card-border);
+ text-align: center;
+}
+
+.o-time {
+ font-family: 'JetBrains Mono', monospace;
+ font-size: 2.2rem;
+ font-weight: 1000;
+ color: var(--text-primary);
+ letter-spacing: -1.5px;
+ margin-bottom: 8px;
+}
+
+.o-status {
+ font-size: 0.65rem;
+ font-weight: 900;
+ color: var(--accent-green);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+}
+
+@media (max-width: 1200px) {
+ .ed-grid-modern { grid-template-columns: 1fr; }
+ .alert-grid { grid-template-columns: 100px 1fr 1fr; padding: 16px; gap: 16px; }
+ .card-actions-area { grid-column: span 3; flex-direction: row; }
+ .card-actions-area button { flex: 1; }
+ .ed-ops-side-panel { position: static !important; }
+}
.vital-telemetry-grid {
display: grid;
@@ -865,42 +2988,40 @@
.telelink-btn-premium {
background: var(--accent-cyan);
- color: #000;
+ color: #ffffff;
border: none;
- padding: 10px 12px;
- border-radius: 10px;
- font-weight: 900;
+ padding: 8px 12px;
+ border-radius: 7px;
+ font-weight: 600;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
- gap: 8px;
- transition: all 0.4s;
+ gap: 6px;
+ transition: all 0.15s ease;
font-size: 0.75rem;
- text-transform: uppercase;
white-space: nowrap;
}
.assign-btn-premium {
- background: rgba(0,0,0,0.03);
+ background: #f8fafc;
color: var(--text-primary);
- border: 1px solid var(--card-border);
- padding: 10px 12px;
- border-radius: 10px;
- font-weight: 700;
+ border: 1px solid #e5e7eb;
+ padding: 8px 12px;
+ border-radius: 7px;
+ font-weight: 600;
cursor: pointer;
- transition: all 0.3s;
+ transition: all 0.15s ease;
font-size: 0.75rem;
- text-transform: uppercase;
white-space: nowrap;
display: flex;
align-items: center;
justify-content: center;
- gap: 8px;
+ gap: 6px;
}
-.telelink-btn-premium:hover { transform: translateY(-3px); box-shadow: 0 10px 30px rgba(59, 130, 246, 0.4); }
-.assign-btn-premium:hover { background: rgba(255,255,255,0.1); border-color: var(--accent-cyan); }
+.telelink-btn-premium:hover { background: #0284c7; box-shadow: 0 4px 12px rgba(14, 165, 233, 0.25); }
+.assign-btn-premium:hover { border-color: var(--accent-cyan); color: var(--accent-cyan); }
.ed-ops-side-panel {
display: flex;
@@ -915,16 +3036,16 @@
/* OPERATIONS PANEL */
.hub-card.premium-ops {
- padding: 20px;
- border-radius: 20px;
- background: var(--card-bg);
- border: 1px solid var(--card-border);
+ padding: 16px;
+ border-radius: 10px;
+ background: #ffffff;
+ border: 1px solid #e5e7eb;
min-width: 0;
overflow: hidden;
}
-.hub-card h4 { font-size: 1.1rem; font-weight: 900; margin: 0 0 10px 0; letter-spacing: -0.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
-.hub-desc { font-size: 0.75rem; color: var(--text-secondary); margin-bottom: 16px; line-height: 1.5; }
+.hub-card h4 { font-size: 1rem; font-weight: 700; margin: 0 0 8px 0; letter-spacing: -0.3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
+.hub-desc { font-size: 0.75rem; color: var(--text-secondary); margin-bottom: 14px; line-height: 1.5; }
.codes-stack { display: flex; flex-direction: column; gap: 12px; }
@@ -937,7 +3058,7 @@
justify-content: space-between;
text-transform: uppercase;
font-weight: 900;
- transition: all 0.4s cubic-bezier(0.2, 0.8, 0.2, 1);
+ transition: background 0.2s;
width: 100%;
border: none;
cursor: pointer;
@@ -952,11 +3073,11 @@
.c-info strong { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 0.85rem; }
.c-info span { font-size: 0.65rem; opacity: 0.75; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
-.code-btn-modern.red { background: linear-gradient(135deg, #ef4444, #7f1d1d); box-shadow: 0 10px 25px rgba(239, 68, 68, 0.25); }
-.code-btn-modern.blue { background: linear-gradient(135deg, #3b82f6, #1e3a8a); box-shadow: 0 10px 25px rgba(59, 130, 246, 0.25); }
-.code-btn-modern.trauma { background: linear-gradient(135deg, #f59e0b, #78350f); box-shadow: 0 10px 25px rgba(245, 158, 11, 0.25); }
+.code-btn-modern.red { background: #ef4444; }
+.code-btn-modern.blue { background: #3b82f6; }
+.code-btn-modern.trauma { background: #f59e0b; }
-.code-btn-modern:hover { transform: scale(1.05) translateY(-8px); filter: brightness(1.2); }
+.code-btn-modern:hover { filter: brightness(1.1); }
.inventory-card {
background: var(--card-bg);
@@ -980,58 +3101,57 @@
}
.operational-clock-card {
- padding: 24px;
- background: linear-gradient(180deg, rgba(0,0,0,0.01) 0%, rgba(0,0,0,0.03) 100%);
- border-radius: 20px;
- border: 1px solid var(--card-border);
+ padding: 20px;
+ background: #ffffff;
+ border-radius: 10px;
+ border: 1px solid #e5e7eb;
text-align: center;
- box-shadow: 0 20px 40px rgba(0,0,0,0.05);
min-width: 0;
overflow: hidden;
}
-.o-time { font-size: 1.6rem; font-weight: 900; letter-spacing: -1px; color: var(--accent-cyan); text-shadow: 0 0 30px rgba(59, 130, 246, 0.3); font-family: 'JetBrains Mono'; white-space: nowrap; }
-.o-status { margin-top: 10px; font-size: 0.65rem; font-weight: 800; color: var(--accent-green); letter-spacing: 0.12em; text-transform: uppercase; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
+.o-time { font-size: 1.4rem; font-weight: 700; letter-spacing: -0.5px; color: var(--accent-cyan); font-family: 'JetBrains Mono'; white-space: nowrap; }
+.o-status { margin-top: 8px; font-size: 0.65rem; font-weight: 600; color: var(--accent-green); letter-spacing: 0.08em; text-transform: uppercase; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* TRIP MANAGEMENT */
.trip-card-premium {
- background: var(--card-bg);
- border: 1px solid var(--card-border);
- border-radius: 20px;
- margin-bottom: 12px;
- transition: all 0.3s;
+ background: #ffffff;
+ border: 1px solid #e5e7eb;
+ border-radius: 10px;
+ margin-bottom: 10px;
+ transition: all 0.15s ease;
}
-.trip-card-premium:hover { background: rgba(0, 0, 0, 0.01); border-color: var(--accent-cyan); }
+.trip-card-premium:hover { border-color: var(--accent-cyan); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06); }
-.trip-patient-main { font-size: 1rem; font-weight: 900; margin-bottom: 4px; }
-.trip-id-mono { font-family: 'JetBrains Mono'; font-size: 0.7rem; color: var(--accent-cyan); opacity: 0.7; }
+.trip-patient-main { font-size: 0.95rem; font-weight: 700; margin-bottom: 4px; }
+.trip-id-mono { font-family: 'JetBrains Mono'; font-size: 0.7rem; color: var(--accent-cyan); opacity: 0.8; }
.trip-status-timeline {
display: flex;
align-items: center;
gap: 4px;
- margin-top: 12px;
- background: rgba(0,0,0,0.02);
+ margin-top: 10px;
+ background: #f8fafc;
padding: 4px;
- border-radius: 20px;
+ border-radius: 8px;
}
-.ts-step { width: 10px; height: 10px; border-radius: 50%; background: rgba(0,0,0,0.05); }
-.ts-step.active { background: var(--accent-cyan); box-shadow: 0 0 10px var(--accent-cyan); }
+.ts-step { width: 8px; height: 8px; border-radius: 50%; background: #e2e8f0; }
+.ts-step.active { background: var(--accent-cyan); }
.ts-step.completed { background: var(--accent-green); }
-.ts-line { flex: 1; height: 2px; background: rgba(0,0,0,0.03); }
+.ts-line { flex: 1; height: 2px; background: #e2e8f0; }
.ts-line.active { background: var(--accent-cyan); }
/* FLEET DASHBOARD */
.fleet-dashboard-layout {
display: grid;
- grid-template-columns: 1fr 400px;
- gap: 32px;
+ grid-template-columns: 1fr 380px;
+ gap: 24px;
height: calc(100vh - 140px);
}
@media (max-width: 1200px) {
- .fleet-dashboard-layout { grid-template-columns: 1fr 340px; }
+ .fleet-dashboard-layout { grid-template-columns: 1fr 320px; }
}
@media (max-width: 1024px) {
@@ -1040,9 +3160,9 @@
}
.fleet-map-container {
- background: var(--card-bg);
- border: 1px solid var(--card-border);
- border-radius: 32px;
+ background: #ffffff;
+ border: 1px solid #e5e7eb;
+ border-radius: 12px;
position: relative;
overflow: hidden;
}
@@ -1104,56 +3224,58 @@
/* SETUP LAYOUT */
/* --- SETUP MODULE PREMIUM --- */
.setup-layout {
- display: grid;
- grid-template-columns: 240px 1fr;
- gap: 32px;
+ display: flex;
+ flex-direction: column;
+ gap: 24px;
height: calc(100vh - 140px);
min-height: 0;
}
.setup-nav {
display: flex;
- flex-direction: column;
- gap: 12px;
- background: rgba(0, 0, 0, 0.01);
- border: 1px solid var(--card-border);
- padding: 20px;
- border-radius: 24px;
- backdrop-filter: blur(20px);
+ flex-direction: row;
+ gap: 6px;
+ padding: 4px;
+ background: #f1f5f9;
+ border-radius: 10px;
+ overflow-x: auto;
+ flex-shrink: 0;
+}
+
+.setup-nav::-webkit-scrollbar {
+ display: none;
}
.setup-nav-item {
- width: 100%;
- padding: 14px 20px;
- border-radius: 14px;
- border: 1px solid transparent;
+ padding: 8px 18px;
+ border-radius: 8px;
+ border: none;
background: transparent;
color: var(--text-secondary);
- font-weight: 700;
- font-size: 0.85rem;
+ font-weight: 500;
+ font-size: 0.82rem;
display: flex;
align-items: center;
- gap: 14px;
+ gap: 6px;
cursor: pointer;
- transition: var(--transition-smooth);
- text-transform: uppercase;
- letter-spacing: 0.05em;
+ transition: all 0.15s ease;
+ white-space: nowrap;
}
.setup-nav-item:hover {
- background: rgba(0, 0, 0, 0.02);
+ background: rgba(255, 255, 255, 0.8);
color: var(--text-primary);
- transform: translateX(5px);
}
.setup-nav-item.active {
- background: rgba(0, 209, 255, 0.1);
- border-color: rgba(0, 209, 255, 0.2);
- color: var(--accent-cyan);
- box-shadow: 0 0 20px rgba(0, 209, 255, 0.05);
+ background: #ffffff;
+ color: var(--text-primary);
+ font-weight: 600;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}
.setup-content-modern {
+ flex: 1;
overflow-y: auto;
overflow-x: hidden;
padding-right: 12px;
@@ -1184,58 +3306,83 @@
}
.form-group-premium label {
- font-size: 0.7rem;
- font-weight: 800;
- color: var(--accent-cyan);
+ font-size: 0.75rem;
+ font-weight: 600;
+ color: var(--text-secondary);
text-transform: uppercase;
- letter-spacing: 0.1em;
- padding-left: 4px;
+ letter-spacing: 0.04em;
+ padding-left: 2px;
}
.setup-input-premium {
- background: rgba(0, 0, 0, 0.02);
+ background: #f8fafc;
border: 1px solid var(--card-border);
- padding: 14px 20px;
- border-radius: 12px;
+ padding: 10px 14px;
+ border-radius: 8px;
color: var(--text-primary);
- font-size: 0.95rem;
+ font-size: 0.9rem;
font-family: inherit;
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+ transition: all 0.15s ease;
}
.setup-input-premium:focus {
outline: none;
- background: rgba(0, 0, 0, 0.03);
+ background: #ffffff;
border-color: var(--accent-cyan);
- box-shadow: 0 0 20px rgba(0, 209, 255, 0.15);
+ box-shadow: 0 0 0 3px var(--accent-cyan-soft);
+}
+
+.profile-data-block {
+ padding: 12px 16px;
+ background: #f8fafc;
+ border-left: 3px solid var(--card-border);
+ border-radius: 6px;
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+}
+
+.profile-data-label {
+ font-size: 0.7rem;
+ font-weight: 600;
+ color: var(--text-muted);
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+}
+
+.profile-data-value {
+ font-size: 0.95rem;
+ font-weight: 600;
+ color: var(--text-primary);
}
select.setup-input-premium {
appearance: none;
- background-image: url('data:image/svg+xml;utf8,');
+ background-image: url('data:image/svg+xml;utf8,');
background-repeat: no-repeat;
- background-position: right 14px top 50%;
- padding-right: 40px;
+ background-position: right 12px top 50%;
+ padding-right: 36px;
+ cursor: pointer;
}
.setup-confirm-btn {
- background: var(--text-primary);
- color: var(--base-bg);
- padding: 16px 32px;
- border-radius: 14px;
- font-weight: 950;
- font-size: 0.85rem;
- letter-spacing: 0.1em;
+ background: var(--accent-cyan);
+ color: #ffffff;
+ padding: 11px 28px;
+ border-radius: 8px;
+ font-weight: 600;
+ font-size: 0.82rem;
+ letter-spacing: 0.03em;
border: none;
cursor: pointer;
- transition: all 0.4s;
+ transition: all 0.15s ease;
align-self: flex-start;
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05);
+ box-shadow: var(--shadow-sm);
}
.setup-confirm-btn:hover {
- transform: translateY(-4px) scale(1.02);
- box-shadow: 0 15px 40px rgba(0, 0, 0, 0.1);
+ background: #0284c7;
+ box-shadow: var(--shadow-md);
}
/* Service Nodes */
@@ -1261,8 +3408,10 @@ select.setup-input-premium {
transform: translateY(-8px);
}
+.service-node-card.map-filter { filter: grayscale(100%) invert(92%) sepia(18%) saturate(163%) hue-rotate(185deg) brightness(85%) contrast(85%); }
+
.service-node-card.active { border-color: var(--accent-green); }
-.service-node-card.inactive { opacity: 0.6; grayscale: 1; }
+.service-node-card.inactive { opacity: 0.6; }
.node-info-text strong { display: block; font-size: 1.1rem; margin-bottom: 4px; }
.node-status-text { font-size: 0.7rem; font-weight: 900; letter-spacing: 0.1em; }
@@ -1485,6 +3634,278 @@ select.setup-input-premium {
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
overflow: hidden;
}
+ /* --- PREMIUM TELELINK HUB --- */
+.call-surface-panel-premium {
+ flex: 1;
+ background: var(--card-bg);
+ border: 1px solid var(--card-border);
+ border-radius: 32px;
+ position: relative;
+ overflow: hidden;
+ display: flex;
+ box-shadow: var(--shadow-premium);
+}
+
+.surface-glass-glow {
+ position: absolute;
+ top: -100px;
+ right: -100px;
+ width: 400px;
+ height: 400px;
+ background: radial-gradient(circle, var(--accent-cyan-glow) 0%, transparent 70%);
+ pointer-events: none;
+}
+
+.active-call-grid {
+ display: grid;
+ grid-template-columns: 1.2fr 400px;
+ width: 100%;
+ height: 100%;
+}
+
+.video-workspace {
+ padding: 24px;
+ display: flex;
+ flex-direction: column;
+}
+
+.video-feed-main {
+ flex: 1;
+ background: #000;
+ border-radius: 24px;
+ position: relative;
+ overflow: hidden;
+ box-shadow: 0 20px 40px rgba(0,0,0,0.4);
+}
+
+.feed-header-overlay {
+ position: absolute;
+ top: 0; left: 0; right: 0;
+ padding: 20px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ background: linear-gradient(180deg, rgba(0,0,0,0.6) 0%, transparent 100%);
+ z-index: 10;
+}
+
+.secure-badge {
+ background: rgba(16, 185, 129, 0.2);
+ color: var(--accent-green);
+ padding: 6px 12px;
+ border-radius: 20px;
+ font-size: 0.65rem;
+ font-weight: 800;
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ backdrop-filter: blur(8px);
+ border: 1px solid rgba(16, 185, 129, 0.2);
+}
+
+.video-placeholder-premium {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ color: #fff;
+ gap: 20px;
+ text-align: center;
+}
+
+.video-pulse-icon {
+ width: 100px;
+ height: 100px;
+ background: var(--accent-cyan-soft);
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ animation: pulse-aura 2s infinite;
+}
+
+.patient-id-overlay {
+ position: absolute;
+ bottom: 80px;
+ left: 20px;
+ background: rgba(0,0,0,0.5);
+ backdrop-filter: blur(12px);
+ padding: 12px 20px;
+ border-radius: 16px;
+ display: flex;
+ align-items: center;
+ gap: 16px;
+ border: 1px solid rgba(255,255,255,0.1);
+}
+
+.p-triage {
+ padding: 4px 12px;
+ border-radius: 8px;
+ font-weight: 900;
+ font-size: 0.75rem;
+}
+.p-triage[data-triage="red"] { background: var(--alert-red); color: #fff; }
+
+.video-actions-floating {
+ position: absolute;
+ bottom: 20px;
+ left: 50%;
+ transform: translateX(-50%);
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ background: rgba(15, 23, 42, 0.8);
+ backdrop-filter: blur(16px);
+ padding: 12px 24px;
+ border-radius: 24px;
+ border: 1px solid rgba(255,255,255,0.1);
+ box-shadow: 0 10px 30px rgba(0,0,0,0.5);
+ z-index: 20;
+}
+
+.v-float-btn {
+ width: 48px;
+ height: 48px;
+ border-radius: 16px;
+ border: none;
+ background: hsla(0, 0%, 100%, 0.1);
+ color: #fff;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ transition: var(--transition-snappy);
+}
+
+.v-float-btn:hover { background: hsla(0, 0%, 100%, 0.2); transform: translateY(-2px); }
+.v-float-btn.active { color: var(--accent-cyan); background: var(--accent-cyan-soft); }
+.v-float-btn.end-session { background: var(--alert-red); color: #fff; margin-left: 20px; }
+
+.clinical-data-rail {
+ border-left: 1px solid var(--card-border);
+ background: hsla(210, 40%, 96%, 0.3);
+ display: flex;
+ flex-direction: column;
+ padding: 24px;
+ gap: 32px;
+}
+
+.rail-section { display: flex; flex-direction: column; gap: 16px; }
+.rail-section.grow { flex: 1; }
+
+.rail-head {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ color: var(--text-primary);
+ font-size: 0.85rem;
+ font-weight: 900;
+ letter-spacing: 0.05em;
+}
+
+.vitals-mini-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 12px;
+}
+
+.v-stat-card {
+ background: #fff;
+ padding: 16px;
+ border-radius: 16px;
+ border: 1px solid var(--card-border);
+}
+
+.v-stat-card label {
+ display: block;
+ font-size: 0.55rem;
+ font-weight: 950;
+ color: var(--text-muted);
+ margin-bottom: 4px;
+}
+
+.v-stat-card .val {
+ font-size: 1.4rem;
+ font-weight: 1000;
+ color: var(--text-primary);
+ letter-spacing: -0.5px;
+}
+
+.v-stat-card .val small { font-size: 0.7rem; font-weight: 600; margin-left: 4px; opacity: 0.6; }
+.v-stat-card.warning { border-color: var(--alert-red); }
+.v-stat-card.warning .val { color: var(--alert-red); }
+
+.clinical-input {
+ flex: 1;
+ background: #fff;
+ border: 1px solid var(--card-border);
+ border-radius: 16px;
+ padding: 16px;
+ font-family: inherit;
+ font-size: 0.9rem;
+ resize: none;
+ transition: var(--transition-snappy);
+}
+
+.clinical-input:focus {
+ border-color: var(--accent-cyan);
+ outline: none;
+ box-shadow: 0 0 0 4px var(--accent-cyan-glow);
+}
+
+.commit-btn {
+ background: var(--text-primary);
+ color: #fff;
+ border: none;
+ padding: 16px;
+ border-radius: 16px;
+ font-weight: 900;
+ letter-spacing: 0.05em;
+ cursor: pointer;
+ transition: var(--transition-snappy);
+}
+
+.commit-btn:hover { background: #000; transform: translateY(-2px); box-shadow: 0 10px 20px rgba(0,0,0,0.3); }
+
+.idle-surface-placeholder {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+ padding: 40px;
+}
+
+.idle-icon-wrap {
+ position: relative;
+ width: 120px;
+ height: 120px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: var(--text-muted);
+ margin-bottom: 32px;
+}
+
+.idle-ring {
+ position: absolute;
+ inset: -10px;
+ border: 2px dashed var(--card-border);
+ border-radius: 50%;
+ animation: rotate-slow 20s linear infinite;
+}
+
+@keyframes rotate-slow {
+ from { transform: rotate(0deg); }
+ to { transform: rotate(360deg); }
+}
+
+@media (max-width: 1400px) {
+ .active-call-grid { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
+ .clinical-data-rail { border-left: none; border-top: 1px solid var(--card-border); }
+}
.video-controls {
position: absolute;
@@ -1654,12 +4075,12 @@ select.setup-input-premium {
.ps-row { display: grid; grid-template-columns: repeat(2, 1fr); gap: 24px; margin-bottom: 16px; font-size: 0.9rem; }
.ps-row div span { font-weight: 800; display: block; font-size: 0.7rem; color: #64748b; margin-bottom: 4px; }
-/* PREMIUM MODALS */
+/* PROFESSIONAL MODALS */
.premium-modal-overlay {
position: fixed;
inset: 0;
- background: rgba(2, 6, 23, 0.85);
- backdrop-filter: blur(25px);
+ background: rgba(15, 23, 42, 0.6);
+ backdrop-filter: blur(8px);
z-index: 9999;
display: flex;
align-items: center;
@@ -1668,13 +4089,13 @@ select.setup-input-premium {
}
.premium-modal-container {
- background: var(--card-bg);
+ background: #ffffff;
border: 1px solid var(--card-border);
- border-radius: 24px;
+ border-radius: 16px;
width: 100%;
max-width: 680px;
- padding: 32px;
- box-shadow: 0 40px 100px rgba(0, 0, 0, 0.8), inset 0 0 0 1px rgba(255, 255, 255, 0.05);
+ padding: 0;
+ box-shadow: var(--shadow-lg);
position: relative;
overflow: hidden;
}
@@ -1682,94 +4103,1589 @@ select.setup-input-premium {
.premium-modal-container::before {
content: '';
position: absolute;
- top: 0; left: 0; right: 0; height: 2px;
- background: linear-gradient(90deg, transparent, var(--accent-cyan), transparent);
+ top: 0; left: 0; right: 0; height: 3px;
+ background: linear-gradient(90deg, var(--accent-cyan), #3b82f6);
}
.modal-header-premium {
display: flex;
justify-content: space-between;
align-items: center;
- margin-bottom: 24px;
- border-bottom: 1px solid rgba(255, 255, 255, 0.05);
- padding-bottom: 16px;
+ padding: 20px 24px;
+ border-bottom: 1px solid var(--card-border);
}
.modal-header-premium h3 {
- font-size: 1.4rem;
- font-weight: 900;
+ font-size: 1.1rem;
+ font-weight: 700;
margin: 0;
- letter-spacing: -0.5px;
- background: linear-gradient(180deg, #fff 40%, rgba(255,255,255,0.4) 100%);
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
+ color: var(--text-primary);
+ -webkit-text-fill-color: var(--text-primary);
+ background: none;
}
.modal-close-btn {
- background: rgba(255, 255, 255, 0.05);
+ background: #f8fafc;
border: 1px solid var(--card-border);
color: var(--text-secondary);
- width: 36px;
- height: 36px;
- border-radius: 12px;
+ width: 32px;
+ height: 32px;
+ border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
- transition: all 0.3s;
+ transition: all 0.15s;
}
.modal-close-btn:hover {
- background: rgba(255, 59, 59, 0.1);
+ background: rgba(239, 68, 68, 0.08);
color: var(--alert-red);
- border-color: rgba(255, 59, 59, 0.3);
+ border-color: rgba(239, 68, 68, 0.2);
}
.premium-modal-container .setup-form-modern {
- gap: 20px;
+ gap: 16px;
}
.modal-footer-premium {
display: flex;
- gap: 16px;
- margin-top: 32px;
- padding-top: 24px;
- border-top: 1px solid rgba(255, 255, 255, 0.05);
+ gap: 12px;
+ padding: 16px 24px;
+ border-top: 1px solid var(--card-border);
+ background: #fafbfc;
}
.modal-footer-premium button {
flex: 1;
- padding: 14px;
- border-radius: 12px;
- font-weight: 900;
+ padding: 10px;
+ border-radius: 8px;
+ font-weight: 600;
font-size: 0.8rem;
- letter-spacing: 0.1em;
+ letter-spacing: 0.03em;
cursor: pointer;
- transition: all 0.3s;
+ transition: all 0.15s;
border: none;
}
.btn-primary-glass {
background: var(--accent-cyan);
- color: #000;
+ color: #ffffff;
border: none !important;
- box-shadow: 0 10px 30px rgba(0, 209, 255, 0.3);
+ box-shadow: var(--shadow-sm);
}
.btn-primary-glass:hover {
- background: #00ecff;
- color: #000;
- box-shadow: 0 10px 40px rgba(0, 209, 255, 0.5);
- transform: translateY(-2px);
+ background: #0284c7;
+ box-shadow: var(--shadow-md);
}
.btn-secondary-glass {
- background: rgba(255, 255, 255, 0.05);
- color: #fff;
+ background: #ffffff;
+ color: var(--text-secondary);
border: 1px solid var(--card-border) !important;
}
.btn-secondary-glass:hover {
- background: rgba(255, 255, 255, 0.1);
- transform: translateY(-2px);
+ background: #f8fafc;
+ color: var(--text-primary);
+}
+
+/* Responsive Table Utility */
+/* --- PREMIUM HOSPITAL SELECTOR --- */
+.hospital-select-card-premium {
+ background: var(--card-bg);
+ border: 1px solid var(--card-border);
+ border-radius: 28px;
+ padding: 32px;
+ cursor: pointer;
+ display: flex;
+ flex-direction: column;
+ gap: 24px;
+ position: relative;
+ overflow: hidden;
+ transition: var(--transition-smooth);
+}
+
+.hospital-select-card-premium:hover {
+ border-color: var(--accent-cyan-glow);
+ transform: translateY(-8px);
+}
+
+.card-top-accent {
+ position: absolute;
+ top: 0; left: 0; right: 0;
+ height: 6px;
+ background: linear-gradient(90deg, var(--accent-cyan), var(--accent-purple));
+ opacity: 0.15;
+}
+
+.hospital-select-card-premium:hover .card-top-accent {
+ opacity: 1;
+}
+
+.h-icon-cluster {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+}
+
+.h-icon-orb {
+ width: 64px;
+ height: 64px;
+ background: var(--accent-cyan-soft);
+ border-radius: 20px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: var(--accent-cyan);
+ transition: var(--transition-snappy);
+}
+
+.hospital-select-card-premium:hover .h-icon-orb {
+ background: var(--accent-cyan);
+ color: #fff;
+ transform: rotate(-5deg);
+}
+
+.h-status-indicator {
+ width: 12px;
+ height: 12px;
+ border-radius: 50%;
+ position: relative;
+}
+
+.h-status-indicator::after {
+ content: '';
+ position: absolute;
+ inset: -4px;
+ border-radius: 50%;
+ border: 2px solid currentColor;
+ opacity: 0.3;
+}
+
+.h-status-indicator[data-status="active"] { color: var(--accent-green); background: currentColor; }
+.h-status-indicator[data-status="occupied"] { color: var(--warning-amber); background: currentColor; }
+
+.h-name-premium {
+ font-size: 1.5rem;
+ font-weight: 950;
+ color: var(--text-primary);
+ margin: 0;
+ letter-spacing: -0.5px;
+}
+
+.h-type-tag {
+ font-size: 0.65rem;
+ font-weight: 900;
+ color: var(--accent-cyan);
+ background: var(--accent-cyan-soft);
+ padding: 4px 10px;
+ border-radius: 20px;
+ letter-spacing: 0.1em;
+ width: fit-content;
+}
+
+.h-meta-grid {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 12px;
+}
+
+.h-meta-item {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 0.8rem;
+ font-weight: 700;
+ color: var(--text-secondary);
+}
+
+.capacity-section {
+ background: hsla(210, 40%, 96.1%, 0.5);
+ padding: 20px;
+ border-radius: 20px;
+ border: 1px solid var(--card-border);
+}
+
+.capacity-header {
+ display: flex;
+ justify-content: space-between;
+ font-size: 0.7rem;
+ font-weight: 900;
+ color: var(--text-muted);
+ margin-bottom: 12px;
+ letter-spacing: 0.05em;
+}
+
+.capacity-val { color: var(--text-primary); font-weight: 950; }
+
+.capacity-track {
+ height: 8px;
+ background: hsla(0, 0%, 0%, 0.05);
+ border-radius: 10px;
+ overflow: hidden;
+}
+
+.capacity-fill {
+ height: 100%;
+ background: linear-gradient(90deg, var(--accent-cyan), var(--accent-purple));
+ border-radius: 10px;
+}
+
+.h-access-btn {
+ width: 100%;
+ padding: 16px;
+ border-radius: 16px;
+ border: 2px solid var(--accent-cyan-soft);
+ background: transparent;
+ color: var(--accent-cyan);
+ font-weight: 900;
+ font-size: 0.8rem;
+ letter-spacing: 0.05em;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 10px;
+ transition: var(--transition-snappy);
+ cursor: pointer;
+}
+
+.hospital-select-card-premium:hover .h-access-btn {
+ background: var(--accent-cyan);
+ color: #fff;
+ border-color: var(--accent-cyan);
+ box-shadow: 0 10px 20px var(--accent-cyan-glow);
+}
+
+/* --- REFINED GLOBAL OVERLAYS --- */
+.hospital-selection-overlay {
+ background: var(--hull-bg);
+}
+
+.glow-sphere {
+ filter: blur(140px);
+ opacity: 0.15;
+}
+
+.selection-header h1 {
+ font-size: 4.5rem;
+ font-weight: 1000;
+ letter-spacing: -4px;
+ background: linear-gradient(180deg, var(--text-primary) 30%, hsla(222, 47%, 11%, 0.4) 100%);
+ -webkit-background-clip: text;
+ background-clip: text;
+ -webkit-text-fill-color: transparent;
+}
+
+
+/* --- NEW MODULE STYLES --- */
+
+.tab-switcher-premium {
+ display: flex;
+ background: rgba(0, 0, 0, 0.03);
+ padding: 4px;
+ border-radius: 14px;
+ gap: 4px;
+}
+
+.tab-btn {
+ padding: 8px 16px;
+ border-radius: 10px;
+ border: none;
+ background: transparent;
+ color: var(--text-secondary);
+ font-weight: 700;
+ font-size: 0.75rem;
+ cursor: pointer;
+ transition: all 0.3s;
+}
+
+.tab-btn.active {
+ background: #fff;
+ color: var(--accent-cyan);
+ box-shadow: 0 4px 12px rgba(0,0,0,0.05);
+}
+
+/* TeleLink */
+.telelink-main-grid {
+ display: grid;
+ grid-template-columns: 320px 1fr;
+ gap: 24px;
+ height: calc(100vh - 180px);
+}
+
+.call-queue-panel {
+ background: #fff;
+ border: 1px solid var(--card-border);
+ border-radius: 20px;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+}
+
+.panel-header-mini {
+ padding: 16px;
+ border-bottom: 1px solid var(--card-border);
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.panel-header-mini h4 {
+ margin: 0;
+ font-size: 0.75rem;
+ font-weight: 800;
+ color: var(--text-secondary);
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+}
+
+.queue-list {
+ flex: 1;
+ overflow-y: auto;
+ padding: 12px;
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.queue-item {
+ padding: 16px;
+ border-radius: 16px;
+ border: 1px solid var(--card-border);
+ background: #fcfcfc;
+ transition: all 0.3s;
+}
+
+.queue-item.triage-red { border-left: 4px solid var(--alert-red); }
+.queue-item.triage-yellow { border-left: 4px solid var(--warning-amber); }
+
+.q-header {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 8px;
+}
+
+.q-id { font-family: monospace; font-weight: 700; color: var(--text-secondary); font-size: 0.7rem; }
+.q-wait { font-size: 0.7rem; color: var(--alert-red); font-weight: 700; display: flex; align-items: center; gap: 4px; }
+
+.q-patient { font-weight: 800; font-size: 0.9rem; margin-bottom: 4px; }
+.q-complaint { font-size: 0.75rem; color: var(--text-secondary); }
+
+.q-actions {
+ display: flex;
+ gap: 8px;
+ margin-top: 12px;
+}
+
+.q-btn {
+ flex: 1;
+ padding: 8px;
+ border-radius: 8px;
+ border: none;
+ font-weight: 800;
+ font-size: 0.7rem;
+ cursor: pointer;
+ transition: all 0.3s;
+}
+
+.q-btn.accept { background: var(--accent-cyan); color: #fff; }
+.q-btn.decline { background: rgba(0,0,0,0.05); color: var(--text-secondary); }
+
+.call-surface-panel {
+ background: #fff;
+ border: 1px solid var(--card-border);
+ border-radius: 24px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ overflow: hidden;
+ position: relative;
+}
+
+.active-call-layout {
+ display: grid;
+ grid-template-columns: 1fr 300px;
+ width: 100%;
+ height: 100%;
+}
+
+.video-main-container {
+ background: #0f172a;
+ position: relative;
+ display: flex;
+ flex-direction: column;
+}
+
+.video-placeholder {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ color: #fff;
+}
+
+.video-icon { opacity: 0.2; margin-bottom: 16px; }
+
+.patient-overlay {
+ position: absolute;
+ top: 24px;
+ left: 24px;
+}
+
+.p-badge { background: var(--alert-red); color: #fff; font-size: 0.6rem; font-weight: 900; padding: 4px 8px; border-radius: 6px; margin-bottom: 4px; display: inline-block; }
+.p-name { font-size: 1.4rem; font-weight: 900; }
+
+.controls-bar {
+ padding: 20px;
+ display: flex;
+ justify-content: center;
+ gap: 16px;
+ background: rgba(0,0,0,0.4);
+ backdrop-filter: blur(10px);
+}
+
+.ctrl-btn {
+ width: 48px;
+ height: 48px;
+ border-radius: 16px;
+ border: none;
+ background: rgba(255,255,255,0.1);
+ color: #fff;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.3s;
+}
+
+.ctrl-btn:hover { background: rgba(255,255,255,0.2); transform: scale(1.05); }
+.ctrl-btn.end-call { background: var(--alert-red); }
+
+.vitals-side-panel {
+ border-left: 1px solid var(--card-border);
+ padding: 20px;
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+
+.vitals-grid-mini {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 12px;
+}
+
+.v-card-mini {
+ background: #f8fafc;
+ padding: 12px;
+ border-radius: 12px;
+}
+
+.v-card-mini span { font-size: 0.6rem; font-weight: 800; color: var(--text-secondary); text-transform: uppercase; }
+.v-card-mini .val { font-size: 1.1rem; font-weight: 950; color: var(--text-primary); margin-top: 2px; }
+
+.clinical-notes-area {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.clinical-notes-area textarea {
+ flex: 1;
+ border-radius: 12px;
+ border: 1px solid var(--card-border);
+ padding: 12px;
+ font-size: 0.8rem;
+ resize: none;
+}
+
+.save-notes-btn {
+ background: var(--text-primary);
+ color: #fff;
+ border: none;
+ padding: 12px;
+ border-radius: 10px;
+ font-weight: 800;
+ font-size: 0.75rem;
+ cursor: pointer;
+}
+
+/* Fleet View */
+.fleet-visibility-layout {
+ display: grid;
+ grid-template-columns: 1fr 340px;
+ gap: 24px;
+ height: calc(100vh - 180px);
+}
+
+.fleet-map-surface {
+ background: #fff;
+ border: 1px solid var(--card-border);
+ border-radius: 24px;
+ overflow: hidden;
+ position: relative;
+}
+
+.map-placeholder {
+ width: 100%;
+ height: 100%;
+ background: #f1f5f9;
+ position: relative;
+}
+
+.map-grid-bg {
+ position: absolute;
+ inset: 0;
+ background-image:
+ linear-gradient(rgba(0,0,0,0.03) 1px, transparent 1px),
+ linear-gradient(90deg, rgba(0,0,0,0.03) 1px, transparent 1px);
+ background-size: 40px 40px;
+}
+
+.map-marker {
+ position: absolute;
+ background: #fff;
+ padding: 8px;
+ border-radius: 12px;
+ box-shadow: 0 4px 12px rgba(0,0,0,0.1);
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ z-index: 10;
+ transform: translate(-50%, -50%);
+}
+
+.map-marker.status-running { border: 2px solid var(--accent-green); color: var(--accent-green); }
+.map-marker.status-breakdown { border: 2px solid var(--alert-red); color: var(--alert-red); }
+
+.marker-label { font-size: 0.7rem; font-weight: 900; color: var(--text-primary); }
+
+.fleet-scroll-area {
+ flex: 1;
+ overflow-y: auto;
+ padding: 12px;
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.fleet-unit-card {
+ padding: 16px;
+ border-radius: 16px;
+ background: #fff;
+ border: 1px solid var(--card-border);
+}
+
+.fleet-unit-card.has-alert { background: rgba(239, 68, 68, 0.03); border-color: rgba(239, 68, 68, 0.2); }
+
+.unit-header {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 12px;
+}
+
+.unit-id { font-weight: 800; font-size: 0.9rem; }
+.unit-type { font-size: 0.6rem; color: var(--text-secondary); text-transform: uppercase; font-weight: 800; margin-right: 4px; }
+
+.unit-status { font-size: 0.6rem; font-weight: 900; padding: 4px 8px; border-radius: 6px; text-transform: uppercase; }
+.unit-status.status-running { background: rgba(16, 185, 129, 0.1); color: var(--accent-green); }
+
+.detail-row {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 0.75rem;
+ color: var(--text-secondary);
+ margin-bottom: 6px;
+}
+
+.unit-alert-box {
+ margin-top: 12px;
+ padding: 8px;
+ background: var(--alert-red);
+ color: #fff;
+ border-radius: 8px;
+ font-size: 0.7rem;
+ font-weight: 700;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+/* Analytics */
+.analytics-dashboard-grid {
+ display: flex;
+ flex-direction: column;
+ gap: 24px;
+}
+
+.metrics-row-modern {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 20px;
+}
+
+.metric-box-premium {
+ background: #fff;
+ padding: 24px;
+ border-radius: 20px;
+ border: 1px solid var(--card-border);
+ box-shadow: var(--shadow-premium);
+}
+
+.m-header { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
+.m-icon { width: 36px; height: 36px; border-radius: 10px; background: rgba(59, 130, 246, 0.1); color: var(--accent-cyan); display: flex; align-items: center; justify-content: center; }
+.m-title { font-size: 0.65rem; font-weight: 800; color: var(--text-secondary); letter-spacing: 0.05em; }
+
+.m-val { font-size: 1.8rem; font-weight: 950; color: var(--text-primary); }
+.m-trend { font-size: 0.7rem; font-weight: 700; margin-top: 8px; display: flex; align-items: center; gap: 4px; }
+.m-trend.up { color: var(--accent-green); }
+.m-trend.down { color: var(--alert-red); }
+
+.charts-grid-main {
+ display: grid;
+ grid-template-columns: 1fr 400px;
+ gap: 20px;
+}
+
+.chart-card-premium {
+ background: #fff;
+ padding: 24px;
+ border-radius: 20px;
+ border: 1px solid var(--card-border);
+}
+
+.chart-header h4 { margin: 0; font-size: 1rem; font-weight: 900; }
+.chart-header p { margin: 4px 0 20px; font-size: 0.8rem; color: var(--text-secondary); }
+
+/* Referrals */
+.referral-grid-layout {
+ display: grid;
+ grid-template-columns: 1fr 340px;
+ gap: 24px;
+}
+
+.referral-node-card {
+ display: flex;
+ gap: 20px;
+ background: #fff;
+ padding: 24px;
+ border-radius: 24px;
+ border: 1px solid var(--card-border);
+ margin-bottom: 16px;
+ transition: all 0.3s;
+}
+
+.referral-node-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-premium); }
+
+.node-icon-bubble {
+ width: 56px;
+ height: 56px;
+ background: #f8fafc;
+ border-radius: 16px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: var(--accent-cyan);
+}
+
+.node-info-content { flex: 1; }
+.node-top-row { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 16px; }
+.node-title-stack h4 { margin: 0; font-size: 1.1rem; font-weight: 900; }
+.node-type { font-size: 0.7rem; color: var(--text-secondary); font-weight: 700; }
+
+.node-details-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 20px; }
+.d-item { display: flex; align-items: center; gap: 8px; font-size: 0.75rem; color: var(--text-secondary); }
+
+.node-footer-actions { display: flex; gap: 12px; }
+
+.node-action {
+ padding: 8px 12px;
+ border-radius: 8px;
+ border: 1px solid var(--card-border);
+ background: #fcfcfc;
+ font-size: 0.7rem;
+ font-weight: 700;
+ cursor: pointer;
+}
+
+.node-action-danger {
+ padding: 8px 12px;
+ border-radius: 8px;
+ border: 1px solid rgba(239, 68, 68, 0.1);
+ background: rgba(239, 68, 68, 0.05);
+ color: var(--alert-red);
+ font-size: 0.7rem;
+ font-weight: 700;
+}
+
+@media (max-width: 1024px) {
+ .telelink-main-grid, .fleet-visibility-layout, .charts-grid-main, .referral-grid-layout {
+ grid-template-columns: 1fr;
+ }
+}
+
+/* ═══════════════════════════════════════════════════════════════════════════ */
+/* ─── OPS MODULE CARD GRID LANDING ─── */
+/* ═══════════════════════════════════════════════════════════════════════════ */
+
+.ops-card-landing {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 8px 0;
+}
+
+.ops-landing-header {
+ margin-bottom: 32px;
+}
+
+.ops-landing-title-row {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 16px;
+}
+
+.ops-landing-title {
+ font-size: 1.75rem;
+ font-weight: 950;
+ color: var(--text-primary);
+ letter-spacing: -1px;
+ line-height: 1.1;
+ margin: 0;
+}
+
+.ops-landing-subtitle {
+ font-size: 0.85rem;
+ color: var(--text-secondary);
+ font-weight: 600;
+ margin-top: 6px;
+ line-height: 1.4;
+}
+
+.ops-module-count {
+ font-size: 0.68rem;
+ font-weight: 800;
+ color: var(--text-muted);
+ background: hsla(210, 30%, 94%, 0.8);
+ padding: 5px 12px;
+ border-radius: 20px;
+ white-space: nowrap;
+ letter-spacing: 0.03em;
+ border: 1px solid var(--card-border);
+ flex-shrink: 0;
+}
+
+/* ── Card Grid ── */
+.ops-module-grid {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 16px;
+}
+
+/* ── Individual Card ── */
+.ops-module-card {
+ position: relative;
+ background: #fff;
+ border: 1px solid var(--card-border);
+ border-radius: 18px;
+ overflow: hidden;
+ cursor: pointer;
+ text-align: left;
+ padding: 0;
+ transition: border-color 0.25s ease, box-shadow 0.35s ease;
+}
+
+.ops-module-card:hover {
+ border-color: hsla(199, 89%, 48%, 0.25);
+ box-shadow:
+ 0 8px 24px -4px hsla(222, 47%, 11%, 0.08),
+ 0 16px 40px -8px hsla(222, 47%, 11%, 0.06);
+}
+
+.ops-card-accent-bar {
+ height: 4px;
+ width: 100%;
+}
+
+.ops-card-body {
+ display: flex;
+ align-items: center;
+ gap: 16px;
+ padding: 20px 22px;
+}
+
+.ops-card-icon {
+ width: 52px;
+ height: 52px;
+ border-radius: 14px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-shrink: 0;
+ transition: transform 0.3s ease;
+}
+
+.ops-module-card:hover .ops-card-icon {
+ transform: scale(1.08);
+}
+
+.ops-card-text {
+ flex: 1;
+ min-width: 0;
+}
+
+.ops-card-label {
+ font-size: 0.92rem;
+ font-weight: 850;
+ color: var(--text-primary);
+ margin: 0 0 4px;
+ letter-spacing: -0.02em;
+}
+
+.ops-card-desc {
+ font-size: 0.72rem;
+ color: var(--text-muted);
+ font-weight: 600;
+ line-height: 1.4;
+ margin: 0;
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+}
+
+.ops-card-arrow {
+ flex-shrink: 0;
+ opacity: 0;
+ transform: translateX(-6px);
+ transition: opacity 0.25s ease, transform 0.25s ease;
+}
+
+.ops-module-card:hover .ops-card-arrow {
+ opacity: 1;
+ transform: translateX(0);
+}
+
+/* ── Back Button ── */
+.ops-back-btn {
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ background: transparent;
+ border: 1px solid var(--card-border);
+ padding: 7px 16px 7px 12px;
+ border-radius: 10px;
+ color: var(--text-secondary);
+ font-size: 0.8rem;
+ font-weight: 750;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ white-space: nowrap;
+ flex-shrink: 0;
+}
+
+.ops-back-btn:hover {
+ background: hsla(199, 89%, 48%, 0.06);
+ border-color: hsla(199, 89%, 48%, 0.25);
+ color: var(--accent-cyan);
+}
+
+/* ── Breadcrumb ── */
+.ops-module-breadcrumb {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 5px 14px;
+ background: hsla(210, 30%, 94%, 0.6);
+ border-radius: 20px;
+ border: 1px solid var(--card-border);
+ flex-shrink: 0;
+}
+
+.ops-breadcrumb-dot {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ flex-shrink: 0;
+}
+
+.ops-breadcrumb-label {
+ font-size: 0.76rem;
+ font-weight: 800;
+ color: var(--text-primary);
+ letter-spacing: -0.01em;
+ white-space: nowrap;
+}
+
+/* ── Active Module Wrapper ── */
+.ops-active-module {
+ width: 100%;
+}
+
+/* ── Responsive: Tablet ── */
+@media (max-width: 1100px) {
+ .ops-module-grid {
+ grid-template-columns: repeat(2, 1fr);
+ gap: 14px;
+ }
+
+ .ops-landing-title {
+ font-size: 1.4rem;
+ }
+
+ .ops-card-body {
+ padding: 16px 18px;
+ gap: 14px;
+ }
+
+ .ops-card-icon {
+ width: 46px;
+ height: 46px;
+ border-radius: 12px;
+ }
+
+ .ops-card-icon svg {
+ width: 20px;
+ height: 20px;
+ }
+}
+
+/* ── Responsive: Mobile ── */
+@media (max-width: 600px) {
+ .ops-module-grid {
+ grid-template-columns: 1fr;
+ gap: 10px;
+ }
+
+ .ops-landing-title {
+ font-size: 1.2rem;
+ }
+
+ .ops-landing-title-row {
+ flex-direction: column;
+ gap: 8px;
+ }
+
+ .ops-card-body {
+ padding: 14px 16px;
+ gap: 12px;
+ }
+
+ .ops-card-icon {
+ width: 42px;
+ height: 42px;
+ border-radius: 10px;
+ }
+
+ .ops-card-label {
+ font-size: 0.85rem;
+ }
+
+ .ops-card-desc {
+ font-size: 0.68rem;
+ -webkit-line-clamp: 1;
+ }
+
+ .ops-card-arrow {
+ opacity: 0.5;
+ transform: translateX(0);
+ }
+
+ .ops-back-btn {
+ font-size: 0.75rem;
+ padding: 6px 12px 6px 8px;
+ }
+
+ .ops-module-breadcrumb {
+ padding: 4px 10px;
+ }
+
+ .ops-breadcrumb-label {
+ font-size: 0.7rem;
+ }
+}
+
+/* ─── Hospital Picker (Inline) ─── */
+.ops-hospital-picker {
+ flex-shrink: 0;
+}
+
+.ops-picker-indicator {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 6px 12px;
+ background: #fff;
+ border: 1px solid var(--card-border);
+ border-radius: 10px;
+ cursor: pointer;
+ transition: border-color 0.2s ease;
+}
+
+.ops-picker-indicator:hover {
+ border-color: hsla(199, 89%, 48%, 0.3);
+}
+
+.ops-hospital-select {
+ border: none;
+ outline: none;
+ background: transparent;
+ font-size: 0.78rem;
+ font-weight: 750;
+ color: var(--text-primary);
+ cursor: pointer;
+ appearance: none;
+ -webkit-appearance: none;
+ padding-right: 4px;
+ max-width: 200px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+/* ─── Module Topbar ─── */
+.ops-module-topbar {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding-bottom: 20px;
+ margin-bottom: 4px;
+ border-bottom: 1px solid var(--card-border);
+}
+
+/* ─── Spinner Animation ─── */
+@keyframes spin {
+ to { transform: rotate(360deg); }
+}
+
+.spin {
+ animation: spin 0.8s linear infinite;
+}
+
+@media (max-width: 600px) {
+ .ops-module-topbar {
+ gap: 8px;
+ padding-bottom: 14px;
+ flex-wrap: wrap;
+ }
+
+ .ops-hospital-select {
+ font-size: 0.72rem;
+ max-width: 140px;
+ }
+
+ .page-container {
+ padding: 16px !important;
+ }
+}
+
+/* ═══════════════════════════════════════════════════════════════════════════ */
+/* ─── INLINE MODULE RESPONSIVENESS OVERRIDES ─── */
+/* ═══════════════════════════════════════════════════════════════════════════ */
+
+/* Ensure the active module container doesn't overflow the page-container horizontally */
+.ops-active-module {
+ width: 100%;
+ min-width: 0; /* Critical for flex/grid children to not overflow */
+ display: flex;
+ flex-direction: column;
+}
+
+.ops-active-module > * {
+ min-width: 0;
+}
+
+/* Remove fixed 100vh calc heights so modules can scroll naturally within page-container */
+.fleet-visibility-grid-premium,
+.fleet-dashboard-layout,
+.telelink-dashboard-layout,
+.epcr-dashboard-layout,
+.telelink-main-grid,
+.fleet-visibility-layout,
+.ed-grid-modern,
+.analytics-dashboard-grid,
+.referral-grid-layout {
+ height: auto !important;
+ min-height: calc(100vh - 240px);
+}
+
+/* Give minimum heights to scrollable areas inside modules */
+.triage-scroll-area-modern,
+.fleet-scroll-area,
+.map-command-surface,
+.epcr-list-column,
+.epcr-content-column {
+ min-height: 500px;
+}
+
+/* Prevent horizontal overflow on tables and grids */
+.trip-mgmt-table-container,
+.hospital-grid,
+.staff-table-premium,
+.staff-grid,
+.module-content {
+ max-width: 100%;
+ overflow-x: auto;
+}
+
+/* Make wide grids stack earlier on typical laptop screens (1366px) when sidebar is open */
+@media (max-width: 1400px) {
+ .ed-grid-modern,
+ .fleet-visibility-grid-premium,
+ .telelink-main-grid,
+ .fleet-dashboard-layout,
+ .telelink-dashboard-layout,
+ .epcr-dashboard-layout,
+ .referral-grid-layout {
+ grid-template-columns: 1fr !important;
+ gap: 20px;
+ }
+
+ .ed-ops-side-panel,
+ .vitals-side-panel {
+ border-left: none;
+ border-top: 1px solid var(--card-border);
+ }
+
+ .charts-grid-main {
+ grid-template-columns: 1fr;
+ }
+}
+
+
+/* ==========================================================================
+ HOSPITAL OPS DUAL SIDEBAR LAYOUT
+ ========================================================================== */
+.ops-child-sidebar {
+ width: 260px;
+ min-width: 260px;
+ flex-basis: 260px;
+ flex-shrink: 0;
+ background: var(--glass-bg);
+ border-right: 1px solid var(--card-border);
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ z-index: 1000;
+}
+
+.ops-child-sidebar-header {
+ padding: 24px 20px;
+ border-bottom: 1px solid var(--card-border);
+ background: linear-gradient(135deg, rgba(15,23,42,0.8) 0%, rgba(2,6,23,0.9) 100%);
+ flex-shrink: 0;
+}
+
+.ops-hospital-picker-dark {
+ background: rgba(255, 255, 255, 0.05);
+ border: 1px solid rgba(255, 255, 255, 0.1);
+ border-radius: 8px;
+ padding: 8px 12px;
+}
+
+.ops-child-nav {
+ flex: 1;
+ padding: 16px 12px;
+ overflow-y: auto;
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+}
+
+.ops-child-nav-item {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding: 12px 16px;
+ border-radius: 8px;
+ background: transparent;
+ border: none;
+ cursor: pointer;
+ text-align: left;
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
+ position: relative;
+ font-family: inherit;
+}
+
+.ops-child-nav-item:hover {
+ background: rgba(0, 0, 0, 0.03);
+}
+
+.ops-child-nav-item.active {
+ background: var(--bg-primary);
+ font-weight: 700;
+ box-shadow: 0 4px 12px rgba(0,0,0,0.05);
+}
+
+.ops-nav-icon {
+ flex-shrink: 0;
+ transition: color 0.2s;
+}
+
+.ops-nav-label {
+ font-size: 0.9rem;
+ font-weight: inherit;
+ color: var(--text-primary);
+ flex: 1;
+}
+
+.ops-nav-indicator {
+ position: absolute;
+ left: 0;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 4px;
+ height: 20px;
+ border-radius: 0 4px 4px 0;
+}
+
+.ops-active-module-wrapper {
+ animation: fadeIn 0.3s ease-out;
+}
+
+@keyframes fadeIn {
+ from { opacity: 0; transform: translateY(10px); }
+ to { opacity: 1; transform: translateY(0); }
+}
+
+/* PROFESSIONAL ED MONITOR DESIGN - DECENT & CLEAN */
+.ed-monitor-tactical {
+ --tactical-bg: #f8fafc;
+ --tactical-border: #e2e8f0;
+ --monitor-dark: #1e293b;
+}
+
+.metrics-row-modern {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ gap: 20px;
+ margin-bottom: 24px;
+}
+
+.metric-card-premium {
+ background: #ffffff;
+ border: 1px solid var(--tactical-border);
+ border-radius: 12px;
+ padding: 16px 20px;
+ display: flex;
+ align-items: center;
+ gap: 16px;
+ transition: border-color 0.2s;
+}
+
+.metric-card-premium:hover {
+ border-color: #cbd5e1;
+}
+
+.metric-icon-wrap {
+ width: 40px;
+ height: 40px;
+ border-radius: 10px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: #f1f5f9;
+}
+
+.tactical-board-container {
+ background: #fff;
+ border-radius: 16px;
+ border: 1px solid var(--tactical-border);
+ padding: 24px;
+ min-height: 500px;
+}
+
+.tactical-patient-card {
+ background: #ffffff;
+ border: 1px solid var(--tactical-border);
+ border-radius: 12px;
+ margin-bottom: 12px;
+ overflow: hidden;
+ display: flex;
+ position: relative;
+ min-width: 0;
+}
+
+.card-status-indicator {
+ width: 6px;
+ height: auto;
+ flex-shrink: 0;
+}
+
+.card-status-indicator.RED { background: #ef4444; }
+.card-status-indicator.ORANGE { background: #f97316; }
+.card-status-indicator.YELLOW { background: #eab308; }
+.card-status-indicator.GREEN { background: #22c55e; }
+.card-status-indicator.WHITE { background: #e2e8f0; }
+
+.card-main-tactical {
+ flex: 1;
+ display: grid;
+ grid-template-columns: 200px 1fr 320px 160px;
+ align-items: center;
+ padding: 16px 24px;
+ gap: 24px;
+}
+
+.unit-info-hex {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+}
+
+.unit-label-premium {
+ font-family: 'Inter', sans-serif;
+ font-size: 0.75rem;
+ font-weight: 700;
+ color: #475569;
+ background: #f1f5f9;
+ padding: 4px 10px;
+ border-radius: 6px;
+ width: max-content;
+ text-transform: uppercase;
+}
+
+.p-identity-block {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+}
+
+.p-name-premium {
+ font-size: 1.1rem;
+ font-weight: 700;
+ color: #1e293b;
+}
+
+.p-meta-inline {
+ font-size: 0.8rem;
+ color: #64748b;
+ font-weight: 500;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.vitals-monitor-block {
+ background: #f8fafc;
+ border: 1px solid #e2e8f0;
+ border-radius: 12px;
+ padding: 12px 20px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.v-node-tactical {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.v-node-tactical .v-val {
+ font-family: 'Inter', sans-serif;
+ font-size: 1.15rem;
+ font-weight: 800;
+ color: #1e293b;
+}
+
+.v-node-tactical .v-lbl {
+ font-size: 0.65rem;
+ font-weight: 700;
+ color: #64748b;
+ text-transform: uppercase;
+ margin-top: 2px;
+}
+
+.v-node-tactical.hr .v-val { color: #ef4444; }
+.v-node-tactical.spo2 .v-val { color: #0ea5e9; }
+.v-node-tactical.bp .v-val { color: #10b981; }
+
+.tactical-actions {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ padding-left: 20px;
+ border-left: 1px solid #f1f5f9;
+}
+
+.action-btn-tactical {
+ height: 34px;
+ border-radius: 8px;
+ border: 1px solid #e2e8f0;
+ background: #fff;
+ color: #475569;
+ font-size: 0.75rem;
+ font-weight: 600;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ cursor: pointer;
+ transition: background 0.2s;
+}
+
+.action-btn-tactical:hover {
+ background: #f8fafc;
+}
+
+.action-btn-tactical.primary {
+ background: #1e293b;
+ border-color: #1e293b;
+ color: #fff;
+}
+
+.action-btn-tactical.primary:hover {
+ background: #0f172a;
+}
+
+.complaint-badge-tactical {
+ background: #f1f5f9;
+ color: #475569;
+ padding: 4px 10px;
+ border-radius: 6px;
+ font-size: 0.7rem;
+ font-weight: 700;
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ width: max-content;
+}
+
+.complaint-badge-tactical.CRITICAL {
+ background: #fee2e2;
+ color: #b91c1c;
+}
+
+/* RESPONSIVE TACTICAL DESIGN */
+@media (max-width: 1440px) {
+ .card-main-tactical {
+ grid-template-columns: 200px 1fr 280px 160px;
+ padding: 20px 24px;
+ gap: 16px;
+ }
+ .v-node-tactical .v-val { font-size: 1.2rem; }
+ .p-name-premium { font-size: 1.1rem; }
+}
+
+@media (max-width: 1280px) {
+ .card-main-tactical {
+ grid-template-columns: 180px 1fr 240px 150px;
+ }
+}
+
+@media (max-width: 1100px) {
+ .card-main-tactical {
+ grid-template-columns: 1fr 1fr;
+ grid-template-rows: auto auto;
+ gap: 20px;
+ }
+ .tactical-actions {
+ border-left: none;
+ padding-left: 0;
+ flex-direction: row;
+ grid-column: span 2;
+ border-top: 1px solid #f1f5f9;
+ padding-top: 16px;
+ }
+ .vitals-monitor-block {
+ grid-column: span 1;
+ }
+}
+
+/* FINAL RESPONSIVE FIX FOR TACTICAL ED MONITOR */
+.ed-grid-modern {
+ display: grid;
+ grid-template-columns: 1fr 380px;
+ gap: 32px;
+ align-items: start;
+ width: 100%;
+}
+
+.tactical-patient-card {
+ width: 100%;
+ min-width: 0;
+}
+
+.card-main-tactical {
+ display: grid;
+ grid-template-columns: 200px 1fr 320px 160px;
+ align-items: center;
+ padding: 16px 24px;
+ gap: 24px;
+ width: 100%;
+}
+
+@media (max-width: 1600px) {
+ .ed-grid-modern {
+ grid-template-columns: 1fr 320px;
+ gap: 24px;
+ }
+ .card-main-tactical {
+ grid-template-columns: 180px 1fr 280px 150px;
+ gap: 16px;
+ padding: 16px;
+ }
+}
+
+@media (max-width: 1400px) {
+ .ed-grid-modern {
+ grid-template-columns: 1fr;
+ }
+ .ed-intel-sidebar {
+ display: grid !important;
+ grid-template-columns: 1fr 1fr;
+ gap: 20px;
+ }
+}
+
+@media (max-width: 1200px) {
+ .card-main-tactical {
+ grid-template-columns: 1fr 1fr;
+ grid-template-rows: auto auto;
+ }
+ .tactical-actions {
+ grid-column: span 2;
+ border-left: none;
+ padding-left: 0;
+ border-top: 1px solid #f1f5f9;
+ padding-top: 16px;
+ flex-direction: row;
+ }
+}
+
+@media (max-width: 900px) {
+ .ed-intel-sidebar {
+ grid-template-columns: 1fr;
+ }
+ .metrics-row-modern {
+ grid-template-columns: 1fr 1fr;
+ }
+}
+
+@media (max-width: 768px) {
+ .card-main-tactical {
+ grid-template-columns: 1fr;
+ padding: 20px;
+ }
+ .vitals-monitor-block, .unit-info-hex, .p-identity-block, .tactical-actions {
+ grid-column: span 1;
+ }
+ .tactical-actions {
+ flex-direction: column;
+ }
+ .detail-module-grid { /* For the expanded view */
+ grid-template-columns: 1fr !important;
+ }
+}
+
+@media (max-width: 480px) {
+ .metrics-row-modern {
+ grid-template-columns: 1fr;
+ }
}
diff --git a/src/pages/HospitalConsole.tsx b/src/pages/HospitalConsole.tsx
index 999322d..5c50b6c 100644
--- a/src/pages/HospitalConsole.tsx
+++ b/src/pages/HospitalConsole.tsx
@@ -1,140 +1,119 @@
import React, { useState, useEffect } from 'react';
-import {
- Building2,
- Activity,
- Truck,
- PhoneCall,
- FileText,
- Settings,
- Plus,
- Search,
- MapPin,
- Clock,
- ShieldAlert,
- CheckCircle2,
- XCircle,
- ChevronRight,
- ChevronDown,
- HeartPulse,
- Share2,
- AlertTriangle,
+import { useSearchParams } from 'react-router-dom';
+import {
+ Building2,
+ Activity,
+ Truck,
+ FileText,
+ Settings,
+ CheckCircle2,
Monitor,
- Users,
- LayoutDashboard,
TrendingUp,
- Printer,
- Download,
- Filter,
- Map as MapIcon,
- Video,
- Mic,
- MoreVertical,
- ExternalLink,
- Save,
- Bell,
- Navigation,
- Calendar,
- AlertCircle,
- Heart,
- Wind,
- Thermometer,
- Zap,
Database,
- Lock,
- Stethoscope,
- Phone,
- Trash2,
- Timer,
- CheckCircle,
- Menu,
- X,
- Eye,
- EyeOff
+ Video,
+ Hospital,
+ ChevronDown,
} from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';
-import { Card, StatCard } from '../components/Common';
+import { Card } from '../components/Common';
import { authApi } from '../api/auth';
+import { hospitalApi } from '../api/hospital';
+import { HospitalSelector } from './hospital/HospitalSelector';
+import { EDMonitor } from './hospital/EDMonitor';
+import { TripManagement } from './hospital/TripManagement';
+import { SetupPanel } from './hospital/SetupPanel';
+import { StaffModal } from './hospital/StaffModal';
+import { DeptModal } from './hospital/DeptModal';
+import { TeleLinkHub } from './hospital/TeleLinkHub';
+import { FleetView } from './hospital/FleetView';
+import { EPCRRecords } from './hospital/EPCRRecords';
+import { PatientArchive } from './hospital/PatientArchive';
+import { ReferralsSetup } from './hospital/ReferralsSetup';
+import { HospitalAnalytics } from './hospital/HospitalAnalytics';
import './HospitalConsole.css';
-type ConsoleModule = 'ED_MONITOR' | 'BOOKINGS' | 'FLEET' | 'TELELINK' | 'EPCR' | 'HISTORY' | 'REPORTS' | 'SETUP' | 'REFERRALS';
+type ConsoleModule =
+ | 'ED_MONITOR'
+ | 'BOOKINGS'
+ | 'FLEET'
+ | 'TELELINK'
+ | 'EPCR'
+ | 'HISTORY'
+ | 'REPORTS'
+ | 'SETUP'
+ | 'REFERRALS';
+// ─── Static data ─────────────────────────────────────────────────────────────
+
+import { incidentsApi } from '../api/incidents';
+
+const INITIAL_TRIPS: any[] = [];
+const FLEET_DATA: any[] = [];
+const EPCR_DATA: any[] = [];
+const TELELINK_QUEUE: any[] = [];
+
+// ─── Component ───────────────────────────────────────────────────────────────
export const HospitalConsole: React.FC = () => {
+ // ── Core state ──
const [hospitals, setHospitals] = useState([]);
const [isLoadingHospitals, setIsLoadingHospitals] = useState(true);
const [selectedHospital, setSelectedHospital] = useState(null);
- const [editingHospital, setEditingHospital] = useState(null);
- const [isUpdating, setIsUpdating] = useState(false);
- const [activeModule, setActiveModule] = useState('ED_MONITOR');
- const [isBookingModalOpen, setIsBookingModalOpen] = useState(false);
- const [successMessage, setSuccessMessage] = useState('');
- const [setupSubTab, setSetupSubTab] = useState('PROFILE');
- const [departments, setDepartments] = useState([]);
- const [isDeptModalOpen, setIsDeptModalOpen] = useState(false);
- const [deptFormData, setDeptFormData] = useState({
- name: '',
- headOfDepartment: '',
- totalBedsCapacity: 0,
- contactPhone: '',
- isActive: true
- });
- const [newBedUnit, setNewBedUnit] = useState({ dept: '', total: 10, occupied: 0 });
- const [isAddingBed, setIsAddingBed] = useState(false);
- const [bedUnits, setBedUnits] = useState([
- { id: 1, dept: 'Emergency Room', total: 12, occupied: 8, status: 'LIVE' },
- { id: 2, dept: 'ICU - Level 1', total: 8, occupied: 7, status: 'LIVE' },
- { id: 3, dept: 'Trauma Unit', total: 4, occupied: 2, status: 'MANUAL' }
- ]);
- const [incomingPatients] = useState([
- { id: 'T-9821', name: 'Rajesh Khanna', age: 45, gender: 'M', triage: 'RED', complaint: 'Cardiac Arrest', eta: '4m', reg: 'KA-01-EF-2291', ambulanceId: 'CURE-ALS-01', vitals: { hr: '124', spo2: '88', bp: '90/60', temp: '98.6' }, location: 'Electronic City' },
- { id: 'T-9825', name: 'Sunita Rao', age: 32, gender: 'F', triage: 'YELLOW', complaint: 'Respiratory Distress', eta: '7m', reg: 'KA-05-MN-8832', ambulanceId: 'CURE-BLS-09', vitals: { hr: '98', spo2: '94', bp: '130/85', temp: '101.2' }, location: 'HSR Layout' },
- { id: 'T-9830', name: 'Unknown Male', age: 28, gender: 'M', triage: 'RED', complaint: 'Multiple Trauma', eta: '2m', reg: 'KA-03-GH-1102', ambulanceId: 'CURE-ALS-04', vitals: { hr: '142', spo2: '82', bp: '70/40', temp: '97.4' }, location: 'Koramangala' },
- { id: 'T-9835', name: 'Amit Shah', age: 58, gender: 'M', triage: 'GREEN', complaint: 'Fracture - Tibia', eta: '12m', reg: 'KA-02-KL-4451', ambulanceId: 'CURE-PTS-12', vitals: { hr: '82', spo2: '98', bp: '120/80', temp: '98.8' }, location: 'Indiranagar' }
- ]);
- const [tripsData, setTripsData] = useState([
- { id: 'TR-4022', patient: 'Anil Kapur', mrn: 'MRN-9022', type: 'IFT-CRITICAL', origin: 'District Hospital', destination: 'Apollo Main', vehicle: 'ALS-04', crew: 'Dr. Arjun, EMT Som', status: 'IN TRANSIT', eta: '6m', urgency: 'RED', step: 2 },
- { id: 'TR-4025', patient: 'Priya Verma', mrn: 'MRN-1102', type: 'EMERGENCY', origin: 'Indiranagar', destination: 'Apollo Main', vehicle: 'BLS-12', crew: 'EMT Suman, Pilot Ravi', status: 'ARRIVED', eta: '0m', urgency: 'YELLOW', step: 3 },
- { id: 'TR-4030', patient: 'Sarah Khan', mrn: 'MRN-4451', type: 'IFT', origin: 'Apollo Main', destination: 'Narayana Health', vehicle: 'ALS-09', crew: 'EMT Kiran, Pilot Dev', status: 'DISPATCHED', eta: '15m', urgency: 'GREEN', step: 1 },
- ]);
- const [isAddingDept, setIsAddingDept] = useState(false);
- const [newDeptName, setNewDeptName] = useState('');
- const [allUsers, setAllUsers] = useState([]);
- const [userSearchTerm, setUserSearchTerm] = useState('');
- const [isStaffModalOpen, setIsStaffModalOpen] = useState(false);
- const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
- const [staffFormData, setStaffFormData] = useState({
- name: '',
- email: '',
- phone: '',
- username: '',
- password: '',
- role: 'ED_DOCTOR',
- department: '',
- specialization: '',
- license: '',
- designation: '',
- shift: 'General'
- });
+
+ const [searchParams, setSearchParams] = useSearchParams();
+ const activeModule = (searchParams.get('tab') as ConsoleModule) || 'ED_MONITOR';
+ const setActiveModule = (key: ConsoleModule) => {
+ setSearchParams({ tab: key });
+ };
- const [user, setUser] = useState(null);
+ // activeModule defaults to ED_MONITOR when tab param exists
+ // When no tab is set, we show the card landing page
+
+ const [successMessage, setSuccessMessage] = useState('');
+
+ // ── Data state ──
+ const [incomingPatients, setIncomingPatients] = useState([]);
+ const [tripsData, setTripsData] = useState(INITIAL_TRIPS);
+ const [departments, setDepartments] = useState([]);
+ const [allUsers, setAllUsers] = useState([]);
const [rolesList, setRolesList] = useState([]);
+ const [user, setUser] = useState(null);
+
+ // ── Modal state ──
+ const [isBookingModalOpen, setIsBookingModalOpen] = useState(false);
+ const [isStaffModalOpen, setIsStaffModalOpen] = useState(false);
+ const [isEditingStaff, setIsEditingStaff] = useState(false);
+ const [editingStaffId, setEditingStaffId] = useState(null);
+ const [isDeptModalOpen, setIsDeptModalOpen] = useState(false);
+ const [isUpdating, setIsUpdating] = useState(false);
+ const [setupSubTab, setSetupSubTab] = useState('PROFILE');
const [showPassword, setShowPassword] = useState(false);
+ // ── Form state ──
+ const [staffFormData, setStaffFormData] = useState({
+ name: '', email: '', phone: '', username: '', password: '',
+ role: 'ED_DOCTOR', department: '', specialization: '',
+ license_number: '', designation: '', shift: 'General',
+ employee_id: '', org_id: '', assigned_floor: '', languages: ''
+ });
+ const [deptFormData, setDeptFormData] = useState({
+ name: '', headOfDepartment: '', totalBedsCapacity: 0,
+ contactPhone: '', isActive: true,
+ });
+
+ // ── Load user from localStorage ──
useEffect(() => {
const userData = localStorage.getItem('teleems_user');
- if (userData) {
- setUser(JSON.parse(userData));
- }
+ if (userData) setUser(JSON.parse(userData));
}, []);
+ // ── Fetch roles ──
useEffect(() => {
const loadRoles = async () => {
try {
const token = localStorage.getItem('teleems_token') || '';
if (!token) return;
const res = await authApi.getRoles(token);
- if (res.data && res.data.data) {
- setRolesList(res.data.data);
- }
+ if (res.data?.data) setRolesList(res.data.data);
} catch (err) {
console.error('Failed to fetch roles:', err);
}
@@ -142,6 +121,125 @@ export const HospitalConsole: React.FC = () => {
loadRoles();
}, []);
+ // ── Fetch trips ──
+ useEffect(() => {
+ const loadTrips = async () => {
+ try {
+ const token = localStorage.getItem('teleems_token') || '';
+ if (!token) return;
+ const res = await incidentsApi.getIncidents({}, token);
+ if (res.data) {
+ const formatted = (Array.isArray(res.data) ? res.data : []).map((inc: any) => ({
+ id: inc.id.substring(0, 8).toUpperCase(),
+ patient: inc.patients?.[0]?.name || 'Unknown',
+ mrn: `MRN-${inc.id.substring(8, 12).toUpperCase()}`,
+ type: inc.category || 'EMERGENCY',
+ origin: inc.address || 'Field Location',
+ destination: selectedHospital?.name || 'Hospital',
+ vehicle: 'Pending',
+ crew: 'Pending',
+ status: inc.status || 'PENDING',
+ eta: 'TBD',
+ urgency: inc.severity || 'YELLOW',
+ step: Math.max(1, inc.status === 'COMPLETED' ? 4 : (inc.status === 'ACTIVE' ? 2 : 1))
+ }));
+ setTripsData(formatted);
+ }
+ } catch (err) {
+ console.error('Failed to fetch trips:', err);
+ setTripsData([]);
+ }
+ };
+ loadTrips();
+ const interval = setInterval(loadTrips, 15000); // 15-sec poll
+ return () => clearInterval(interval);
+ }, [selectedHospital]);
+
+ // ── Fetch incoming patients for ED Monitor ──
+ useEffect(() => {
+ const loadIncoming = async () => {
+ try {
+ const token = localStorage.getItem('teleems_token') || '';
+ if (!token) return;
+ const orgId = user?.organisationId || user?.hospitalId || selectedHospital?.rawUser?.organisationId || selectedHospital?.id;
+ const res = await hospitalApi.getIncomingOperations(token, orgId);
+ console.log('[DEBUG] Incoming Operations Full Response:', res);
+
+ let items = [];
+ if (res.data?.data?.items && Array.isArray(res.data.data.items)) {
+ items = res.data.data.items;
+ } else if (res.data?.items && Array.isArray(res.data.items)) {
+ items = res.data.items;
+ } else if (Array.isArray(res.data?.data)) {
+ items = res.data.data;
+ } else if (Array.isArray(res.data)) {
+ items = res.data;
+ } else if (Array.isArray(res.items)) {
+ items = res.items;
+ }
+
+ console.log('[DEBUG] Extracted Items:', items);
+
+ if (items.length > 0) {
+ const flattenedPatients: any[] = [];
+ items.forEach((dispatch: any) => {
+ const rawPatients = dispatch.patients || dispatch.patient_data;
+ const patientsArr = Array.isArray(rawPatients) ? rawPatients : (rawPatients ? [rawPatients] : [{}]);
+
+ patientsArr.forEach((patient: any, idx: number) => {
+ const pId = patient.id || dispatch.dispatch_id || `idx-${idx}`;
+ flattenedPatients.push({
+ id: `${pId}-${idx}`,
+ originalId: pId,
+ mrn: patient.mrn || String(pId).substring(0, 8).toUpperCase(),
+ name: patient.name || dispatch.patient_name || 'Unknown Patient',
+ age: patient.age || dispatch.patient_age || '--',
+ gender: patient.gender || dispatch.patient_gender || '--',
+ triage: patient.triage_level || dispatch.severity || 'GREEN',
+ complaint: patient.chief_complaint || patient.symptoms?.[0]?.name || dispatch.category || 'Observation',
+ eta: dispatch.eta_seconds ? Math.floor(dispatch.eta_seconds / 60) + 'm' : 'TBD',
+ ambulanceId: (dispatch.dispatch_id || 'UNIT').substring(0, 8).toUpperCase(),
+ status: dispatch.status || 'IN_TRANSIT',
+ vitals: { hr: '--', spo2: '--', bp: '--/--' },
+ location: 'In Transit',
+ gcs: patient.gcs || null,
+ hpi: patient.hpi || null,
+ avpu: patient.avpu || '--',
+ pupils: patient.pupils || null,
+ trauma: patient.trauma || null,
+ allergies: patient.allergies || [],
+ surgeries: patient.surgeries || [],
+ conditions: patient.conditions || [],
+ medications: patient.medications || [],
+ informer: {
+ name: patient.informer_name || '--',
+ relation: patient.informer_relation || '--',
+ phone: patient.informer_phone || '--'
+ },
+ mlc: {
+ is_mlc: patient.is_mlc || false,
+ fir: patient.mlc_fir_number || '--',
+ station: patient.mlc_police_station || '--',
+ officer: patient.mlc_officer_contact || '--'
+ }
+ });
+ });
+ });
+ console.log('[DEBUG] Final Flattened Patients:', flattenedPatients);
+ setIncomingPatients(flattenedPatients);
+ } else {
+ setIncomingPatients([]);
+ }
+ } catch (err) {
+ console.error('Failed to fetch incoming patients:', err);
+ }
+ };
+ loadIncoming();
+ const interval = setInterval(loadIncoming, 15000);
+ return () => clearInterval(interval);
+ }, [selectedHospital]);
+
+ // ── Fetch departments ──
useEffect(() => {
const fetchDepartments = async () => {
const token = localStorage.getItem('teleems_token');
@@ -152,7 +250,7 @@ export const HospitalConsole: React.FC = () => {
const hospId = selectedHospital.rawUser?.hospitalId || selectedHospital.id;
setDepartments(res.data.filter((d: any) => d.hospitalId === hospId));
}
- } catch(err) {
+ } catch (err) {
console.error('Failed to fetch departments:', err);
}
}
@@ -160,16 +258,11 @@ export const HospitalConsole: React.FC = () => {
fetchDepartments();
}, [selectedHospital]);
- const userRoles = user?.roles?.map((r: any) => String(r).toUpperCase()) || [];
- const isAdmin = userRoles.includes('ADMIN') || userRoles.includes('HOSPITAL_ADMIN') || userRoles.includes('CURESELECT_ADMIN');
-
+ // ── Fetch hospitals ──
useEffect(() => {
const fetchHospitals = async () => {
const token = localStorage.getItem('teleems_token');
- if (!token) {
- setIsLoadingHospitals(false);
- return;
- }
+ if (!token) { setIsLoadingHospitals(false); return; }
try {
const response = await authApi.getUsers(token);
@@ -187,80 +280,103 @@ export const HospitalConsole: React.FC = () => {
const org = u.metadata?.organization || {};
return {
id: u.id,
- name: h.name || org.company_name || u.name || u.username || "Unknown Hospital",
- type: h.specialization || h.type || "General Care",
- address: h.city || org.city || "Bangalore",
+ name: h.name || org.company_name || u.name || u.username || 'Unknown Hospital',
+ type: h.specialization || h.type || 'General Care',
+ address: h.city || org.city || 'Bangalore',
floor: h.floor || 0,
lat: h.lat || 13.0827,
lon: h.lon || 80.2707,
status: u.status === 'ACTIVE' ? 'Active' : 'Occupied',
- beds: h.beds || "12/50",
+ beds: h.beds || '12/50',
icon: ,
specialty: h.specialization ? [h.specialization] : ['General'],
admin: u.name,
email: u.email,
phone: u.phone,
- rawUser: u
+ rawUser: u,
};
});
setHospitals(mappedHospitals);
+
+ // Auto-select first hospital if none selected
+ if (!selectedHospital && mappedHospitals.length > 0) {
+ setSelectedHospital(mappedHospitals[0]);
+ }
}
} catch (error) {
- console.error("Failed to fetch hospitals:", error);
- setHospitals([
- {
- id: 'hosp-001',
- name: 'Apollo Main Hospital',
- type: 'Multispecialty',
- address: 'Greams Road, Chennai',
- status: 'Active',
- beds: '42/150',
- admin: 'Dr. Ramesh R.',
- rawUser: { id: 'hosp-001', metadata: { hospital: { id: 'hosp-001' } } }
- }
- ]);
+ console.error('Failed to fetch hospitals:', error);
+ setHospitals([]);
} finally {
setIsLoadingHospitals(false);
}
};
fetchHospitals();
- }, [isUpdating]);
+ }, []);
- const handleUpdateInternal = async () => {
+ // ── Fetch specific profile ──
+ useEffect(() => {
+ const fetchProfile = async () => {
+ const token = localStorage.getItem('teleems_token');
+ if (!token) return;
+ try {
+ const res = await hospitalApi.getProfile(token);
+ console.log("PROFILE API RESPONSE:", res);
+
+ if (res.data) {
+ const apiData = res.data.metadata?.hospital || res.data.profile || res.data;
+
+ setSelectedHospital((prev: any) => ({
+ ...prev,
+ ...apiData,
+ name: apiData.hospitalName || apiData.name || prev?.name || '',
+ contact_phone: apiData.contact_phone || apiData.phone || prev?.contact_phone || '',
+ contact_email: apiData.contact_email || apiData.email || prev?.contact_email || '',
+ address: apiData.address || prev?.address || '',
+ emergency_phone: apiData.emergency_phone || prev?.emergency_phone || '',
+ gps_lat: apiData.gps_lat || prev?.gps_lat || '',
+ gps_lon: apiData.gps_lon || prev?.gps_lon || '',
+ nabh_status: apiData.nabh_status || prev?.nabh_status || false,
+ // Keep the raw user object around just in case
+ rawUser: res.data
+ }));
+ }
+ } catch (err) {
+ console.error('Failed to fetch hospital profile:', err);
+ }
+ };
+ fetchProfile();
+ }, []);
+
+
+ // ── Handlers ──
+ const handleSaveProfile = async () => {
if (!selectedHospital) return;
-
setIsUpdating(true);
try {
const token = localStorage.getItem('teleems_token');
if (!token) throw new Error('Not authenticated');
- const u = selectedHospital.rawUser || selectedHospital.raw;
- if (!u) throw new Error('Hospital metadata missing');
-
const payload = {
- ...u,
- name: selectedHospital.name,
- metadata: {
- ...u.metadata,
- hospital: {
- ...u.metadata.hospital,
- name: selectedHospital.name,
- city: selectedHospital.address,
- specialization: selectedHospital.type,
- floor: parseInt(selectedHospital.floor) || 0,
- lat: parseFloat(selectedHospital.lat) || 0,
- lon: parseFloat(selectedHospital.lon) || 0
- }
- }
+ name: selectedHospital.name || '',
+ address: selectedHospital.address || '',
+ emergency_phone: selectedHospital.emergency_phone || '',
+ contact_phone: selectedHospital.contact_phone || '',
+ contact_email: selectedHospital.contact_email || '',
+ gps_lat: parseFloat(selectedHospital.gps_lat) || 0,
+ gps_lon: parseFloat(selectedHospital.gps_lon) || 0,
+ nabh_status: selectedHospital.nabh_status || false
};
- const result = await authApi.updateUser(u.id, payload, token);
+ const result = await hospitalApi.updateProfile(payload, token);
+ console.log('PATCH RESPONSE:', result);
+
if (result.status === 200 || result.status === 201 || !result.error) {
setSuccessMessage('Configuration Updated!');
setTimeout(() => setSuccessMessage(''), 3000);
} else {
+ console.error('PATCH FAILED:', result);
alert(result.message || 'Update failed');
}
} catch (err: any) {
@@ -270,887 +386,338 @@ export const HospitalConsole: React.FC = () => {
}
};
- const handleUpdateHospital = async (e: React.FormEvent) => {
- e.preventDefault();
- if (!editingHospital) return;
-
- setIsUpdating(true);
- const token = localStorage.getItem('teleems_token');
- if (!token) return;
-
+ const handleRegisterStaff = async () => {
try {
- const u = editingHospital.rawUser;
- const payload = {
- ...u,
- name: editingHospital.name,
- metadata: {
- ...u.metadata,
- hospital: {
- ...u.metadata.hospital,
- name: editingHospital.name,
- city: editingHospital.address,
- specialization: editingHospital.type,
- floor: parseInt(editingHospital.floor) || 0,
- lat: parseFloat(editingHospital.lat) || 0,
- lon: parseFloat(editingHospital.lon) || 0
- }
- }
+ const token = localStorage.getItem('teleems_token');
+
+ const basePayload: any = {
+ phone: staffFormData.phone,
+ email: staffFormData.email,
+ name: staffFormData.name,
+ username: staffFormData.username,
+ role: staffFormData.role,
};
- const result = await authApi.updateUser(u.id, payload, token);
- if (result.status === 200 || result.status === 201 || !result.error) {
- setSuccessMessage('Node updated successfully!');
- setTimeout(() => setSuccessMessage(''), 3000);
- setEditingHospital(null);
- } else {
- alert(result.message || 'Update failed');
+ if (staffFormData.password) {
+ basePayload.password = staffFormData.password;
}
- } catch (error) {
- console.error('Update failed:', error);
- } finally {
- setIsUpdating(false);
+
+ let finalPayload: any = { ...basePayload };
+
+ if (staffFormData.role === 'ED_DOCTOR') {
+ finalPayload.metadata = {
+ specialization: staffFormData.specialization,
+ license_number: staffFormData.license_number,
+ department: staffFormData.department,
+ designation: staffFormData.designation,
+ shift: staffFormData.shift,
+ };
+ } else if (staffFormData.role === 'Hospital Coordinator') {
+ finalPayload.department = staffFormData.department;
+ finalPayload.designation = staffFormData.designation;
+ finalPayload.metadata = {
+ shift: staffFormData.shift,
+ languages: staffFormData.languages ? staffFormData.languages.split(',').map(s => s.trim()) : [],
+ };
+ } else if (staffFormData.role === 'Hospital Nurse') {
+ finalPayload.department = staffFormData.department;
+ finalPayload.designation = staffFormData.designation;
+ finalPayload.employee_id = staffFormData.employee_id;
+ finalPayload.org_id = staffFormData.org_id || selectedHospital?.rawUser?.organisationId;
+ finalPayload.metadata = {
+ shift: staffFormData.shift,
+ languages: staffFormData.languages ? staffFormData.languages.split(',').map(s => s.trim()) : [],
+ assigned_floor: staffFormData.assigned_floor,
+ };
+ } else {
+ // Fallback for other roles
+ finalPayload.org_id = selectedHospital?.rawUser?.organisationId;
+ finalPayload.metadata = {
+ department: staffFormData.department,
+ designation: staffFormData.designation,
+ shift: staffFormData.shift,
+ };
+ }
+
+ let res;
+ if (isEditingStaff && editingStaffId) {
+ // Backend forbids updating username and password via this endpoint
+ delete finalPayload.username;
+ delete finalPayload.password;
+ res = await authApi.updateUser(editingStaffId, finalPayload, token || '');
+ } else {
+ res = await hospitalApi.registerStaff(finalPayload, token || '');
+ }
+
+ if (res.status === 201 || res.status === 200 || !res.error) {
+ setSuccessMessage(`Staff ${isEditingStaff ? 'updated' : 'registered'} successfully.`);
+ setIsStaffModalOpen(false);
+ setIsEditingStaff(false);
+ setEditingStaffId(null);
+
+ // Refresh users list
+ const usersRes = await authApi.getUsers(token || '');
+ if (usersRes.data) {
+ setAllUsers(usersRes.data);
+ }
+ } else {
+ alert(res.message || 'Operation failed');
+ }
+ } catch (e: any) {
+ alert(e.message || 'Failed');
}
};
- const telelinkQueue = [
- { id: 'TL-9921', patient: 'TR-1082', triage: 'RED', wait: '1:45', complaint: 'Cardiac Arrest', symptoms: 'Ongoing CPR, 2 shocks delivered' },
- { id: 'TL-9925', patient: 'TR-1089', triage: 'RED', wait: '0:30', complaint: 'Potential Stroke', symptoms: 'GCS 12, unilateral weakness' },
- ];
+ const handleEditStaff = (user: any) => {
+ setIsEditingStaff(true);
+ setEditingStaffId(user.id);
+
+ // Parse role-specific metadata
+ const role = user.roles?.[0] || 'ED_DOCTOR';
+ const metadata = user.metadata || {};
+
+ setStaffFormData({
+ name: user.name || '',
+ email: user.email || '',
+ phone: user.phone || '',
+ username: user.username || '',
+ password: '', // Leave blank so it doesn't update unless typed
+ role: role,
+ department: user.department || metadata.department || '',
+ designation: user.designation || metadata.designation || '',
+ specialization: metadata.specialization || '',
+ license_number: metadata.license_number || '',
+ shift: metadata.shift || '',
+ employee_id: user.employee_id || user.employeeId || '',
+ org_id: user.org_id || user.organisationId || '',
+ assigned_floor: metadata.assigned_floor || '',
+ languages: metadata.languages ? metadata.languages.join(', ') : '',
+ });
+
+ setIsStaffModalOpen(true);
+ };
- const fleetDataList = [
- { id: 'AMB-01', type: 'ALS', status: 'RUNNING', patient: 'TR-1082', fuel: '75%', crew: 'EMT Arjun, Driver Som', eta: '4m', coords: [12.9716, 77.5946] },
- { id: 'AMB-02', type: 'BLS', status: 'IDLE', patient: null, fuel: '92%', crew: 'EMT Suman, Driver Ravi', eta: '-', coords: [12.9350, 77.6245] },
- { id: 'AMB-03', type: 'Transport', status: 'BREAKDOWN', patient: null, fuel: '15%', crew: 'None', eta: '-', coords: [12.9500, 77.6000], alert: 'Engine Overheat' },
- ];
-
- const epcrs = [
- { id: 'PCR-7721', date: '2026-04-16', ambulance: 'KA-01-AM-22', patient: 'Anil Kapur', triage: 'RED', status: 'PENDING_SIGN' },
- { id: 'PCR-7718', date: '2026-04-16', ambulance: 'KA-05-BX-44', patient: 'Priya Verma', triage: 'YELLOW', status: 'RECEIVED' },
- ];
+ const handleCreateDepartment = async () => {
+ try {
+ const token = localStorage.getItem('teleems_token');
+ const payload = {
+ name: deptFormData.name,
+ headOfDepartment: deptFormData.headOfDepartment,
+ totalBedsCapacity: deptFormData.totalBedsCapacity,
+ contactPhone: deptFormData.contactPhone,
+ hospitalId: selectedHospital?.rawUser?.hospitalId || selectedHospital?.id,
+ isActive: true,
+ };
+ const res = await hospitalApi.createDepartment(payload, token || '');
+ if (res.status === 200 || res.status === 201) {
+ setSuccessMessage('Department verified and registered.');
+ setIsDeptModalOpen(false);
+ const updatedRes = await authApi.getDepartments(token || '');
+ if (updatedRes.data) {
+ const hospId = selectedHospital?.rawUser?.hospitalId || selectedHospital?.id;
+ setDepartments(updatedRes.data.filter((d: any) => d.hospitalId === hospId));
+ }
+ } else {
+ alert('Failed to register department. Code: ' + res.status);
+ }
+ } catch (e) {
+ alert('Exception: ' + e);
+ }
+ };
+ // ── Module renderer ──
const renderModule = () => {
switch (activeModule) {
case 'ED_MONITOR':
return (
-
-
-
-
-
-
REAL-TIME TRIAGE BOARD
-
4 CRITICAL • 2 ENROUTE
-
-
-
-
-
- {incomingPatients.map((patient, idx) => (
-
-
-
-
-
{patient.ambulanceId || patient.reg}
-
-
{patient.eta}
-
ARRIVAL
-
-
-
-
-
{patient.name}
-
{patient.age}Y · {patient.gender} · {patient.id}
-
-
{patient.triage} · {patient.complaint}
-
-
-
-
-
110 ? 'critical' : ''}`}>
-
-
- {patient.vitals.hr}
- HR / BPM
-
-
-
-
-
- {patient.vitals.spo2}
- SpO2 / %
-
-
-
-
-
- {patient.vitals.bp}
- BP / mmHg
-
-
-
-
-
- {patient.vitals.temp}
- TEMP / °F
-
-
-
-
-
-
setActiveModule('TELELINK')}>
- VIDEO LINK
-
-
setIsBookingModalOpen(true)}>
- ADMIT UNIT
-
-
-
-
- ))}
-
-
-
-
-
-
EMERGENCY RESPONSE HUB
-
Broadcast high-priority emergency alerts throughout hospital network nodes.
-
-
- CODE REDCardiac Arrest
-
-
-
- CODE BLUEMedical Emergency
-
-
-
- CODE TRAUMASevere Surgical
-
-
-
-
-
-
-
-
-
- EMERGENCY BAY
- {selectedHospital?.beds || '4/12'}
-
-
-
-
-
- ICU - LEVEL 1
- 1/8
-
-
-
-
-
- REFRESH FROM HMS
-
-
-
-
-
14:55:02
-
NODE STATUS: SYNCED
-
-
-
-
+ {
+ // Trigger reload in console
+ window.dispatchEvent(new CustomEvent('refresh_incoming'));
+ }}
+ onOpenBooking={() => setIsBookingModalOpen(true)}
+ onOpenTelelink={() => setActiveModule('TELELINK')}
+ />
);
- case 'BOOKINGS':
+ case 'BOOKINGS':
return (
-
-
-
-
LIVE TRIP MANAGEMENT
-
8 ACTIVE TRANSPORTS
-
-
-
-
-
-
-
setIsBookingModalOpen(true)} className="register-staff-btn-premium">
- NEW DISPATCH
-
-
-
-
-
-
-
Active Trips
-
{tripsData.length}
-
25% vs last hour
-
-
-
Avg Arrival E.T.A
-
9.4m
-
10% vs last hour
-
-
-
I.F.T Pending Nodes
-
03
-
Status: Operational
-
-
-
-
-
-
-
- | Accession & Patient |
- Trip Parameters |
- Fleet Asset |
- Live Progress Timeline |
- Operational Actions |
-
-
-
- {tripsData.map((t, idx) => (
-
-
-
- {t.patient}
- {t.id} · MRNID: {t.mrn}
-
- |
-
-
- {t.origin}
-
- {t.destination}
-
- |
-
-
- {t.vehicle}
- {t.crew}
-
- |
-
-
-
- {t.status}
- {t.eta} REMAINING
-
-
- = 1 ? 'completed' : ''}`}>
- = 2 ? 'active' : ''}`}>
- = 2 ? 'completed' : t.step === 1 ? 'active' : ''}`}>
- = 3 ? 'active' : ''}`}>
- = 3 ? 'completed' : t.step === 2 ? 'active' : ''}`}>
-
-
- |
-
-
-
-
- setTripsData(tripsData.filter(item => item.id !== t.id))} style={{ color: 'var(--alert-red)' }}>
-
- |
-
- ))}
-
-
-
-
+ setTripsData(tripsData.filter((t) => t.id !== id))}
+ onOpenBooking={() => setIsBookingModalOpen(true)}
+ />
);
+
case 'FLEET':
- return (
-
-
-
-
-
-
- {fleetDataList.map(v => (
-
-
-
- {v.id}
- {v.type}
-
-
{v.status}
-
-
{v.crew}
-
- ))}
-
-
-
-
- );
+ return ;
case 'TELELINK':
- return (
-
-
-
-
-
ACTIVE INBOUND 2 PENDING
-
- {telelinkQueue.map(q => (
-
-
-
{q.patient}
-
EMT: Arjun
-
-
ACCEPT UPLINK
-
- ))}
-
-
-
+ return
;
-
-
-
- );
case 'EPCR':
- return (
-
- CLINICAL RECORDS (ePCR)
-
-
- | Record ID | Patient | Status | Action |
-
- {epcrs.map(e => (
- | {e.id} | {e.patient} | {e.status} | VIEW |
- ))}
-
-
-
-
- );
+ return ;
case 'HISTORY':
- return (
-
- PATIENT ARCHIVE
-
-
- | Date | Patient | Triage | Status |
-
- {[
- { date: '16 Apr 2026', patient: 'Meera Jain', triage: 'RED', status: 'ADMITTED' }
- ].map((item, i) => (
- | {item.date} | {item.patient} | {item.triage} | {item.status} |
- ))}
-
-
-
-
- );
+ return ;
case 'REPORTS':
- return (
-
- ANALYTICS
-
-
- );
+ return ;
case 'SETUP':
return (
-
-
-
-
-
- {setupSubTab === 'PROFILE' && (
-
-
-
-
-
- setSelectedHospital({...selectedHospital, name: e.target.value})}
- />
-
-
-
-
ACTIVE • FULLY OPERATIONAL
-
-
- SAVE CONFIGURATION
-
-
-
-
- )}
-
- {setupSubTab === 'USERS' && (
-
-
-
-
-
-
-
-
setIsStaffModalOpen(true)}>
- REGISTER NEW STAFF
-
-
-
-
-
- | Operator Name |
- Designation |
- Node Alignment |
- Auth Status |
-
-
-
- {allUsers.filter(u => u.hospitalId === selectedHospital?.rawUser?.hospitalId || u.organisationId === selectedHospital?.rawUser?.organisationId).map((u, i) => (
-
- | {u.name || u.username} |
- {u.roles[0]?.replace('_', ' ')} |
- {selectedHospital?.name} |
- AUTHORIZED |
-
- ))}
-
-
-
-
- )}
-
- {setupSubTab === 'DEPTS' && (
-
-
-
-
Active Departments: {departments.length}
-
setIsDeptModalOpen(true)}>
- ADD DEPARTMENT
-
-
-
- {departments.map((d, i) => (
-
-
-
{d.name}
-
- Head: {d.headOfDepartment}
- Beds: {d.totalBedsCapacity} | Tel: {d.contactPhone}
-
-
- {d.isActive ? '• OPERATIONAL' : '• OFFLINE'}
-
-
-
{
- // Local toggle preview for now, normally would PATCH to API
- const n = [...departments];
- n[i].isActive = !n[i].isActive;
- setDepartments(n);
- }}
- >
- {d.isActive ? 'OFFLINE' : 'ONLINE'}
-
-
- ))}
-
-
-
- )}
-
- {setupSubTab === 'BEDS' && (
-
-
-
-
Active Care Units: {departments.length}
-
ADD UNIT
-
-
-
-
- | Care Unit / Dept |
- Total Capacity |
- Occupied |
- Availability |
-
-
-
- {departments.map((b, i) => {
- const occ = b.occupiedBeds || 0; // Fallback if API hasn't mapped occupied yet
- const tot = b.totalBedsCapacity || 1; // Prevent division by zero
- return (
-
- | {b.name} |
- {b.totalBedsCapacity} Units |
- {occ} |
-
-
- |
-
- )})}
-
-
-
-
- )}
-
-
-
+ {
+ setIsEditingStaff(false);
+ setEditingStaffId(null);
+ setStaffFormData({
+ name: '', email: '', phone: '', username: '', password: '',
+ role: 'ED_DOCTOR', department: '', specialization: '',
+ license_number: '', designation: '', shift: 'General',
+ employee_id: '', org_id: '', assigned_floor: '', languages: ''
+ });
+ setIsStaffModalOpen(true);
+ }}
+ onEditStaff={handleEditStaff}
+ onOpenDeptModal={() => setIsDeptModalOpen(true)}
+ />
);
case 'REFERRALS':
- return (
-
- Referral Network
-
- No active outgoing referrals at this time.
-
-
- );
+ return ;
default:
return Module Under Development
;
}
};
- if (!selectedHospital) {
- return (
-
-
-
-
-
-
-
Command Node Protocol
-
Regional Emergency Service Network · Authorized Node Access Only
-
-
+ // Hospital selection is now handled inline — no full-screen overlay
-
- {isLoadingHospitals ? (
-
-
-
-
-
ESTABLISHING SECURE UPLINK...
-
- ) : hospitals.length === 0 ? (
-
-
-
No active hospital nodes detected within the regional network grid.
-
window.location.reload()}>RESCAN NETWORK
-
- ) : hospitals.map((h, idx) => (
-
setSelectedHospital(h)}
- >
-
-
-
- {h.name}
-
- {h.type} Node
- {h.status}
-
-
-
-
- Admin: {h.admin || 'Dr. Admin'}
-
-
-
- BED CAPACITY
- {h.beds} AVAIL
-
-
- SECURE ACCESS
-
- ))}
-
-
-
- );
- }
+ // ── Main console ──
+ // Module card definitions with descriptions and color accents
+ const MODULE_CARDS: { key: ConsoleModule; icon: any; label: string; description: string; accent: string; accentBg: string }[] = [
+ { key: 'ED_MONITOR', icon: Monitor, label: 'ED Monitor', description: 'Live triage stream, incoming patients & emergency broadcasts', accent: 'hsl(0, 84%, 60%)', accentBg: 'hsla(0, 84%, 60%, 0.08)' },
+ { key: 'BOOKINGS', icon: Activity, label: 'Trip Management', description: 'Ambulance bookings, dispatches & trip tracking', accent: 'hsl(199, 89%, 48%)', accentBg: 'hsla(199, 89%, 48%, 0.08)' },
+ { key: 'FLEET', icon: Truck, label: 'Fleet Visibility', description: 'Real-time fleet map, vehicle status & route monitoring', accent: 'hsl(262, 83%, 58%)', accentBg: 'hsla(262, 83%, 58%, 0.08)' },
+ { key: 'TELELINK', icon: Video, label: 'TeleLink Hub', description: 'Video consults, physician console & remote triage', accent: 'hsl(152, 69%, 40%)', accentBg: 'hsla(152, 69%, 40%, 0.08)' },
+ { key: 'EPCR', icon: FileText, label: 'ePCR Records', description: 'Electronic patient care reports & documentation', accent: 'hsl(38, 92%, 50%)', accentBg: 'hsla(38, 92%, 50%, 0.08)' },
+ { key: 'HISTORY', icon: Database, label: 'Patient Archive', description: 'Historical patient data, discharge records & search', accent: 'hsl(215, 60%, 50%)', accentBg: 'hsla(215, 60%, 50%, 0.08)' },
+ { key: 'REPORTS', icon: TrendingUp, label: 'Analytics', description: 'Performance metrics, KPIs & operational insights', accent: 'hsl(280, 65%, 55%)', accentBg: 'hsla(280, 65%, 55%, 0.08)' },
+ { key: 'REFERRALS', icon: Hospital, label: 'Referral Hub', description: 'Inter-hospital referrals, network & transfer protocols', accent: 'hsl(170, 60%, 42%)', accentBg: 'hsla(170, 60%, 42%, 0.08)' },
+ { key: 'SETUP', icon: Settings, label: 'Account & Setup', description: 'Hospital profile, departments, staff & configuration', accent: 'hsl(220, 15%, 50%)', accentBg: 'hsla(220, 15%, 50%, 0.08)' },
+ ];
return (
-