(() => {
const { useState, useCallback } = React;

const SHIFT_TYPES = [
  { id: '0645-1515', label: '6:45a - 3:15p', start: 6.75, color: '#4ade80' },
  { id: '0645-1715', label: '6:45a - 5:15p', start: 6.75, color: '#60a5fa' },
  { id: '0645-1915', label: '6:45a - 7:15p', start: 6.75, color: '#f59e0b' },
  { id: '0645-2115', label: '6:45a - 9:15p', start: 6.75, color: '#c084fc' },
  { id: '1100-1900', label: '11:00a - 7:00p', start: 11, color: '#fb7185' },
  { id: '1100-2100', label: '11:00a - 9:00p', start: 11, color: '#f97316' },
  { id: '1900-0700', label: '7:00p - 7:00a', start: 19, color: '#818cf8' },
];

const RELIEF_WINDOWS = ['3:00p', '5:00p', '7:00p', '9:00p'];
const DEFAULT_ROOM_NUMBERS = [1, 2, 3, 50];
const ROLE_OPTIONS = ['Circulator', 'Scrub Person', 'PCA', 'Team Leader'];
const ROLE_STORAGE_KEY = 'or-flow-role-map-v1';
const ASSIGNMENT_FIELDS = [
  { key: 'surgeon', label: 'Surgeon', shortLabel: 'Surgeon', type: 'text' },
  { key: 'circulator1', label: 'Circulator #1', shortLabel: 'Circ 1', type: 'staff' },
  { key: 'circulator2', label: 'Circulator #2', shortLabel: 'Circ 2', type: 'staff' },
  { key: 'scrub1', label: 'Scrub Person #1', shortLabel: 'Scrub 1', type: 'staff' },
  { key: 'scrub2', label: 'Scrub Person #2', shortLabel: 'Scrub 2', type: 'staff' },
  { key: 'reliefRn', label: 'Relief RN', shortLabel: 'Relief RN', type: 'staff' },
  { key: 'reliefScrub', label: 'Relief Scrub Person', shortLabel: 'Relief Scrub', type: 'staff' },
  { key: 'comments', label: 'Comments', shortLabel: 'Comments', type: 'comments' },
];

function BrandLogo() {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
      <svg width='54' height='54' viewBox='0 0 64 64' fill='none' aria-hidden='true'>
        <rect x='4' y='4' width='56' height='56' rx='16' fill='#0B1522' stroke='#223248' strokeWidth='2' />
        <rect x='13' y='13' width='28' height='28' rx='8' fill='#4ADE8020' stroke='#4ADE80' strokeWidth='3' />
        <path d='M27 17V37' stroke='#4ADE80' strokeWidth='4' strokeLinecap='round' />
        <path d='M17 27H37' stroke='#4ADE80' strokeWidth='4' strokeLinecap='round' />
        <path d='M46 22H52C54.7614 22 57 24.2386 57 27V31C57 33.7614 54.7614 36 52 36H46' stroke='#60A5FA' strokeWidth='4' strokeLinecap='round' />
        <path d='M47 40C47 45.5228 42.5228 50 37 50H17' stroke='#60A5FA' strokeWidth='4' strokeLinecap='round' />
        <path d='M20 46L16 50L20 54' stroke='#60A5FA' strokeWidth='4' strokeLinecap='round' strokeLinejoin='round' />
      </svg>
      <div className="nav-brand-text">
        <div style={{ fontSize: 11, letterSpacing: 3, color: '#4ade80', fontFamily: "'Space Mono', monospace" }}>OR FLOW</div>
        <div style={{ fontSize: 26, fontWeight: 900, color: '#fff', lineHeight: 1 }}>OR Flow</div>
      </div>
    </div>
  );
}

function formatRoomLabel(roomNumber) {
  return `OR ${roomNumber}`;
}

function formatDateKey(date) {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const day = String(date.getDate()).padStart(2, '0');
  return `${year}-${month}-${day}`;
}

function formatReadableDate(dateKey) {
  const date = new Date(`${dateKey}T00:00:00`);
  return date.toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' });
}

function getMonthMatrix(monthKey) {
  const [year, month] = monthKey.split('-').map(Number);
  const first = new Date(year, month - 1, 1);
  const startDay = first.getDay();
  const start = new Date(first);
  start.setDate(first.getDate() - startDay);
  return Array.from({ length: 42 }, (_, index) => {
    const date = new Date(start);
    date.setDate(start.getDate() + index);
    return date;
  });
}

function createEmptyAssignment(roomNumber) {
  return { roomNumber, surgeon: '', circulator1: '', circulator2: '', scrub1: '', scrub2: '', reliefRn: '', reliefScrub: '', comments: '' };
}

function sortAssignments(assignments) {
  return [...assignments].sort((a, b) => a.roomNumber - b.roomNumber);
}

function buildInitialAssignments() {
  const seeded = {
    1: { surgeon: 'Dr. Alvarez', circulator1: 'J. Martinez', circulator2: 'A. Thompson', scrub1: 'R. Patel', scrub2: 'L. Chen', reliefRn: 'M. Johnson', reliefScrub: 'K. Williams', comments: 'Robotics block 7:30a' },
    2: { surgeon: 'Dr. Singh', circulator1: 'S. Davis', circulator2: 'C. Wilson', scrub1: 'N. Garcia', scrub2: 'B. Anderson', reliefRn: 'H. Taylor', reliefScrub: 'D. Jackson', comments: 'Total joints priority' },
    3: { surgeon: 'Dr. Brooks', circulator1: 'F. White', circulator2: 'G. Harris', scrub1: 'I. Martin', scrub2: 'E. Lee', reliefRn: 'P. Walker', reliefScrub: 'O. Hall', comments: 'Late flip expected' },
    50: { surgeon: 'Dr. Moore', circulator1: 'Q. Young', circulator2: 'V. Allen', scrub1: 'W. King', scrub2: 'X. Wright', reliefRn: 'Y. Scott', reliefScrub: 'Z. Torres', comments: 'Add-on room' },
  };
  return DEFAULT_ROOM_NUMBERS.map((roomNumber) => ({ ...createEmptyAssignment(roomNumber), ...(seeded[roomNumber] || {}) }));
}

function loadRoleMap() {
  try {
    const raw = window.localStorage.getItem(ROLE_STORAGE_KEY);
    return raw ? JSON.parse(raw) : {};
  } catch {
    return {};
  }
}

function saveRoleMap(roleMap) {
  try {
    window.localStorage.setItem(ROLE_STORAGE_KEY, JSON.stringify(roleMap));
  } catch {
  }
}

function normalizeRole(role) {
  return ROLE_OPTIONS.includes(role) ? role : 'PCA';
}

function inferRole(text) {
  const value = String(text || '').toLowerCase();
  if (value.includes('team leader') || value.includes('lead')) return 'Team Leader';
  if (value.includes('scrub') || value.includes('tech') || value.includes('surgical')) return 'Scrub Person';
  if (value.includes('circ') || value.includes('rn') || value.includes('nurse')) return 'Circulator';
  if (value.includes('pca')) return 'PCA';
  return 'PCA';
}

function timeToDecimal(timeStr) {
  const clean = String(timeStr || '').trim();
  const match = clean.match(/(\d{1,2}):(\d{2})\s*(AM|PM)?/i);
  if (!match) return 6.75;
  let hour = Number(match[1]);
  const minute = Number(match[2]);
  const ampm = match[3];
  if (ampm) {
    const upper = ampm.toUpperCase();
    if (upper === 'PM' && hour !== 12) hour += 12;
    if (upper === 'AM' && hour === 12) hour = 0;
  }
  return hour + minute / 60;
}

function matchShiftLabel(shiftStart) {
  const startHr = timeToDecimal(shiftStart);
  const matched = SHIFT_TYPES.reduce((best, shift) => (
    Math.abs(shift.start - startHr) < Math.abs(best.start - startHr) ? shift : best
  ), SHIFT_TYPES[0]);
  return { shift: matched.id, shiftLabel: matched.label };
}
function parseCsv(text) {
  const rows = text.trim().split(/\r?\n/).filter(Boolean);
  if (rows.length < 2) return [];
  const headers = rows[0].split(',').map((value) => value.trim().replace(/^"|"$/g, ''));
  return rows.slice(1).map((line, index) => {
    const cols = line.split(',').map((value) => value.trim().replace(/^"|"$/g, ''));
    const row = {};
    headers.forEach((header, i) => {
      row[header] = cols[i] || '';
    });
    const shiftStart = row['Start Time'] || row['Shift Start'] || row['In'] || '06:45';
    const shiftEnd = row['End Time'] || row['Shift End'] || row['Out'] || '15:15';
    const matchedShift = matchShiftLabel(shiftStart);
    return {
      id: index + 1,
      name: row['Employee Name'] || row['Name'] || row['Full Name'] || `Staff ${index + 1}`,
      role: inferRole(row['Role'] || row['Job'] || row['Position'] || ''),
      rawRole: row['Role'] || row['Job'] || row['Position'] || '',
      room: row['Room'] || row['OR'] || row['Room Number'] || '',
      shiftStart,
      shiftEnd,
      shift: matchedShift.shift,
      shiftLabel: matchedShift.shiftLabel,
      comments: row['Comments'] || '',
    };
  });
}

function generateSampleStaff() {
  const names = ['J. Martinez', 'A. Thompson', 'R. Patel', 'L. Chen', 'M. Johnson', 'K. Williams', 'S. Davis', 'T. Brown', 'C. Wilson', 'N. Garcia', 'B. Anderson', 'H. Taylor', 'D. Jackson', 'F. White', 'G. Harris', 'I. Martin', 'E. Lee', 'P. Walker', 'O. Hall', 'Q. Young', 'V. Allen', 'W. King', 'X. Wright', 'Y. Scott', 'Z. Torres', 'AA. Nguyen', 'BB. Hill', 'CC. Flores', 'DD. Green', 'EE. Adams'];
  const baseRoles = ['Circulator', 'Circulator', 'Scrub Person', 'Scrub Person', 'PCA', 'Team Leader'];
  return names.map((name, index) => {
    const shift = SHIFT_TYPES[index % SHIFT_TYPES.length];
    return { id: index + 1, name, role: baseRoles[index % baseRoles.length], shift: shift.id, shiftLabel: shift.label, room: '' };
  });
}

function applyRoleMap(roster, roleMap) {
  const nextRoleMap = { ...roleMap };
  const normalizedRoster = roster.map((person, index) => {
    const key = String(person.name || '').trim().toLowerCase();
    const role = normalizeRole(nextRoleMap[key] || person.role || inferRole(person.rawRole));
    if (key) nextRoleMap[key] = role;
    return { ...person, id: index + 1, role };
  });
  return { roster: normalizedRoster, roleMap: nextRoleMap };
}

function createDayData(roster) {
  return {
    draftAssignments: sortAssignments(buildInitialAssignments()),
    publishedAssignments: sortAssignments(buildInitialAssignments()),
    publishedAt: new Date().toISOString(),
    roster: roster.map((person) => ({ ...person })),
  };
}

function roomCoverageScore(room) {
  let score = 0;
  if (room.circulator1) score += 1;
  if (room.circulator2) score += 1;
  if (room.scrub1) score += 1;
  if (room.scrub2) score += 1;
  return score;
}

function roomIsRunning(room) {
  return Boolean(room.surgeon && room.circulator1 && room.scrub1);
}

function reliefCovered(room) {
  return Boolean(room.reliefRn && room.reliefScrub);
}

function getAssignedNames(assignments) {
  const assigned = new Set();
  assignments.forEach((room) => {
    ['circulator1', 'circulator2', 'scrub1', 'scrub2', 'reliefRn', 'reliefScrub'].forEach((field) => {
      const value = String(room[field] || '').trim();
      if (value) assigned.add(value.toLowerCase());
    });
  });
  return assigned;
}

function buildRosterForDisplay(roster, assignments) {
  const assignedNames = getAssignedNames(assignments);
  return [...roster].sort((a, b) => a.name.localeCompare(b.name)).map((person) => ({
    ...person,
    assignmentStatus: assignedNames.has(String(person.name || '').toLowerCase()) ? 'Assigned' : 'Available',
  }));
}

function eligibleRolesForField(field) {
  if (field === 'circulator1' || field === 'circulator2' || field === 'reliefRn') return ['Circulator', 'Team Leader'];
  if (field === 'scrub1' || field === 'scrub2' || field === 'reliefScrub') return ['Scrub Person', 'Circulator'];
  return ROLE_OPTIONS;
}

function eligibleStaffForField(field, roster) {
  const roles = eligibleRolesForField(field);
  return roster.filter((person) => roles.includes(person.role)).sort((a, b) => a.name.localeCompare(b.name));
}

function HomeView({ assignments, publishedAt, roster, selectedDate, onToggleNav }) {
  const [showStaffPanel, setShowStaffPanel] = useState(true);
  const displayRoster = buildRosterForDisplay(roster, assignments);
  const runningRooms = assignments.filter(roomIsRunning).length;
  const availableStaff = displayRoster.filter((person) => person.assignmentStatus === 'Available').length;

  return (
    <div className='home-board-page'>
      <div className='board-header'>
        <div>
          <div className='board-title'>OR Flow Assignment Board</div>
          <div className='board-subtitle'>{formatReadableDate(selectedDate)}</div>
        </div>
        <div className='board-actions'>
          <button className='ghost-button' onClick={() => setShowStaffPanel((value) => !value)}>{showStaffPanel ? 'Hide Staff Panel' : 'Show Staff Panel'}</button>
          <button className='ghost-button' onClick={onToggleNav}>Toggle Left Menu</button>
        </div>
        <div className='board-stats'>
          <div className='stat-pill'><span className='stat-label'>Rooms</span><span className='stat-value'>{assignments.length}</span></div>
          <div className='stat-pill'><span className='stat-label'>Covered</span><span className='stat-value'>{assignments.filter((room) => roomCoverageScore(room) >= 2).length}</span></div>
          <div className='stat-pill'><span className='stat-label'>Roster</span><span className='stat-value'>{displayRoster.length}</span></div>
          <div className='stat-pill'><span className='stat-label'>Available</span><span className='stat-value'>{availableStaff}</span></div>
          <div className='stat-pill running'><span className='stat-label'>Running Now</span><span className='stat-value'>{runningRooms}</span></div>
          <div className='stat-pill wide'><span className='stat-label'>Published</span><span className='stat-timestamp'>{publishedAt ? new Date(publishedAt).toLocaleString() : 'Not published yet'}</span></div>
        </div>
      </div>

      <div className='wallboard-layout' style={{ gridTemplateColumns: showStaffPanel ? 'minmax(0, 3.2fr) minmax(220px, 0.72fr)' : '1fr' }}>
        <section className='wallboard-panel'>
          <div className='panel-title'>Room Assignments</div>
          <div className='tv-table-wrap'>
            <table className='tv-table'>
              <thead>
                <tr>
                  <th>Room</th>
                  {ASSIGNMENT_FIELDS.map((field) => <th key={field.key}>{field.shortLabel}</th>)}
                </tr>
              </thead>
              <tbody>
                {assignments.map((room) => (
                  <tr key={room.roomNumber}>
                    <td className='room-id-cell'>{formatRoomLabel(room.roomNumber)}</td>
                    {ASSIGNMENT_FIELDS.map((field) => <td key={field.key} className={room[field.key] ? '' : 'empty-cell'}>{room[field.key] || '-'}</td>)}
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </section>

        {showStaffPanel ? (
          <section className='wallboard-panel'>
            <div className='panel-title'>All Staff</div>
            <div className='roster-grid'>
              {displayRoster.map((person) => (
                <div key={person.id} className='roster-chip'>
                  <div className='roster-name-row'>
                    <span className='roster-name'>{person.name}</span>
                    <span className={`roster-status ${person.assignmentStatus === 'Assigned' ? 'assigned' : 'available'}`}>{person.assignmentStatus}</span>
                  </div>
                  <div className='roster-meta'>{person.role} � {person.shiftLabel}</div>
                  {person.room ? <div className='roster-meta'>Preferred room {person.room}</div> : null}
                </div>
              ))}
            </div>
          </section>
        ) : null}
      </div>
    </div>
  );
}

function CalendarView({ selectedDate, onSelectDate, monthKey, onMonthChange, scheduleByDate }) {
  const days = getMonthMatrix(monthKey);
  const [year, month] = monthKey.split('-').map(Number);
  const monthLabel = new Date(year, month - 1, 1).toLocaleDateString('en-US', { month: 'long', year: 'numeric' });
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', gap: 16, flexWrap: 'wrap', alignItems: 'center' }}>
        <div>
          <div style={{ fontSize: 30, fontWeight: 900, color: '#fff' }}>Calendar</div>
          <div style={{ fontSize: 12, color: '#64748b', fontFamily: "'Space Mono', monospace", marginTop: 4 }}>Select a day to manage room assignments and future staffing uploads</div>
        </div>
        <div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
          <button onClick={() => onMonthChange(-1)} style={{ background: '#111827', color: '#fff', border: '1px solid #1e2433', borderRadius: 10, padding: '10px 14px', cursor: 'pointer' }}>Prev</button>
          <div style={{ minWidth: 180, textAlign: 'center', fontWeight: 800 }}>{monthLabel}</div>
          <button onClick={() => onMonthChange(1)} style={{ background: '#111827', color: '#fff', border: '1px solid #1e2433', borderRadius: 10, padding: '10px 14px', cursor: 'pointer' }}>Next</button>
        </div>
      </div>
      <div style={{ background: '#0f1117', border: '1px solid #1e2433', borderRadius: 14, padding: 16 }}>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, minmax(0, 1fr))', gap: 8, marginBottom: 8 }}>
          {['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map((label) => <div key={label} style={{ fontSize: 10, color: '#93c5fd', fontFamily: "'Space Mono', monospace", textTransform: 'uppercase', padding: '6px 8px' }}>{label}</div>)}
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, minmax(0, 1fr))', gap: 8 }}>
          {days.map((date) => {
            const key = formatDateKey(date);
            const dayData = scheduleByDate[key];
            const running = dayData ? dayData.publishedAssignments.filter(roomIsRunning).length : 0;
            const rosterCount = dayData ? dayData.roster.length : 0;
            const isCurrentMonth = date.getMonth() === month - 1;
            const isSelected = key === selectedDate;
            return (
              <button key={key} onClick={() => onSelectDate(key)} className='calendar-day-btn' style={{ background: isSelected ? '#172033' : '#080b12', border: isSelected ? '1px solid #4ade80' : '1px solid #1e2433', color: isCurrentMonth ? '#fff' : '#475569', borderRadius: 12, minHeight: 94, padding: '10px 10px 12px', textAlign: 'left', cursor: 'pointer' }}>
                <div style={{ fontSize: 12, fontWeight: 800 }}>{date.getDate()}</div>
                <div style={{ fontSize: 9, color: '#60a5fa', fontFamily: "'Space Mono', monospace", marginTop: 10 }}>Running: {running}</div>
                <div style={{ fontSize: 9, color: '#94a3b8', fontFamily: "'Space Mono', monospace", marginTop: 4 }}>Roster: {rosterCount}</div>
              </button>
            );
          })}
        </div>
      </div>

      <div style={{ background: '#0f1117', border: '1px solid #1e2433', borderRadius: 14, padding: 18 }}>
        <div style={{ fontSize: 12, color: '#93c5fd', fontFamily: "'Space Mono', monospace", marginBottom: 10 }}>Selected Day</div>
        <div style={{ fontSize: 20, fontWeight: 800 }}>{formatReadableDate(selectedDate)}</div>
        <div style={{ fontSize: 11, color: '#64748b', fontFamily: "'Space Mono', monospace", marginTop: 8 }}>Choose a future date here, then go to Import or Admin to manage that day.</div>
      </div>
    </div>
  );
}

function AdminView({ assignments, onFieldChange, onAddRoom, onPublish, roster, onRoleChange, publishedAt, selectedDate }) {
  const [newRoomValue, setNewRoomValue] = useState('');

  const handleAddRoom = () => {
    const roomNumber = Number(newRoomValue);
    if (!roomNumber) return;
    if (onAddRoom(roomNumber)) setNewRoomValue('');
  };



  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', gap: 16, alignItems: 'flex-start', flexWrap: 'wrap' }}>
        <div>
          <div style={{ fontSize: 30, fontWeight: 900, color: '#fff', fontFamily: "'Syne', sans-serif" }}>Admin Assignment Board</div>
          <div style={{ fontSize: 12, color: '#64748b', fontFamily: "'Space Mono', monospace", marginTop: 4 }}>{formatReadableDate(selectedDate)}</div>
        </div>
        <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>
          <input value={newRoomValue} onChange={(event) => setNewRoomValue(event.target.value.replace(/[^0-9]/g, ''))} placeholder='Add OR number' style={{ background: '#0f1117', border: '1px solid #1e2433', color: '#fff', borderRadius: 10, padding: '12px 14px', minWidth: 140, fontFamily: "'Space Mono', monospace" }} />
          <button onClick={handleAddRoom} style={{ background: '#1d4ed8', color: '#fff', border: 'none', borderRadius: 10, padding: '12px 16px', fontWeight: 700, cursor: 'pointer' }}>Add Room</button>
          <button onClick={onPublish} style={{ background: '#4ade80', color: '#03120a', border: 'none', borderRadius: 10, padding: '12px 18px', fontWeight: 900, cursor: 'pointer' }}>Publish Board</button>
        </div>
      </div>

      <div className='admin-layout'>
        <div style={{ background: '#0f1117', border: '1px solid #1e2433', borderRadius: 14, overflow: 'auto' }}>
          <div style={{ display: 'grid', gridTemplateColumns: '90px repeat(8, minmax(160px, 1fr))', gap: 1, background: '#1e2433' }}>
            {['Room', ...ASSIGNMENT_FIELDS.map((field) => field.label)].map((label) => <div key={label} style={{ background: '#111827', padding: '12px 10px', fontSize: 10, color: '#93c5fd', fontFamily: "'Space Mono', monospace", textTransform: 'uppercase' }}>{label}</div>)}
            {assignments.map((room) => (
              <React.Fragment key={room.roomNumber}>
                <div style={{ background: '#080b12', padding: '14px 10px', fontSize: 13, color: '#fff', fontWeight: 700 }}>{formatRoomLabel(room.roomNumber)}</div>
                {ASSIGNMENT_FIELDS.map((field) => (
                  <div key={field.key} style={{ background: '#080b12', padding: 6 }}>
                    {field.type === 'comments' ? (
                      <textarea value={room[field.key]} onChange={(event) => onFieldChange(room.roomNumber, field.key, event.target.value)} rows={3} style={{ width: '100%', resize: 'vertical', minHeight: 68, background: '#111827', border: '1px solid #1f2937', color: '#fff', borderRadius: 8, padding: '10px 12px', fontFamily: "'Space Mono', monospace", fontSize: 11 }} />
                    ) : field.type === 'text' ? (
                      <input value={room[field.key]} onChange={(event) => onFieldChange(room.roomNumber, field.key, event.target.value)} style={{ width: '100%', background: '#111827', border: '1px solid #1f2937', color: '#fff', borderRadius: 8, padding: '10px 12px', fontFamily: "'Space Mono', monospace", fontSize: 11 }} />
                    ) : (
                      <select value={room[field.key] || ''} onChange={(event) => onFieldChange(room.roomNumber, field.key, event.target.value)} style={{ width: '100%', background: '#111827', border: '1px solid #1f2937', color: '#fff', borderRadius: 8, padding: '10px 12px', fontFamily: "'Space Mono', monospace", fontSize: 11 }}>
                        <option value=''>Unassigned</option>
                        {eligibleStaffForField(field.key, roster).map((person) => <option key={`${field.key}-${person.id}`} value={person.name}>{person.name} ({person.role})</option>)}
                      </select>
                    )}
                  </div>
                ))}
              </React.Fragment>
            ))}
          </div>
        </div>

        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          <div style={{ background: '#0f1117', border: '1px solid #1e2433', borderRadius: 14, padding: 18 }}>
            <div style={{ fontSize: 12, color: '#93c5fd', fontFamily: "'Space Mono', monospace", marginBottom: 10 }}>Publish Status</div>
            <div style={{ fontSize: 16, color: '#fff', fontWeight: 700 }}>{publishedAt ? `Last pushed ${new Date(publishedAt).toLocaleString()}` : 'Draft changes have not been published yet'}</div>
          </div>
          <div style={{ background: '#0f1117', border: '1px solid #1e2433', borderRadius: 14, padding: 18 }}>
            <div style={{ fontSize: 12, color: '#93c5fd', fontFamily: "'Space Mono', monospace", marginBottom: 10 }}>Staff Directory</div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 8, maxHeight: 620, overflowY: 'auto' }}>
              {roster.map((person) => (
                <div key={person.id} style={{ background: '#080b12', borderRadius: 10, padding: '10px 12px' }}>
                  <div style={{ fontSize: 13, color: '#fff', fontWeight: 700 }}>{person.name}</div>
                  <div style={{ fontSize: 10, color: '#64748b', fontFamily: "'Space Mono', monospace", marginTop: 4 }}>{person.shiftLabel}</div>
                  <select value={person.role} onChange={(event) => onRoleChange(person.name, event.target.value)} style={{ width: '100%', marginTop: 8, background: '#111827', border: '1px solid #1f2937', color: '#fff', borderRadius: 8, padding: '9px 10px', fontFamily: "'Space Mono', monospace", fontSize: 11 }}>
                    {ROLE_OPTIONS.map((role) => <option key={role} value={role}>{role}</option>)}
                  </select>
                </div>
              ))}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}
function AnalyticsView({ assignments, roster, selectedDate }) {
  const displayRoster = buildRosterForDisplay(roster, assignments);
  const runningRooms = assignments.filter(roomIsRunning).length;
  const fullyCoveredRooms = assignments.filter((room) => roomCoverageScore(room) >= 4).length;
  const reliefReadyRooms = assignments.filter(reliefCovered).length;
  const openRooms = assignments.filter((room) => !room.circulator1 || !room.scrub1).length;
  const addOnRooms = assignments.filter((room) => room.roomNumber >= 50).length;
  const pcaCoverage = displayRoster.filter((person) => person.role === 'PCA').length;
  const optionalTeamLeaders = displayRoster.filter((person) => person.role === 'Team Leader').length;
  const availableStaff = displayRoster.filter((person) => person.assignmentStatus === 'Available').length;
  const roleCounts = ROLE_OPTIONS.map((role) => ({ role, count: displayRoster.filter((person) => person.role === role).length }));
  const shiftCounts = SHIFT_TYPES.map((shift) => ({ ...shift, count: displayRoster.filter((person) => person.shift === shift.id).length }));
  const maxShiftCount = Math.max(...shiftCounts.map((shift) => shift.count), 1);



  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
      <div>
        <div style={{ fontSize: 30, fontWeight: 900, color: '#fff' }}>Leadership Analytics</div>
        <div style={{ fontSize: 12, color: '#64748b', fontFamily: "'Space Mono', monospace", marginTop: 4 }}>{formatReadableDate(selectedDate)}</div>
      </div>
      <div className='coverage-cards'>
        {[
          { label: 'Rooms Running', value: runningRooms, color: '#4ade80', sub: `${assignments.length ? Math.round((runningRooms / assignments.length) * 100) : 0}% of board` },
          { label: 'Fully Covered Rooms', value: fullyCoveredRooms, color: '#60a5fa', sub: '2 circulators + 2 scrubs' },
          { label: 'Relief Ready Rooms', value: reliefReadyRooms, color: '#f59e0b', sub: 'both relief roles assigned' },
          { label: 'Open Rooms', value: openRooms, color: '#fb7185', sub: 'missing a core role' },
          { label: 'Available Staff', value: availableStaff, color: '#22c55e', sub: 'not yet assigned' },
          { label: 'PCAs', value: pcaCoverage, color: '#14b8a6', sub: 'room turnover and cleaning support' },
        ].map((card) => (
          <div key={card.label} style={{ background: '#0f1117', border: '1px solid #1e2433', borderRadius: 14, padding: 18 }}>
            <div style={{ fontSize: 10, color: '#64748b', fontFamily: "'Space Mono', monospace" }}>{card.label}</div>
            <div style={{ fontSize: 34, fontWeight: 900, color: card.color, marginTop: 8 }}>{card.value}</div>
            <div style={{ fontSize: 10, color: '#94a3b8', fontFamily: "'Space Mono', monospace", marginTop: 6 }}>{card.sub}</div>
          </div>
        ))}
      </div>
      <div className='coverage-layout'>
        <div style={{ background: '#0f1117', border: '1px solid #1e2433', borderRadius: 14, padding: 18 }}>
          <div style={{ fontSize: 12, color: '#93c5fd', fontFamily: "'Space Mono', monospace", marginBottom: 12 }}>Leadership Highlights</div>
          <div style={{ display: 'grid', gap: 10 }}>
            {[
              `Running rooms: ${runningRooms} of ${assignments.length} currently staffed with surgeon, circulator, and scrub coverage.`,
              `Relief gap: ${assignments.length - reliefReadyRooms} rooms still need both relief roles assigned before afternoon break coverage is fully ready.`,
              `Add-on capacity: ${addOnRooms} add-on rooms are on today's board.`,
              `PCA support: ${pcaCoverage} PCAs are available to support room cleaning and turnover flow.`,
              `Team leader coverage: ${optionalTeamLeaders} team leaders are available today as optional support, not a required around-the-clock role.`,
            ].map((item) => <div key={item} style={{ background: '#080b12', borderRadius: 12, padding: '12px 14px', color: '#e2e8f0', fontSize: 13, lineHeight: 1.4 }}>{item}</div>)}
          </div>
        </div>
        <div style={{ background: '#0f1117', border: '1px solid #1e2433', borderRadius: 14, padding: 18 }}>
          <div style={{ fontSize: 12, color: '#93c5fd', fontFamily: "'Space Mono', monospace", marginBottom: 12 }}>Role Mix</div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
            {roleCounts.map((item) => {
              const pct = displayRoster.length ? Math.round((item.count / displayRoster.length) * 100) : 0;
              return (
                <div key={item.role}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 4 }}>
                    <span style={{ fontSize: 11, color: '#e2e8f0', fontFamily: "'Space Mono', monospace" }}>{item.role}</span>
                    <span style={{ fontSize: 11, color: '#93c5fd', fontFamily: "'Space Mono', monospace" }}>{item.count} � {pct}%</span>
                  </div>
                  <div style={{ height: 8, borderRadius: 999, background: '#111827' }}><div style={{ width: `${Math.max(6, pct)}%`, height: 8, borderRadius: 999, background: '#60a5fa' }} /></div>
                </div>
              );
            })}
          </div>
        </div>
      </div>
      <div className='coverage-layout'>
        <div style={{ background: '#0f1117', border: '1px solid #1e2433', borderRadius: 14, padding: 18 }}>
          <div style={{ fontSize: 12, color: '#93c5fd', fontFamily: "'Space Mono', monospace", marginBottom: 12 }}>Shift Distribution</div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
            {shiftCounts.map((shift) => (
              <div key={shift.id}>
                <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 4 }}>
                  <span style={{ fontSize: 10, color: '#e2e8f0', fontFamily: "'Space Mono', monospace" }}>{shift.label}</span>
                  <span style={{ fontSize: 10, color: shift.color, fontFamily: "'Space Mono', monospace" }}>{shift.count}</span>
                </div>
                <div style={{ height: 8, borderRadius: 999, background: '#111827' }}><div style={{ width: `${(shift.count / maxShiftCount) * 100}%`, height: 8, borderRadius: 999, background: shift.color, minWidth: shift.count ? 10 : 0 }} /></div>
              </div>
            ))}
          </div>
        </div>
        <div style={{ background: '#0f1117', border: '1px solid #1e2433', borderRadius: 14, padding: 18 }}>
          <div style={{ fontSize: 12, color: '#93c5fd', fontFamily: "'Space Mono', monospace", marginBottom: 12 }}>Relief Windows</div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 12 }}>
            {RELIEF_WINDOWS.map((label, index) => (
              <div key={label} style={{ background: '#080b12', borderRadius: 12, padding: '14px 12px' }}>
                <div style={{ fontSize: 10, color: '#64748b', fontFamily: "'Space Mono', monospace" }}>{label}</div>
                <div style={{ fontSize: 24, fontWeight: 900, color: ['#4ade80', '#60a5fa', '#f59e0b', '#fb7185'][index], marginTop: 8 }}>{Math.max(0, reliefReadyRooms - index)}</div>
                <div style={{ fontSize: 10, color: '#475569', fontFamily: "'Space Mono', monospace", marginTop: 4 }}>rooms ready</div>
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

function ImportView({ onImport, rosterCount, targetDate, onTargetDateChange, onClearRoster, onUndoRoster, canUndo }) {
  const [preview, setPreview] = useState('');
  const [error, setError] = useState('');
  const [parsed, setParsed] = useState([]);
  const [manualName, setManualName] = useState('');
  const [manualRole, setManualRole] = useState(ROLE_OPTIONS[0]);
  const [manualShift, setManualShift] = useState(SHIFT_TYPES[0].id);

  const handleFile = (file) => {
    if (!file || !file.name.toLowerCase().endsWith('.csv')) {
      setError('Please upload a CSV file.');
      return;
    }
    setError('');
    const reader = new FileReader();
    reader.onload = (event) => {
      const text = String(event.target.result || '');
      setPreview(text.split(/\r?\n/).slice(0, 6).join('\n'));
      try {
        setParsed(parseCsv(text));
      } catch {
        setError('Could not parse the CSV. Please confirm the file format and try again.');
      }
    };
    reader.readAsText(file);
  };



  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
      <div>
        <div style={{ fontSize: 30, fontWeight: 900, color: '#fff' }}>Import Staffing Roster</div>
        <div style={{ fontSize: 12, color: '#64748b', fontFamily: "'Space Mono', monospace", marginTop: 4 }}>Upload a CSV roster for the selected day. Future-day staffing uploads are supported.</div>
      </div>
      <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', alignItems: 'center' }}>
        <button className='ghost-button' onClick={onClearRoster}>Clear current roster</button>
        <button className='ghost-button' onClick={onUndoRoster} disabled={!canUndo}>Undo last clear/import</button>
      </div>
      <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>
        <div style={{ background: '#0f1117', border: '1px solid #1e2433', borderRadius: 14, padding: 18 }}>
          <div style={{ fontSize: 12, color: '#93c5fd', fontFamily: "'Space Mono', monospace", marginBottom: 8 }}>Target Date</div>
          <input type='date' value={targetDate} onChange={(event) => onTargetDateChange(event.target.value)} style={{ background: '#111827', border: '1px solid #1f2937', color: '#fff', borderRadius: 8, padding: '10px 12px', fontFamily: "'Space Mono', monospace" }} />
        </div>
        <div style={{ background: '#0f1117', border: '1px solid #1e2433', borderRadius: 14, padding: 18, flex: 1 }}>
          <div style={{ fontSize: 12, color: '#93c5fd', fontFamily: "'Space Mono', monospace", marginBottom: 12 }}>Supported Columns</div>
          <div className='import-columns'>
            {['Employee Name / Name / Full Name', 'Role / Job / Position', 'Start Time / Shift Start / In', 'End Time / Shift End / Out', 'Room / OR / Room Number', 'Surgeon / Comments'].map((item) => <div key={item} style={{ background: '#080b12', borderRadius: 10, padding: '10px 12px', color: '#e2e8f0', fontSize: 12, fontFamily: "'Space Mono', monospace" }}>{item}</div>)}
          </div>
        </div>
      </div>
      <div onDragOver={(event) => event.preventDefault()} onDrop={(event) => { event.preventDefault(); handleFile(event.dataTransfer.files[0]); }} style={{ border: '2px dashed #1e2433', borderRadius: 14, padding: '48px 24px', textAlign: 'center', background: '#0f1117' }}>
        <div style={{ fontSize: 18, color: '#fff', fontWeight: 700 }}>Drop a CSV roster here</div>
        <div style={{ fontSize: 11, color: '#64748b', fontFamily: "'Space Mono', monospace", marginTop: 8 }}>Current roster size for {formatReadableDate(targetDate)}: {rosterCount}</div>
        <label style={{ display: 'inline-block', marginTop: 18, cursor: 'pointer' }}>
          <input type='file' accept='.csv' style={{ display: 'none' }} onChange={(event) => handleFile(event.target.files[0])} />
          <span style={{ background: '#4ade80', color: '#04130a', padding: '11px 18px', borderRadius: 10, fontWeight: 800 }}>Browse CSV</span>
        </label>
      </div>

      <div style={{ background: '#0f1117', border: '1px solid #1e2433', borderRadius: 14, padding: 18, display: 'flex', flexDirection: 'column', gap: 10 }}>
        <div style={{ fontSize: 12, color: '#93c5fd', fontFamily: "'Space Mono', monospace" }}>Add Staff Manually</div>
        <div style={{ display: 'grid', gap: 10, gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))' }}>
          <input value={manualName} onChange={(e) => setManualName(e.target.value)} placeholder='Name' style={{ background: '#111827', border: '1px solid #1f2937', color: '#fff', borderRadius: 8, padding: '10px 12px', fontFamily: "'Space Mono', monospace" }} />
          <select value={manualRole} onChange={(e) => setManualRole(e.target.value)} style={{ background: '#111827', border: '1px solid #1f2937', color: '#fff', borderRadius: 8, padding: '10px 12px', fontFamily: "'Space Mono', monospace" }}>
            {ROLE_OPTIONS.map((role) => <option key={role} value={role}>{role}</option>)}
          </select>
          <select value={manualShift} onChange={(e) => setManualShift(e.target.value)} style={{ background: '#111827', border: '1px solid #1f2937', color: '#fff', borderRadius: 8, padding: '10px 12px', fontFamily: "'Space Mono', monospace" }}>
            {SHIFT_TYPES.map((shift) => <option key={shift.id} value={shift.id}>{shift.label}</option>)}
          </select>
        </div>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: 10 }}>
          <div style={{ fontSize: 11, color: '#94a3b8', fontFamily: "'Space Mono', monospace" }}>Manual additions: {parsed.length}</div>
          <button className='ghost-button' onClick={() => { const name = manualName.trim(); if (!name) return; const shift = SHIFT_TYPES.find((item) => item.id === manualShift) || SHIFT_TYPES[0]; const person = { id: Date.now(), name, role: manualRole, shift: shift.id, shiftLabel: shift.label, room: '' }; setParsed((current) => [...current, person]); setManualName(''); setError(''); }}>Add Staff</button>
        </div>
      </div>

      {error ? <div style={{ background: '#451a24', border: '1px solid #7f1d1d', borderRadius: 12, padding: 14, color: '#fecaca', fontFamily: "'Space Mono', monospace", fontSize: 11 }}>{error}</div> : null}
      {preview ? <div style={{ background: '#0f1117', border: '1px solid #1e2433', borderRadius: 14, padding: 18 }}><div style={{ fontSize: 11, color: '#93c5fd', fontFamily: "'Space Mono', monospace", marginBottom: 10 }}>CSV Preview</div><pre style={{ margin: 0, color: '#cbd5e1', fontFamily: "'Space Mono', monospace", fontSize: 11, whiteSpace: 'pre-wrap' }}>{preview}</pre></div> : null}
      {parsed.length ? <div style={{ display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}><div style={{ background: '#052e1b', border: '1px solid #166534', borderRadius: 12, padding: 14, color: '#86efac', fontFamily: "'Space Mono', monospace", fontSize: 11 }}>Parsed {parsed.length} staff records. Loading this file will replace the roster for {formatReadableDate(targetDate)}.</div><button onClick={() => onImport(parsed)} style={{ background: '#4ade80', color: '#04130a', border: 'none', borderRadius: 10, padding: '12px 18px', fontWeight: 900, cursor: 'pointer' }}>Load Roster</button></div> : null}
    </div>
  );
}

function NavBar({ activeTab, setActiveTab, publishedAt, collapsed, onToggle, onLogout }) {
  const [mobileOpen, setMobileOpen] = React.useState(false);

  const tabs = [
    { id: 'home', label: 'Home Board' },
    { id: 'calendar', label: 'Calendar' },
    { id: 'admin', label: 'Admin View' },
    { id: 'analytics', label: 'Analytics' },
    { id: 'import', label: 'Import' },
  ];

  const handleTabClick = (id) => {
    setActiveTab(id);
    setMobileOpen(false);
  };

  return (
    <>
      {/* Mobile top bar — only visible on mobile */}
      <div className='mobile-app-topbar'>
        <BrandLogo />
        <button
          className='mobile-hamburger'
          onClick={() => setMobileOpen(true)}
          aria-label='Open navigation menu'
        >
          <svg width='22' height='22' viewBox='0 0 24 24' fill='none' stroke='currentColor' strokeWidth='2.5' strokeLinecap='round'>
            <line x1='3' y1='6' x2='21' y2='6' />
            <line x1='3' y1='12' x2='21' y2='12' />
            <line x1='3' y1='18' x2='21' y2='18' />
          </svg>
        </button>
      </div>

      {/* Mobile slide-in drawer */}
      {mobileOpen && (
        <div className='mobile-drawer-overlay' onClick={() => setMobileOpen(false)} />
      )}
      <div className={`mobile-drawer ${mobileOpen ? 'open' : ''}`}>
        <div className='mobile-drawer-header'>
          <BrandLogo />
          <button className='mobile-drawer-close' onClick={() => setMobileOpen(false)} aria-label='Close menu'>
            <svg width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='currentColor' strokeWidth='2.5' strokeLinecap='round'>
              <line x1='18' y1='6' x2='6' y2='18' />
              <line x1='6' y1='6' x2='18' y2='18' />
            </svg>
          </button>
        </div>
        <div className='mobile-drawer-tabs'>
          {tabs.map((tab) => (
            <button
              key={tab.id}
              onClick={() => handleTabClick(tab.id)}
              className={`mobile-drawer-tab ${activeTab === tab.id ? 'active' : ''}`}
            >
              {tab.label}
            </button>
          ))}
        </div>
        <div className='mobile-drawer-footer'>
          <button className='mobile-logout-btn' onClick={onLogout}>
            <svg width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='currentColor' strokeWidth='2' strokeLinecap='round' strokeLinejoin='round' style={{ marginRight: 8 }}>
              <path d='M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4' />
              <polyline points='16 17 21 12 16 7' />
              <line x1='21' y1='12' x2='9' y2='12' />
            </svg>
            Log Out
          </button>
          <div style={{ fontSize: 11, color: '#475569', marginTop: 12 }}>
            {publishedAt ? `Last published ${new Date(publishedAt).toLocaleTimeString()}` : 'No published board yet'}
          </div>
        </div>
      </div>

      {/* Desktop sidebar — unchanged */}
      <nav className={`app-nav ${collapsed ? 'collapsed' : ''}`}>
        <div className='nav-brand'>
          <BrandLogo />
          <div className='nav-caption' style={{ marginTop: 10 }}>Surgical staffing, room flow, and operational visibility</div>
          <button className='ghost-button nav-toggle' onClick={onToggle}>{collapsed ? 'Expand Menu' : 'Collapse Menu'}</button>
        </div>
        <div className='nav-tabs'>
          {tabs.map((tab) => <button key={tab.id} onClick={() => setActiveTab(tab.id)} className={`nav-tab ${activeTab === tab.id ? 'active' : ''}`}>{tab.label}</button>)}
        </div>
        <div className='nav-footer'>
          <div className='nav-footer-label'>Publish Status</div>
          <div className='nav-footer-text'>{publishedAt ? `Live board updated ${new Date(publishedAt).toLocaleString()}` : 'No published board yet'}</div>
        </div>
      </nav>
    </>
  );
}

function ORStaffingApp() {
  const [activeTab, setActiveTab] = useState('home');
  const [navCollapsed, setNavCollapsed] = useState(false);
  const [undoRosterByDate, setUndoRosterByDate] = useState({});
  const [roleMap, setRoleMap] = useState(() => loadRoleMap());
  const [selectedDate, setSelectedDate] = useState(() => formatDateKey(new Date()));
  const [calendarMonth, setCalendarMonth] = useState(() => formatDateKey(new Date()).slice(0, 7));
  const [scheduleByDate, setScheduleByDate] = useState(() => {
    const applied = applyRoleMap(generateSampleStaff(), loadRoleMap());
    saveRoleMap(applied.roleMap);
    return { [formatDateKey(new Date())]: createDayData(applied.roster) };
  });

  const ensureDay = useCallback((dateKey, current) => {
    if (current[dateKey]) return current;
    const fallbackRoster = current[selectedDate]?.roster || applyRoleMap(generateSampleStaff(), roleMap).roster;
    return { ...current, [dateKey]: createDayData(fallbackRoster) };
  }, [roleMap, selectedDate]);

  const currentDay = scheduleByDate[selectedDate] || createDayData(applyRoleMap(generateSampleStaff(), roleMap).roster);

  const handleSelectDate = useCallback((dateKey) => {
    setSelectedDate(dateKey);
    setCalendarMonth(dateKey.slice(0, 7));
    setScheduleByDate((current) => ensureDay(dateKey, current));
  }, [ensureDay]);

  const handleMonthChange = useCallback((offset) => {
    const [year, month] = calendarMonth.split('-').map(Number);
    const next = new Date(year, month - 1 + offset, 1);
    setCalendarMonth(`${next.getFullYear()}-${String(next.getMonth() + 1).padStart(2, '0')}`);
  }, [calendarMonth]);
  const handleFieldChange = useCallback((roomNumber, field, value) => {
    setScheduleByDate((current) => {
      const next = ensureDay(selectedDate, current);
      return {
        ...next,
        [selectedDate]: {
          ...next[selectedDate],
          draftAssignments: next[selectedDate].draftAssignments.map((room) => room.roomNumber === roomNumber ? { ...room, [field]: value } : room),
        },
      };
    });
  }, [ensureDay, selectedDate]);

  const handleAddRoom = useCallback((roomNumber) => {
    let added = false;
    setScheduleByDate((current) => {
      const next = ensureDay(selectedDate, current);
      if (next[selectedDate].draftAssignments.some((room) => room.roomNumber === roomNumber)) return next;
      added = true;
      return {
        ...next,
        [selectedDate]: {
          ...next[selectedDate],
          draftAssignments: sortAssignments([...next[selectedDate].draftAssignments, createEmptyAssignment(roomNumber)]),
        },
      };
    });
    return added;
  }, [ensureDay, selectedDate]);

  const handlePublish = useCallback(() => {
    setScheduleByDate((current) => {
      const next = ensureDay(selectedDate, current);
      return {
        ...next,
        [selectedDate]: {
          ...next[selectedDate],
          publishedAssignments: next[selectedDate].draftAssignments.map((room) => ({ ...room })),
          publishedAt: new Date().toISOString(),
        },
      };
    });
    setActiveTab('home');
  }, [ensureDay, selectedDate]);

  const handleRoleChange = useCallback((name, role) => {
    const normalized = normalizeRole(role);
    setRoleMap((current) => {
      const next = { ...current, [String(name || '').trim().toLowerCase()]: normalized };
      saveRoleMap(next);
      return next;
    });
    setScheduleByDate((current) => {
      const next = { ...current };
      Object.keys(next).forEach((dateKey) => {
        next[dateKey] = {
          ...next[dateKey],
          roster: next[dateKey].roster.map((person) => person.name === name ? { ...person, role: normalized } : person),
        };
      });
      return next;
    });
  }, []);

  const handleImport = useCallback((rows) => {
    const applied = applyRoleMap(rows, roleMap);
    saveRoleMap(applied.roleMap);
    setRoleMap(applied.roleMap);
    let previousRoster = [];
    setScheduleByDate((current) => {
      const next = ensureDay(selectedDate, current);
      previousRoster = next[selectedDate].roster;
      return {
        ...next,
        [selectedDate]: {
          ...next[selectedDate],
          roster: applied.roster,
        },
      };
    });
    setUndoRosterByDate((current) => ({ ...current, [selectedDate]: previousRoster }));
    setActiveTab('home');
  }, [ensureDay, roleMap, selectedDate]);

  const handleClearRoster = useCallback(() => {
    let previousRoster = [];
    setScheduleByDate((current) => {
      const next = ensureDay(selectedDate, current);
      previousRoster = next[selectedDate].roster;
      return {
        ...next,
        [selectedDate]: {
          ...next[selectedDate],
          roster: [],
        },
      };
    });
    setUndoRosterByDate((current) => ({ ...current, [selectedDate]: previousRoster }));
  }, [ensureDay, selectedDate]);

  const handleUndoRoster = useCallback(() => {
    const backup = undoRosterByDate[selectedDate];
    if (!backup) return;
    setScheduleByDate((current) => {
      const next = ensureDay(selectedDate, current);
      return {
        ...next,
        [selectedDate]: {
          ...next[selectedDate],
          roster: backup,
        },
      };
    });
    setUndoRosterByDate((current) => {
      const copy = { ...current };
      delete copy[selectedDate];
      return copy;
    });
  }, [ensureDay, selectedDate, undoRosterByDate]);

  const pages = {
    home: <HomeView assignments={currentDay.publishedAssignments} publishedAt={currentDay.publishedAt} roster={currentDay.roster} selectedDate={selectedDate} onToggleNav={() => setNavCollapsed((value) => !value)} />,
    calendar: <CalendarView selectedDate={selectedDate} onSelectDate={handleSelectDate} monthKey={calendarMonth} onMonthChange={handleMonthChange} scheduleByDate={scheduleByDate} />,
    admin: <AdminView assignments={currentDay.draftAssignments} onFieldChange={handleFieldChange} onAddRoom={handleAddRoom} onPublish={handlePublish} roster={currentDay.roster} onRoleChange={handleRoleChange} publishedAt={currentDay.publishedAt} selectedDate={selectedDate} />,
    analytics: <AnalyticsView assignments={currentDay.publishedAssignments} roster={currentDay.roster} selectedDate={selectedDate} />,
    import: <ImportView onImport={handleImport} onClearRoster={handleClearRoster} onUndoRoster={handleUndoRoster} canUndo={Boolean(undoRosterByDate[selectedDate])} rosterCount={currentDay.roster.length} targetDate={selectedDate} onTargetDateChange={handleSelectDate} />,
  };

  return (
    <>
      <style>{`
        @import url('https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800;900&family=Space+Mono:wght@400;700&display=swap');
        * { box-sizing: border-box; margin: 0; padding: 0; }
        html, body, #root { min-height: 100%; }
        body { background: #080b12; color: #fff; }
        button, input, select, textarea { outline: none; }
        .app-shell { display: flex; min-height: 100vh; background: #080b12; font-family: 'Syne', sans-serif; }
        .app-nav { width: 230px; min-height: 100vh; background: #0f1117; border-right: 1px solid #1e2433; display: flex; flex-direction: column; transition: width 0.2s ease; }
        .app-nav.collapsed { width: 72px; }
        .app-nav.collapsed .nav-brand-text, .app-nav.collapsed .nav-caption, .app-nav.collapsed .nav-footer { display: none; }
        .app-nav.collapsed .nav-tab { padding: 10px 12px; text-align: center; border-left: none; }
        .app-nav.collapsed .nav-tab.active { border-left: none; }
        .nav-brand { padding: 28px 24px 20px; border-bottom: 1px solid #1e2433; }
        .nav-caption { font-size: 10px; color: #64748b; font-family: 'Space Mono', monospace; }
        .nav-tabs { padding: 12px 0; flex: 1; }
        .nav-tab { width: 100%; background: transparent; border: none; border-left: 3px solid transparent; color: #94a3b8; padding: 12px 24px; text-align: left; font-weight: 700; cursor: pointer; }
        .nav-tab.active { background: #172033; border-left-color: #4ade80; color: #fff; }
        .nav-footer { padding: 18px 24px; border-top: 1px solid #1e2433; }
        .nav-footer-label { font-size: 10px; color: #4ade80; font-family: 'Space Mono', monospace; }
        .nav-footer-text { font-size: 11px; color: #cbd5e1; font-family: 'Space Mono', monospace; margin-top: 8px; line-height: 1.5; }
        .app-main { flex: 1; padding: 20px; overflow-y: auto; max-height: 100vh; }
        /* Mobile top bar + drawer — hidden on desktop */
        .mobile-app-topbar { display: none; }
        .mobile-drawer { display: none; }
        .mobile-drawer-overlay { display: none; }
        .home-board-page { display: flex; flex-direction: column; gap: 14px; }
        .board-header { display: flex; justify-content: space-between; align-items: flex-start; gap: 14px; flex-wrap: wrap; }
        .board-title { font-size: 28px; font-weight: 900; color: #fff; }
        .board-subtitle { font-size: 11px; color: #64748b; font-family: 'Space Mono', monospace; margin-top: 4px; }
        .board-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
        .ghost-button { background: #0f1117; border: 1px solid #1e2433; color: #cbd5e1; border-radius: 10px; padding: 8px 12px; font-weight: 700; cursor: pointer; }
        .ghost-button:hover { border-color: #4ade80; color: #fff; }
        .board-stats { display: flex; gap: 10px; flex-wrap: wrap; }
        .stat-pill { display: flex; flex-direction: column; gap: 4px; min-width: 92px; padding: 10px 12px; background: #0f1117; border: 1px solid #1e2433; border-radius: 12px; }
        .stat-pill.wide { min-width: 210px; }
        .stat-pill.running .stat-value { color: #f59e0b; }
        .stat-label { font-size: 9px; color: #64748b; font-family: 'Space Mono', monospace; text-transform: uppercase; }
        .stat-value { font-size: 24px; color: #4ade80; font-weight: 900; line-height: 1; }
        .stat-timestamp { font-size: 12px; color: #e2e8f0; font-weight: 700; line-height: 1.3; }
        .wallboard-layout { display: grid; grid-template-columns: minmax(0, 3.2fr) minmax(220px, 0.72fr); gap: 14px; }
        .wallboard-panel { background: #0f1117; border: 1px solid #1e2433; border-radius: 14px; padding: 12px; }
        .panel-title { font-size: 11px; color: #93c5fd; font-family: 'Space Mono', monospace; margin-bottom: 10px; text-transform: uppercase; }
        .tv-table-wrap { overflow: hidden; }
        .tv-table { width: 100%; border-collapse: collapse; table-layout: fixed; }
        .tv-table th { font-size: 8px; color: #93c5fd; font-family: 'Space Mono', monospace; font-weight: 700; text-transform: uppercase; padding: 5px 6px; border-bottom: 1px solid #1e2433; text-align: left; }
        .tv-table td { font-size: 8px; color: #e2e8f0; padding: 5px 6px; border-bottom: 1px solid rgba(30, 36, 51, 0.6); line-height: 1.15; vertical-align: top; word-break: break-word; }
        .room-id-cell { font-size: 9px; font-weight: 800; color: #fff; white-space: nowrap; }
        .empty-cell { color: #475569; }
        .roster-grid { display: grid; grid-template-columns: 1fr; gap: 8px; }
        .roster-chip { background: #080b12; border: 1px solid #182132; border-radius: 10px; padding: 8px 9px; min-height: 62px; }
        .roster-name-row { display: flex; justify-content: space-between; gap: 8px; align-items: flex-start; }
        .roster-name { font-size: 11px; color: #fff; font-weight: 800; line-height: 1.2; }
        .roster-status { font-size: 8px; font-family: 'Space Mono', monospace; padding: 2px 6px; border-radius: 999px; white-space: nowrap; }
        .roster-status.assigned { color: #0f172a; background: #60a5fa; }
        .roster-status.available { color: #052e1b; background: #4ade80; }
        .roster-meta { font-size: 8px; color: #94a3b8; font-family: 'Space Mono', monospace; line-height: 1.35; margin-top: 5px; }
        .admin-layout { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 16px; align-items: start; }
        .coverage-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 16px; }
        .coverage-layout { display: grid; grid-template-columns: 1.4fr 1fr; gap: 16px; }
        .import-columns { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
        ::-webkit-scrollbar { width: 8px; height: 8px; }
        ::-webkit-scrollbar-track { background: #0f1117; }
        ::-webkit-scrollbar-thumb { background: #1f2937; border-radius: 999px; }
        @media (max-width: 1024px) {
          body { font-size: 16px !important; }
          .app-shell { flex-direction: column; }
          .app-nav { width: 100%; min-height: auto; border-right: none; border-bottom: 1px solid #1e2433; position: sticky; top: 0; z-index: 100; }
          .nav-brand { padding: 12px 16px; }
          .nav-brand-text { display: block !important; }
          .nav-brand-text div:first-child { font-size: 14px !important; }
          .nav-brand-text div:last-child { font-size: 20px !important; }
          .nav-caption { display: none; }
          .nav-tabs { display: flex; overflow-x: auto; padding: 12px; gap: 8px; }
          .nav-tab { width: auto; min-width: 110px; padding: 12px 16px; border-left: none; border-radius: 10px; border: 1px solid #1e2433; white-space: nowrap; font-size: 16px !important; }
          .nav-tab.active { border-color: #4ade80; background: #172033; }
          .nav-footer { display: none; }
          .app-main { max-height: none; overflow-y: visible; padding: 16px; }
          
          .wallboard-layout { grid-template-columns: 1fr !important; gap: 16px; }
          .admin-layout, .coverage-layout { grid-template-columns: 1fr; gap: 16px; }
          .board-header { flex-direction: column; align-items: stretch; }
          .board-actions { flex-direction: column; gap: 12px; align-items: stretch; margin-top: 16px; }
          .board-stats { display: flex; flex-direction: column; gap: 12px; margin-top: 16px; }
          .stat-pill { padding: 16px; min-height: auto; }
          .stat-value { font-size: 24px; }
          .stat-label { font-size: 12px; margin-bottom: 4px; }
          
          /* Enforce 44px min-height & 16px font on interactive elements */
          button, input, select, textarea { min-height: 48px !important; font-size: 16px !important; padding: 12px 16px !important; word-wrap: break-word; }
          .ghost-button { width: 100%; text-align: center; }
          
          /* Mobile cards for tv-table */
          .tv-table-wrap { overflow: visible !important; }
          .tv-table, .tv-table tbody, .tv-table tr, .tv-table td { display: block; width: 100%; }
          .tv-table thead { display: none; }
          .tv-table tr { background: #172033; border: 1px solid #1e2433; border-radius: 16px; padding: 16px; margin-bottom: 16px; }
          .tv-table td { font-size: 16px !important; padding: 12px 0 !important; border-bottom: 1px solid rgba(255,255,255,0.05) !important; text-align: left !important; white-space: normal !important; }
          .tv-table td:last-child { border-bottom: none !important; }
          .room-id-cell { font-size: 22px !important; font-weight: 900; color: #4ade80 !important; text-align: center !important; margin-bottom: 12px; padding-bottom: 16px !important; border-bottom: 1px solid #1e293b !important; }
          .empty-cell { display: block !important; color: #475569 !important; } 

          .tv-table td::before { display: block; font-size: 12px; color: #94A3B8; margin-bottom: 4px; font-weight: 700; text-transform: uppercase; }
          .tv-table td:nth-child(2)::before { content: 'Surgeon'; }
          .tv-table td:nth-child(3)::before { content: 'Circ 1'; }
          .tv-table td:nth-child(4)::before { content: 'Circ 2'; }
          .tv-table td:nth-child(5)::before { content: 'Scrub 1'; }
          .tv-table td:nth-child(6)::before { content: 'Scrub 2'; }
          .tv-table td:nth-child(7)::before { content: 'Relief RN'; }
          .tv-table td:nth-child(8)::before { content: 'Relief Scrub'; }
          .tv-table td:nth-child(9)::before { content: 'Comments'; }

          /* Stack Admin Grid */
          .admin-layout > div > div { display: flex !important; flex-direction: column !important; gap: 16px !important; background: transparent !important; }
          .admin-layout > div > div > div { background: #0f1117 !important; padding: 0 !important; display: flex; flex-direction: column; gap: 8px; }
          .admin-layout > div > div > div:nth-child(-n+9) { display: none !important; }
          .admin-layout > div > div > div:nth-child(9n+1) { background: #172033 !important; font-size: 24px !important; color: #4ade80 !important; text-align: center !important; margin-top: 32px !important; padding: 16px !important; border-radius: 12px; }
          .admin-layout > div > div > div::before { font-size: 12px; color: #94A3B8; text-transform: uppercase; padding-left: 4px; font-weight: 700; }
          .admin-layout > div > div > div:nth-child(9n+2)::before { content: 'Surgeon'; }
          .admin-layout > div > div > div:nth-child(9n+3)::before { content: 'Circulator #1'; }
          .admin-layout > div > div > div:nth-child(9n+4)::before { content: 'Circulator #2'; }
          .admin-layout > div > div > div:nth-child(9n+5)::before { content: 'Scrub Person #1'; }
          .admin-layout > div > div > div:nth-child(9n+6)::before { content: 'Scrub Person #2'; }
          .admin-layout > div > div > div:nth-child(9n+7)::before { content: 'Relief RN'; }
          .admin-layout > div > div > div:nth-child(9n+8)::before { content: 'Relief Scrub'; }
          .admin-layout > div > div > div:nth-child(9n+9)::before { content: 'Comments'; }
          
          /* Roster updates */
          .roster-grid { gap: 12px; }
          .roster-chip { padding: 16px; }
          .roster-name { font-size: 18px; line-height: 1.4; }
          .roster-status { padding: 8px 14px; font-size: 14px; display: inline-block; margin-top: 8px; }
          .roster-meta { font-size: 14px; margin-top: 12px; white-space: normal; }
          
          .nav-toggle { display: none; }
          
          /* Hide desktop sidebar on mobile — replaced by drawer */
          .app-nav { display: none !important; }

          /* Mobile top bar */
          .mobile-app-topbar { display: flex !important; align-items: center; justify-content: space-between; padding: 12px 16px; background: #0f1117; border-bottom: 1px solid #1e2433; position: sticky; top: 0; z-index: 200; }
          .mobile-hamburger { display: flex !important; align-items: center; justify-content: center; background: rgba(255,255,255,0.06); border: 1px solid #1e2433; color: #fff; border-radius: 10px; width: 44px; height: 44px; cursor: pointer; min-height: 44px !important; padding: 0 !important; }

          /* Mobile slide-in drawer */
          .mobile-drawer-overlay { display: block !important; position: fixed; inset: 0; background: rgba(0,0,0,0.6); z-index: 300; }
          .mobile-drawer { display: flex !important; flex-direction: column; position: fixed; top: 0; left: 0; height: 100vh; width: 82vw; max-width: 320px; background: #0b1220; border-right: 1px solid #1e2433; z-index: 400; transform: translateX(-100%); transition: transform 0.25s ease; }
          .mobile-drawer.open { transform: translateX(0); }
          .mobile-drawer-header { display: flex; align-items: center; justify-content: space-between; padding: 20px 20px 16px; border-bottom: 1px solid #1e2433; }
          .mobile-drawer-close { background: transparent; border: none; color: #94a3b8; cursor: pointer; padding: 8px; min-height: 44px !important; display: flex; align-items: center; justify-content: center; }
          .mobile-drawer-tabs { flex: 1; overflow-y: auto; padding: 16px 12px; display: flex; flex-direction: column; gap: 6px; }
          .mobile-drawer-tab { width: 100%; background: transparent; border: none; border-radius: 10px; color: #94a3b8; padding: 14px 16px; text-align: left; font-size: 16px; font-weight: 600; cursor: pointer; min-height: 52px !important; transition: background 0.15s; }
          .mobile-drawer-tab:hover { background: #172033; color: #e2e8f0; }
          .mobile-drawer-tab.active { background: #172033; color: #4ade80; border-left: 3px solid #4ade80; }
          .mobile-drawer-footer { padding: 20px; border-top: 1px solid #1e2433; }
          .mobile-logout-btn { display: flex; align-items: center; width: 100%; background: rgba(251,113,133,0.08); border: 1px solid rgba(251,113,133,0.2); color: #fb7185; padding: 14px 16px; border-radius: 10px; font-size: 15px; font-weight: 600; cursor: pointer; min-height: 52px !important; transition: background 0.15s; }
          .mobile-logout-btn:hover { background: rgba(251,113,133,0.15); }

          /* App shell stays flex but sidebar hidden — content fills full width */
          .app-shell { flex-direction: column; }
          .app-main { max-height: none; overflow-y: visible; padding: 16px; }
          
          /* Calendar Mobile */
          .calendar-day-btn { min-height: 72px !important; padding: 12px !important; font-size: 18px !important; }
          .calendar-day-btn div:last-child { display: none !important; }
          .calendar-day-btn div:nth-child(2) { margin-top: 8px !important; font-size: 14px !important; }
        }

        @media (max-width: 600px) {
          .board-title { font-size: 22px; }
          .nav-brand-text div:last-child { font-size: 20px !important; }
          .stat-pill { padding: 10px; }
          .stat-value { font-size: 18px; }
          .stat-label { font-size: 8px; }
          .nav-tab { min-width: 85px; font-size: 11px; padding: 8px 12px; }
          .panel-title { font-size: 9px; }
        }
      `}</style>
      <div className='app-shell'>
        <NavBar activeTab={activeTab} setActiveTab={setActiveTab} publishedAt={currentDay.publishedAt} collapsed={navCollapsed} onToggle={() => setNavCollapsed((value) => !value)} onLogout={() => { if (window.onORFlowLogout) window.onORFlowLogout(); }} />
        <main className='app-main'>{pages[activeTab]}</main>
      </div>
    </>
  );
}

window.Playground = ORStaffingApp;
})();

































