import React, { useEffect, useState, useMemo, useRef } from 'react';
import type { SeatingTemplate } from './SeatingTemplatesSection';
import { StudentAvatar, StudentOnlineBadge } from './StudentAvatar';
import { apiSeatingLayout } from '../api';

// ── Inline SVG icons (stroke-only, matching LearningTab / ExamsTab style) ─────

type IconProps = { size?: number };

const IconChair = ({ size = 32 }: IconProps) => (
  <svg viewBox="0 0 24 24" width={size} height={size} fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
    <path d="M4 12V6a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v6" />
    <path d="M2 12h20" />
    <path d="M6 12v5" />
    <path d="M18 12v5" />
    <path d="M4 17h16" />
    <path d="M8 21v-4" />
    <path d="M16 21v-4" />
  </svg>
);

const IconGrid = ({ size = 14 }: IconProps) => (
  <svg viewBox="0 0 24 24" width={size} height={size} fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
    <rect x="3" y="3" width="7" height="7" rx="1" />
    <rect x="14" y="3" width="7" height="7" rx="1" />
    <rect x="3" y="14" width="7" height="7" rx="1" />
    <rect x="14" y="14" width="7" height="7" rx="1" />
  </svg>
);

const IconList = ({ size = 14 }: IconProps) => (
  <svg viewBox="0 0 24 24" width={size} height={size} fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
    <path d="M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01" />
  </svg>
);

const IconZap = ({ size = 13 }: IconProps) => (
  <svg viewBox="0 0 24 24" width={size} height={size} fill="none" stroke="currentColor" strokeWidth="2.25" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
    <path d="M13 2 3 14h9l-1 8 10-12h-9l1-8z" />
  </svg>
);

const IconTrash = ({ size = 13 }: IconProps) => (
  <svg viewBox="0 0 24 24" width={size} height={size} fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
    <path d="M3 6h18" />
    <path d="M8 6V4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v2" />
    <path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" />
    <path d="M10 11v6M14 11v6" />
  </svg>
);

const IconSettings = ({ size = 13 }: IconProps) => (
  <svg viewBox="0 0 24 24" width={size} height={size} fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
    <circle cx="12" cy="12" r="3" />
    <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" />
  </svg>
);

const IconCheck = ({ size = 13 }: IconProps) => (
  <svg viewBox="0 0 24 24" width={size} height={size} fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
    <path d="M20 6 9 17l-5-5" />
  </svg>
);

const IconLock = ({ size = 14 }: IconProps) => (
  <svg viewBox="0 0 24 24" width={size} height={size} fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
    <rect x="3" y="11" width="18" height="11" rx="2" />
    <path d="M7 11V7a5 5 0 0 1 10 0v4" />
  </svg>
);

const IconX = ({ size = 10 }: IconProps) => (
  <svg viewBox="0 0 24 24" width={size} height={size} fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
    <path d="M18 6 6 18M6 6l12 12" />
  </svg>
);

const IconSearch = ({ size = 15 }: IconProps) => (
  <svg viewBox="0 0 24 24" width={size} height={size} fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
    <circle cx="11" cy="11" r="7" />
    <line x1="21" y1="21" x2="16.65" y2="16.65" />
  </svg>
);

const IconFileText = ({ size = 11 }: IconProps) => (
  <svg viewBox="0 0 24 24" width={size} height={size} fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
    <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
    <polyline points="14 2 14 8 20 8" />
    <line x1="16" y1="13" x2="8" y2="13" />
    <line x1="16" y1="17" x2="8" y2="17" />
    <polyline points="10 9 9 9 8 9" />
  </svg>
);

const IconBoard = ({ size = 13 }: IconProps) => (
  <svg viewBox="0 0 24 24" width={size} height={size} fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
    <rect x="2" y="3" width="20" height="14" rx="2" />
    <path d="M8 21h8M12 17v4" />
  </svg>
);

const IconTemplate = ({ size = 15 }: IconProps) => (
  <svg viewBox="0 0 24 24" width={size} height={size} fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
    <rect x="3" y="3" width="18" height="18" rx="2" />
    <path d="M3 9h18M9 21V9" />
  </svg>
);

const IconSliders = ({ size = 15 }: IconProps) => (
  <svg viewBox="0 0 24 24" width={size} height={size} fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
    <line x1="4" y1="6" x2="20" y2="6" />
    <line x1="4" y1="12" x2="20" y2="12" />
    <line x1="4" y1="18" x2="20" y2="18" />
    <circle cx="8" cy="6" r="2" fill="currentColor" stroke="none" />
    <circle cx="16" cy="12" r="2" fill="currentColor" stroke="none" />
    <circle cx="10" cy="18" r="2" fill="currentColor" stroke="none" />
  </svg>
);

const IconRefresh = ({ size = 13 }: IconProps) => (
  <svg viewBox="0 0 24 24" width={size} height={size} fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
    <path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" />
    <path d="M3 3v5h5" />
  </svg>
);

// ── Component ─────────────────────────────────────────────────────────────────

interface WorkspaceSeatingChartProps {
  workspaceId: string;
  students: {
    rkId: number;
    fullName: string;
    studentCode: string;
    avatar?: string;
    paperTitle?: string;
  }[];
  onlineIds: number[];
  onStudentClick?: (studentRkId: number) => void;
}

interface SeatingLayout {
  rows: number;
  cols: number;
  boardPosition: 'top' | 'bottom' | 'left' | 'right';
  lockedSeats: string[];
  seats: Record<string, number>;
}

export const WorkspaceSeatingChart: React.FC<WorkspaceSeatingChartProps> = ({
  workspaceId,
  students,
  onlineIds,
  onStudentClick,
}) => {
  const [layout, setLayout] = useState<SeatingLayout | null>(null);
  const [templates, setTemplates] = useState<SeatingTemplate[]>([]);
  const [searchQuery, setSearchQuery] = useState('');
  const [setupMode, setSetupMode] = useState<'template' | 'custom'>('template');
  const [customRows, setCustomRows] = useState(5);
  const [customCols, setCustomCols] = useState(6);
  const [customBoard, setCustomBoard] = useState<'top' | 'bottom' | 'left' | 'right'>('top');
  const [selectedTemplateId, setSelectedTemplateId] = useState('');
  const [isEditingStructure, setIsEditingStructure] = useState(false);
  const [editRows, setEditRows] = useState(5);
  const [editCols, setEditCols] = useState(6);
  const [editBoardPos, setEditBoardPos] = useState<'top' | 'bottom' | 'left' | 'right'>('top');
  const [dragOverCell, setDragOverCell] = useState<string | null>(null);
  const [saveNotice, setSaveNotice] = useState<string | null>(null);
  const [saveNoticeKind, setSaveNoticeKind] = useState<'success' | 'error'>('success');
  const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid');
  const [listSearchQuery, setListSearchQuery] = useState('');

  const workspaceInfo = useMemo(() => {
    if (workspaceId.startsWith('class-')) {
      const n = Number(workspaceId.replace('class-', ''));
      return isNaN(n) ? null : { kind: 'class' as const, id: n };
    }
    if (workspaceId.startsWith('exam-')) {
      const n = Number(workspaceId.replace('exam-', ''));
      return isNaN(n) ? null : { kind: 'exam' as const, id: n };
    }
    return null;
  }, [workspaceId]);

  const saveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const pendingLayoutRef = useRef<SeatingLayout | null | undefined>(undefined);
  const legacyLayoutKey = `sc_seating_layout_${workspaceId}`;

  const showSaveNotice = (message: string, kind: 'success' | 'error' = 'success') => {
    setSaveNoticeKind(kind);
    setSaveNotice(message);
  };

  const persistLayout = async (newLayout: SeatingLayout | null) => {
    if (!workspaceInfo) return;
    try {
      if (newLayout) {
        const json = JSON.stringify(newLayout);
        const saver = workspaceInfo.kind === 'class'
          ? apiSeatingLayout.saveClass(workspaceInfo.id, json)
          : apiSeatingLayout.saveExam(workspaceInfo.id, json);
        await saver;
        localStorage.removeItem(legacyLayoutKey);
        showSaveNotice('Đã lưu sơ đồ chỗ ngồi lên server');
      } else {
        const deleter = workspaceInfo.kind === 'class'
          ? apiSeatingLayout.deleteClass(workspaceInfo.id)
          : apiSeatingLayout.deleteExam(workspaceInfo.id);
        await deleter;
        localStorage.removeItem(legacyLayoutKey);
        showSaveNotice('Đã xóa sơ đồ chỗ ngồi trên server');
      }
    } catch {
      if (newLayout) {
        localStorage.setItem(legacyLayoutKey, JSON.stringify(newLayout));
      }
      showSaveNotice('Lưu server thất bại — đã giữ bản cục bộ tạm. Kiểm tra server đã deploy API sơ đồ chưa.', 'error');
    } finally {
      pendingLayoutRef.current = undefined;
    }
  };

  const studentSeats = useMemo(() => {
    if (!layout) return {} as Record<number, string>;
    const mapping: Record<number, string> = {};
    Object.entries(layout.seats).forEach(([cellKey, rkId]) => {
      const [rStr, cStr] = cellKey.split(',');
      const r = Number(rStr) + 1;
      const c = Number(cStr) + 1;
      mapping[rkId] = `Hàng ${r}, Cột ${c}`;
    });
    return mapping;
  }, [layout]);

  const filteredListStudents = useMemo(() => {
    return students.filter(
      (s) =>
        s.fullName.toLowerCase().includes(listSearchQuery.toLowerCase()) ||
        s.studentCode.toLowerCase().includes(listSearchQuery.toLowerCase())
    );
  }, [students, listSearchQuery]);

  const hasPaperColumn = useMemo(() => {
    return students.some((s) => s.paperTitle);
  }, [students]);

  useEffect(() => {
    const storedTemplates = localStorage.getItem('sc_seating_templates');
    if (storedTemplates) {
      try { setTemplates(JSON.parse(storedTemplates)); } catch { setTemplates([]); }
    }
    if (workspaceInfo !== null) {
      const getter = workspaceInfo.kind === 'class'
        ? apiSeatingLayout.getClass(workspaceInfo.id)
        : apiSeatingLayout.getExam(workspaceInfo.id);
      getter.then(async (json) => {
        if (json) {
          try { setLayout(JSON.parse(json)); localStorage.removeItem(legacyLayoutKey); } catch { setLayout(null); }
          return;
        }
        const legacy = localStorage.getItem(legacyLayoutKey);
        if (!legacy) { setLayout(null); return; }
        try {
          const parsed = JSON.parse(legacy) as SeatingLayout;
          setLayout(parsed);
          await persistLayout(parsed);
        } catch { setLayout(null); }
      }).catch(() => setLayout(null));
    } else {
      setLayout(null);
    }
  }, [workspaceId, workspaceInfo, legacyLayoutKey]);

  const saveLayout = (newLayout: SeatingLayout | null) => {
    setLayout(newLayout);
    if (!workspaceInfo) return;
    pendingLayoutRef.current = newLayout;
    if (saveTimerRef.current) clearTimeout(saveTimerRef.current);
    saveTimerRef.current = setTimeout(() => {
      void persistLayout(newLayout);
    }, 600);
  };

  useEffect(() => {
    return () => {
      if (saveTimerRef.current) {
        clearTimeout(saveTimerRef.current);
        saveTimerRef.current = null;
      }
      if (pendingLayoutRef.current !== undefined && workspaceInfo) {
        void persistLayout(pendingLayoutRef.current);
      }
    };
  }, [workspaceInfo, legacyLayoutKey]);

  useEffect(() => {
    if (saveNotice) {
      const timer = setTimeout(() => setSaveNotice(null), 2500);
      return () => clearTimeout(timer);
    }
  }, [saveNotice]);

  const seatedStudentIds = useMemo(() => {
    if (!layout) return new Set<number>();
    return new Set<number>(Object.values(layout.seats));
  }, [layout]);

  const unseatedStudents = useMemo(() => {
    return students.filter((s) => !seatedStudentIds.has(s.rkId));
  }, [students, seatedStudentIds]);

  const filteredUnseatedStudents = useMemo(() => {
    return unseatedStudents.filter(
      (s) =>
        s.fullName.toLowerCase().includes(searchQuery.toLowerCase()) ||
        s.studentCode.toLowerCase().includes(searchQuery.toLowerCase())
    );
  }, [unseatedStudents, searchQuery]);

  const handleApplyTemplate = () => {
    const tpl = templates.find((t) => t.id === selectedTemplateId);
    if (!tpl) { alert('Vui lòng chọn sơ đồ mẫu.'); return; }
    const newLayout: SeatingLayout = {
      rows: tpl.rows,
      cols: tpl.cols,
      boardPosition: tpl.boardPosition,
      lockedSeats: [...tpl.lockedSeats],
      seats: {},
    };
    saveLayout(newLayout);
  };

  const handleApplyCustom = () => {
    const newLayout: SeatingLayout = {
      rows: customRows,
      cols: customCols,
      boardPosition: customBoard,
      lockedSeats: [],
      seats: {},
    };
    saveLayout(newLayout);
  };

  const handleDragStart = (e: React.DragEvent, source: string) => {
    e.dataTransfer.setData('text/plain', source);
  };

  const handleDragOver = (e: React.DragEvent, cellKey: string) => {
    e.preventDefault();
    setDragOverCell(cellKey);
  };

  const handleDragLeave = () => setDragOverCell(null);

  const handleDrop = (e: React.DragEvent, targetRow: number, targetCol: number) => {
    e.preventDefault();
    setDragOverCell(null);
    if (!layout) return;
    const source = e.dataTransfer.getData('text/plain');
    if (!source) return;
    const targetKey = `${targetRow},${targetCol}`;
    if (layout.lockedSeats.includes(targetKey)) return;
    const newSeats = { ...layout.seats };
    const targetStudentId = newSeats[targetKey];

    if (source.startsWith('unseated:')) {
      const studentId = Number(source.replace('unseated:', ''));
      newSeats[targetKey] = studentId;
      Object.keys(newSeats).forEach((key) => {
        if (key !== targetKey && newSeats[key] === studentId) delete newSeats[key];
      });
    } else if (source.startsWith('cell:')) {
      const sourceKey = source.replace('cell:', '');
      const studentId = newSeats[sourceKey];
      if (!studentId) return;
      if (targetStudentId) {
        newSeats[targetKey] = studentId;
        newSeats[sourceKey] = targetStudentId;
      } else {
        newSeats[targetKey] = studentId;
        delete newSeats[sourceKey];
      }
    }
    saveLayout({ ...layout, seats: newSeats });
  };

  const handleUnseat = (cellKey: string) => {
    if (!layout) return;
    const newSeats = { ...layout.seats };
    delete newSeats[cellKey];
    saveLayout({ ...layout, seats: newSeats });
  };

  const handleAutoAssign = () => {
    if (!layout) return;
    const emptyCells: string[] = [];
    for (let r = 0; r < layout.rows; r++) {
      for (let c = 0; c < layout.cols; c++) {
        const key = `${r},${c}`;
        if (!layout.lockedSeats.includes(key) && !layout.seats[key]) emptyCells.push(key);
      }
    }
    if (unseatedStudents.length > emptyCells.length) {
      alert(`Không đủ chỗ ngồi cho tất cả học viên! Số học viên chưa có chỗ: ${unseatedStudents.length}, Số chỗ trống khả dụng: ${emptyCells.length}. Thiếu ${unseatedStudents.length - emptyCells.length} chỗ.`);
    }
    const shuffledStudents = [...unseatedStudents].sort(() => Math.random() - 0.5);
    const newSeats = { ...layout.seats };
    const assignCount = Math.min(shuffledStudents.length, emptyCells.length);
    for (let i = 0; i < assignCount; i++) {
      newSeats[emptyCells[i]] = shuffledStudents[i].rkId;
    }
    saveLayout({ ...layout, seats: newSeats });
  };

  const handleApplyResize = () => {
    if (!layout) return;
    const newRows = Math.max(1, Math.min(editRows, 15));
    const newCols = Math.max(1, Math.min(editCols, 20));
    const newSeats: Record<string, number> = {};
    const newLocked: string[] = [];
    Object.entries(layout.seats).forEach(([key, rkId]) => {
      const [r, c] = key.split(',').map(Number);
      if (r < newRows && c < newCols) newSeats[key] = rkId;
    });
    layout.lockedSeats.forEach((key) => {
      const [r, c] = key.split(',').map(Number);
      if (r < newRows && c < newCols) newLocked.push(key);
    });
    saveLayout({
      rows: newRows,
      cols: newCols,
      boardPosition: editBoardPos,
      lockedSeats: newLocked,
      seats: newSeats,
    });
  };

  const handleClearAllSeats = () => {
    if (!layout) return;
    if (confirm('Bạn có chắc chắn muốn giải tán tất cả chỗ ngồi?')) {
      saveLayout({ ...layout, seats: {} });
    }
  };

  const handleResetLayout = () => {
    if (confirm('Lưu ý: Xóa sơ đồ sẽ xóa toàn bộ vị trí chỗ ngồi hiện tại. Bạn có chắc chắn muốn thực hiện?')) {
      saveLayout(null);
      setIsEditingStructure(false);
    }
  };

  const handleToggleCellLock = (r: number, c: number) => {
    if (!layout) return;
    const key = `${r},${c}`;
    let newLocked = [...layout.lockedSeats];
    let newSeats = { ...layout.seats };
    if (newLocked.includes(key)) {
      newLocked = newLocked.filter((k) => k !== key);
    } else {
      newLocked.push(key);
      delete newSeats[key];
    }
    saveLayout({ ...layout, lockedSeats: newLocked, seats: newSeats });
  };

  // ── Board label ──────────────────────────────────────────────────────────────

  const BoardLabel = ({ vertical = false }: { vertical?: boolean }) => (
    <div className={`wsc-board-label${vertical ? ' wsc-board-label--vert' : ''}`}>
      <IconBoard size={13} />
      <span>BẢNG GIẢNG ĐƯỜNG</span>
    </div>
  );

  // ── Seating grid ─────────────────────────────────────────────────────────────

  const renderSeatingGrid = () => {
    if (!layout) return null;
    const gridItems = [];
    for (let r = 0; r < layout.rows; r++) {
      for (let c = 0; c < layout.cols; c++) {
        const key = `${r},${c}`;
        const isLocked = layout.lockedSeats.includes(key);
        const studentId = layout.seats[key];
        const student = studentId ? students.find((s) => s.rkId === studentId) : null;
        const isOnline = student ? onlineIds.includes(student.rkId) : false;
        const isHovered = dragOverCell === key;

        let cellCls = 'wsc-grid-cell';
        if (isLocked) cellCls += ' wsc-cell--locked';
        else if (isHovered) cellCls += ' wsc-cell--dragover';
        else if (student) cellCls += isOnline ? ' wsc-cell--online' : ' wsc-cell--occupied';
        if (isEditingStructure) cellCls += ' wsc-cell--editing';

        gridItems.push(
          <div
            key={key}
            onDragOver={(e) => !isLocked && handleDragOver(e, key)}
            onDragLeave={handleDragLeave}
            onDrop={(e) => !isLocked && handleDrop(e, r, c)}
            onClick={() => isEditingStructure && handleToggleCellLock(r, c)}
            className={cellCls}
            draggable={!!student && !isEditingStructure}
            onDragStart={(e) => student && handleDragStart(e, `cell:${key}`)}
          >
            {isLocked ? (
              <div className="wsc-cell-locked-inner">
                <IconLock size={14} />
                <span className="wsc-cell-locked-label">Khóa</span>
              </div>
            ) : student ? (
              <div
                className="wsc-seat-card"
                onClick={() => { if (!isEditingStructure && onStudentClick) onStudentClick(student.rkId); }}
              >
                {!isEditingStructure && (
                  <button
                    type="button"
                    className="wsc-unseat-btn"
                    onClick={(e) => { e.stopPropagation(); handleUnseat(key); }}
                    title="Bỏ chỗ ngồi"
                  >
                    <IconX size={9} />
                  </button>
                )}
                <StudentAvatar fullName={student.fullName} avatar={student.avatar} isOnline={isOnline} size={40} />
                <span className="wsc-seat-name">{student.fullName}</span>
                <span className="wsc-seat-code">{student.studentCode}</span>
                {!isEditingStructure && <StudentOnlineBadge isOnline={isOnline} size="sm" />}
                {student.paperTitle && (
                  <span className="wsc-seat-paper">
                    <IconFileText size={10} />
                    {student.paperTitle}
                  </span>
                )}
              </div>
            ) : (
              <div className="wsc-cell-empty">
                <span className="wsc-cell-coord">H{r + 1}-C{c + 1}</span>
                <span className="wsc-cell-empty-label">Trống</span>
              </div>
            )}
          </div>
        );
      }
    }

    return (
      <div className="wsc-grid-wrap">
        {layout.boardPosition === 'top' && <BoardLabel />}
        <div className="wsc-grid-row-wrap">
          {layout.boardPosition === 'left' && <BoardLabel vertical />}
          <div
            className="wsc-grid-board"
            style={{ gridTemplateColumns: `repeat(${layout.cols}, minmax(100px, 1fr))` }}
          >
            {gridItems}
          </div>
          {layout.boardPosition === 'right' && <BoardLabel vertical />}
        </div>
        {layout.boardPosition === 'bottom' && <BoardLabel />}
      </div>
    );
  };

  // ── Render ────────────────────────────────────────────────────────────────────

  return (
    <div className="wsc-root">

      {/* ── Empty / Setup state ─────────────────────────────────────────────── */}
      {!layout ? (
        <div className="wsc-setup-state">
          <div className="wsc-setup-icon-wrap">
            <IconChair size={34} />
          </div>
          <h2 className="wsc-setup-heading">Chưa thiết lập sơ đồ chỗ ngồi</h2>
          <p className="wsc-setup-desc">
            Thiết lập nhanh từ mẫu lớp học có sẵn hoặc tạo tự do kích thước mong muốn để xếp vị trí cho sinh viên.
          </p>

          {/* Mode switcher */}
          <div className="wsc-seg" role="group" aria-label="Kiểu thiết lập">
            <button
              type="button"
              className={`wsc-seg-btn${setupMode === 'template' ? ' wsc-seg-btn--active' : ''}`}
              onClick={() => setSetupMode('template')}
            >
              <IconTemplate size={13} />
              <span>Từ sơ đồ mẫu</span>
            </button>
            <button
              type="button"
              className={`wsc-seg-btn${setupMode === 'custom' ? ' wsc-seg-btn--active' : ''}`}
              onClick={() => setSetupMode('custom')}
            >
              <IconSliders size={13} />
              <span>Tạo tự do</span>
            </button>
          </div>

          {/* Setup panels */}
          <div className="wsc-setup-panels">
            {setupMode === 'template' ? (
              <div className="wsc-setup-panel">
                <select
                  className="select-filter"
                  style={{ width: '100%' }}
                  value={selectedTemplateId}
                  onChange={(e) => setSelectedTemplateId(e.target.value)}
                >
                  <option value="">— Chọn sơ đồ mẫu —</option>
                  {templates.map((t) => (
                    <option key={t.id} value={t.id}>{t.name} ({t.rows}×{t.cols})</option>
                  ))}
                </select>
                <button className="btn btn-primary btn-sm wsc-setup-apply-btn" onClick={handleApplyTemplate}>
                  <IconCheck size={13} />
                  Áp dụng mẫu
                </button>
              </div>
            ) : (
              <div className="wsc-setup-panel">
                <div className="wsc-custom-fields">
                  <div className="wsc-field-group">
                    <label className="wsc-field-label">Hàng</label>
                    <input
                      type="number"
                      min={1} max={10}
                      className="search-input"
                      style={{ width: '70px' }}
                      value={customRows}
                      onChange={(e) => setCustomRows(Math.max(1, Number(e.target.value)))}
                    />
                  </div>
                  <div className="wsc-field-group">
                    <label className="wsc-field-label">Cột</label>
                    <input
                      type="number"
                      min={1} max={15}
                      className="search-input"
                      style={{ width: '70px' }}
                      value={customCols}
                      onChange={(e) => setCustomCols(Math.max(1, Number(e.target.value)))}
                    />
                  </div>
                  <div className="wsc-field-group">
                    <label className="wsc-field-label">Vị trí bảng</label>
                    <select
                      className="select-filter"
                      value={customBoard}
                      onChange={(e) => setCustomBoard(e.target.value as 'top' | 'bottom' | 'left' | 'right')}
                    >
                      <option value="top">Trên (Top)</option>
                      <option value="bottom">Dưới (Bottom)</option>
                      <option value="left">Trái (Left)</option>
                      <option value="right">Phải (Right)</option>
                    </select>
                  </div>
                </div>
                <button className="btn btn-primary btn-sm wsc-setup-apply-btn" onClick={handleApplyCustom}>
                  <IconCheck size={13} />
                  Tạo sơ đồ trống
                </button>
              </div>
            )}
          </div>
        </div>
      ) : (

        /* ── Active workspace ──────────────────────────────────────────────── */
        <div className={`wsc-workspace-grid${viewMode === 'list' ? ' wsc-workspace-grid--list' : ''}`}>

          {/* Left: main content */}
          <div className="wsc-workspace-main">

            {/* Toolbar */}
            <div className="wsc-toolbar">
              <div className="wsc-toolbar-left">
                {/* View-mode segmented control */}
                <div className="wsc-seg" role="group" aria-label="Chế độ xem">
                  <button
                    type="button"
                    className={`wsc-seg-btn${viewMode === 'grid' ? ' wsc-seg-btn--active' : ''}`}
                    onClick={() => setViewMode('grid')}
                  >
                    <IconGrid size={13} />
                    <span>Sơ đồ</span>
                  </button>
                  <button
                    type="button"
                    className={`wsc-seg-btn${viewMode === 'list' ? ' wsc-seg-btn--active' : ''}`}
                    onClick={() => setViewMode('list')}
                  >
                    <IconList size={13} />
                    <span>Danh sách</span>
                  </button>
                </div>

                {viewMode === 'grid' && (
                  <>
                    <button className="btn btn-primary btn-sm wsc-toolbar-btn" onClick={handleAutoAssign}>
                      <IconZap size={12} />
                      Xếp ngẫu nhiên
                    </button>
                    <button className="btn btn-secondary btn-sm wsc-toolbar-btn" onClick={handleClearAllSeats}>
                      <IconTrash size={12} />
                      Giải tán
                    </button>
                  </>
                )}
              </div>

              {viewMode === 'grid' && (
                <div className="wsc-toolbar-right">
                  <button
                    className={`btn btn-sm wsc-toolbar-btn${isEditingStructure ? ' btn-primary' : ' btn-secondary'}`}
                    onClick={() => {
                      if (!isEditingStructure && layout) {
                        setEditRows(layout.rows);
                        setEditCols(layout.cols);
                        setEditBoardPos(layout.boardPosition);
                      }
                      setIsEditingStructure(!isEditingStructure);
                    }}
                  >
                    {isEditingStructure ? <IconCheck size={12} /> : <IconSettings size={12} />}
                    {isEditingStructure ? 'Xong' : 'Sửa sơ đồ'}
                  </button>
                  <button
                    className="btn btn-secondary btn-sm wsc-toolbar-btn wsc-reset-btn"
                    onClick={handleResetLayout}
                  >
                    <IconRefresh size={12} />
                    Reset
                  </button>
                </div>
              )}
            </div>

            {/* Edit-structure banner */}
            {viewMode === 'grid' && isEditingStructure && (
              <div className="wsc-edit-banner">
                <span className="wsc-edit-banner-hint">
                  <IconSettings size={13} />
                  Chế độ chỉnh sửa: Click vào ô để khóa / mở vị trí. Chỉnh kích thước bên dưới.
                </span>
                <div className="wsc-edit-fields">
                  <label className="wsc-field-label">Hàng</label>
                  <input type="number" min={1} max={15} value={editRows} onChange={(e) => setEditRows(Math.max(1, Math.min(15, Number(e.target.value))))} className="search-input wsc-edit-num" />
                  <label className="wsc-field-label">Cột</label>
                  <input type="number" min={1} max={20} value={editCols} onChange={(e) => setEditCols(Math.max(1, Math.min(20, Number(e.target.value))))} className="search-input wsc-edit-num" />
                  <label className="wsc-field-label">Bảng</label>
                  <select value={editBoardPos} onChange={(e) => setEditBoardPos(e.target.value as 'top' | 'bottom' | 'left' | 'right')} className="select-filter wsc-edit-select">
                    <option value="top">Top</option>
                    <option value="bottom">Bottom</option>
                    <option value="left">Left</option>
                    <option value="right">Right</option>
                  </select>
                  <button className="btn btn-primary btn-sm" onClick={handleApplyResize}>
                    <IconCheck size={12} />
                    Áp dụng
                  </button>
                </div>
              </div>
            )}

            {/* Grid or list content */}
            {viewMode === 'grid' ? (
              <div className="wsc-grid-scroll">{renderSeatingGrid()}</div>
            ) : (
              <div className="wsc-list-wrap">
                <div className="wsc-list-search-wrap">
                  <IconSearch size={14} />
                  <input
                    type="search"
                    placeholder="Tìm sinh viên..."
                    className="search-input wsc-list-search"
                    value={listSearchQuery}
                    onChange={(e) => setListSearchQuery(e.target.value)}
                  />
                </div>
                <div className="attendance-table-scroll table-wrapper wsc-list-table-wrap">
                  {filteredListStudents.length === 0 ? (
                    <div className="wsc-list-empty">
                      <IconSearch size={28} />
                      <span>Không tìm thấy sinh viên nào.</span>
                    </div>
                  ) : (
                    <table className="data-table" style={{ width: '100%', borderCollapse: 'collapse' }}>
                      <thead>
                        <tr>
                          <th className="wsc-th">Sinh viên</th>
                          <th className="wsc-th">Mã SV</th>
                          {hasPaperColumn && <th className="wsc-th">Gói đề</th>}
                          <th className="wsc-th">Vị trí</th>
                          <th className="wsc-th">Trạng thái</th>
                          <th className="wsc-th wsc-th--right">Thao tác</th>
                        </tr>
                      </thead>
                      <tbody>
                        {filteredListStudents.map((s) => {
                          const isOnline = onlineIds.includes(s.rkId);
                          const seatLabel = studentSeats[s.rkId] || 'Chưa xếp chỗ';
                          return (
                            <tr key={s.rkId} className="wsc-list-row">
                              <td className="wsc-td">
                                <div className="wsc-td-student">
                                  <StudentAvatar fullName={s.fullName} avatar={s.avatar} isOnline={isOnline} size={28} />
                                  <span className="wsc-td-name">{s.fullName}</span>
                                </div>
                              </td>
                              <td className="wsc-td"><code>{s.studentCode}</code></td>
                              {hasPaperColumn && <td className="wsc-td">{s.paperTitle || '—'}</td>}
                              <td className="wsc-td">
                                <span className={`badge ${studentSeats[s.rkId] ? 'badge-info' : 'badge-muted'}`} style={{ fontSize: '0.7rem' }}>{seatLabel}</span>
                              </td>
                              <td className="wsc-td"><StudentOnlineBadge isOnline={isOnline} size="md" /></td>
                              <td className="wsc-td wsc-td--right">
                                <button type="button" className="btn btn-primary btn-sm" style={{ padding: '0.2rem 0.6rem', fontSize: '0.72rem' }} onClick={() => onStudentClick && onStudentClick(s.rkId)}>Giám sát</button>
                              </td>
                            </tr>
                          );
                        })}
                      </tbody>
                    </table>
                  )}
                </div>
              </div>
            )}
          </div>

          {/* Right: unseated sidebar */}
          {viewMode === 'grid' && (
            <div className="wsc-sidebar">
              <div className="wsc-sidebar-header">
                <span className="wsc-sidebar-title">Chưa vào chỗ</span>
                <span className="wsc-unseated-badge">{unseatedStudents.length} SV</span>
              </div>
              <p className="wsc-sidebar-hint">Kéo thả vào vị trí trống trên sơ đồ.</p>
              <div className="wsc-sidebar-search-wrap">
                <IconSearch size={13} />
                <input
                  type="search"
                  placeholder="Tìm tên, mã sinh viên..."
                  className="search-input wsc-sidebar-search"
                  value={searchQuery}
                  onChange={(e) => setSearchQuery(e.target.value)}
                />
              </div>
              <div className="wsc-unseated-list">
                {filteredUnseatedStudents.length === 0 ? (
                  <div className="wsc-unseated-empty">Không tìm thấy sinh viên.</div>
                ) : (
                  filteredUnseatedStudents.map((s) => {
                    const isOnline = onlineIds.includes(s.rkId);
                    return (
                      <div
                        key={s.rkId}
                        draggable
                        onDragStart={(e) => handleDragStart(e, `unseated:${s.rkId}`)}
                        onClick={() => onStudentClick && onStudentClick(s.rkId)}
                        className="wsc-unseated-card"
                      >
                        <StudentAvatar fullName={s.fullName} avatar={s.avatar} isOnline={isOnline} size={32} />
                        <div className="wsc-unseated-info">
                          <span className="wsc-unseated-name">{s.fullName}</span>
                          <span className="wsc-unseated-code">
                            {s.studentCode}{s.paperTitle && <> · <IconFileText size={10} /> {s.paperTitle}</>}
                          </span>
                          <StudentOnlineBadge isOnline={isOnline} size="sm" />
                        </div>
                      </div>
                    );
                  })
                )}
              </div>
            </div>
          )}
        </div>
      )}

      {/* ── Save toast ──────────────────────────────────────────────────────── */}
      {saveNotice && (
        <div className={`wsc-toast${saveNoticeKind === 'error' ? ' wsc-toast--error' : ' wsc-toast--success'}`}>
          {saveNoticeKind === 'error'
            ? <IconX size={14} />
            : <IconCheck size={14} />}
          <span>{saveNotice}</span>
        </div>
      )}

      {/* ── Scoped styles ───────────────────────────────────────────────────── */}
      <style>{`
        /* ── Root layout ─────────────────────────────────────────── */
        .wsc-root {
          display: flex;
          flex-direction: column;
          gap: 1rem;
          flex: 1;
          min-height: 0;
          height: 100%;
          overflow: hidden;
        }

        /* ── Setup / empty state ─────────────────────────────────── */
        .wsc-setup-state {
          display: flex;
          flex-direction: column;
          align-items: center;
          gap: 0.7rem;
          padding: 2rem 1.25rem 2.25rem;
        }
        .wsc-setup-icon-wrap {
          color: var(--text-muted, #9ca3af);
          display: flex;
          align-items: center;
          justify-content: center;
          width: 64px;
          height: 64px;
          background: var(--bg-subtle, #f0f3f7);
          border: 1px solid var(--border-color, #e4e9f0);
          border-radius: 14px;
          margin-bottom: 0.15rem;
        }
        .wsc-setup-heading {
          font-size: 1.05rem;
          font-weight: 700;
          color: var(--text-primary);
          margin: 0;
        }
        .wsc-setup-desc {
          color: var(--text-secondary);
          font-size: 0.85rem;
          text-align: center;
          max-width: 420px;
          margin: 0 0 0.3rem;
          line-height: 1.5;
        }
        .wsc-setup-panels {
          width: 100%;
          max-width: 380px;
          margin-top: 0.25rem;
        }
        .wsc-setup-panel {
          display: flex;
          flex-direction: column;
          gap: 0.6rem;
          padding: 1rem;
          background: var(--bg-card, #fff);
          border: 1px solid var(--border-color, #e4e9f0);
          border-radius: var(--radius-md, 10px);
        }
        .wsc-setup-apply-btn {
          display: inline-flex;
          align-items: center;
          gap: 0.35rem;
          align-self: flex-end;
        }
        .wsc-custom-fields {
          display: flex;
          flex-wrap: wrap;
          gap: 0.75rem 1rem;
          align-items: flex-end;
        }
        .wsc-field-group {
          display: flex;
          flex-direction: column;
          gap: 3px;
        }
        .wsc-field-label {
          font-size: 0.72rem;
          font-weight: 600;
          color: var(--text-muted, #9ca3af);
          text-transform: uppercase;
          letter-spacing: 0.03em;
        }

        /* ── Segmented controls ──────────────────────────────────── */
        .wsc-seg {
          display: inline-flex;
          align-items: center;
          gap: 2px;
          padding: 3px;
          background: var(--bg-subtle, #f0f3f7);
          border: 1px solid var(--border-color, #e4e9f0);
          border-radius: 9px;
          flex-shrink: 0;
        }
        .wsc-seg-btn {
          display: inline-flex;
          align-items: center;
          justify-content: center;
          gap: 0.3rem;
          border: none;
          background: transparent;
          color: var(--text-secondary, #6b7280);
          font-size: 0.78rem;
          font-weight: 500;
          padding: 0.3rem 0.7rem;
          line-height: 1;
          border-radius: 6px;
          cursor: pointer;
          white-space: nowrap;
          transition: background 0.15s, color 0.15s, box-shadow 0.15s;
        }
        .wsc-seg-btn svg { flex-shrink: 0; opacity: 0.85; }
        .wsc-seg-btn:hover:not(.wsc-seg-btn--active) {
          color: var(--text-primary, #1a2332);
          background: rgba(255,255,255,0.65);
        }
        .wsc-seg-btn--active {
          background: #fff;
          color: var(--accent, #bb2126);
          box-shadow: 0 1px 2px rgba(26,35,50,0.08), 0 0 0 1px rgba(187,33,38,0.12);
        }
        .wsc-seg-btn--active svg { opacity: 1; }

        /* ── Workspace layout ────────────────────────────────────── */
        .wsc-workspace-grid {
          display: grid;
          grid-template-columns: 1fr 268px;
          gap: 1rem;
          flex: 1;
          min-height: 0;
          overflow: hidden;
        }
        .wsc-workspace-grid--list {
          grid-template-columns: 1fr;
        }
        .wsc-workspace-main {
          display: flex;
          flex-direction: column;
          gap: 0.65rem;
          flex: 1;
          min-height: 0;
          overflow: hidden;
        }

        /* ── Toolbar ─────────────────────────────────────────────── */
        .wsc-toolbar {
          display: flex;
          justify-content: space-between;
          align-items: center;
          flex-wrap: wrap;
          gap: 8px;
          flex-shrink: 0;
        }
        .wsc-toolbar-left,
        .wsc-toolbar-right {
          display: flex;
          align-items: center;
          gap: 6px;
        }
        .wsc-toolbar-btn {
          display: inline-flex;
          align-items: center;
          gap: 0.3rem;
          padding: 0.28rem 0.65rem !important;
          font-size: 0.75rem !important;
        }
        .wsc-reset-btn {
          border-color: #fca5a5 !important;
          color: var(--danger, #dc2626) !important;
        }
        .wsc-reset-btn:hover {
          background: #fef2f2 !important;
        }

        /* ── Edit-structure banner ───────────────────────────────── */
        .wsc-edit-banner {
          background: #fffbeb;
          border: 1px solid #fde68a;
          padding: 0.55rem 0.9rem;
          border-radius: 8px;
          display: flex;
          flex-direction: column;
          gap: 0.45rem;
          flex-shrink: 0;
        }
        .wsc-edit-banner-hint {
          display: flex;
          align-items: center;
          gap: 5px;
          color: #92400e;
          font-size: 0.77rem;
          font-weight: 600;
        }
        .wsc-edit-fields {
          display: flex;
          flex-wrap: wrap;
          align-items: center;
          gap: 6px;
        }
        .wsc-edit-num {
          width: 56px !important;
          padding: 0.2rem 0.4rem !important;
          font-size: 0.75rem !important;
        }
        .wsc-edit-select {
          padding: 0.2rem 0.4rem !important;
          font-size: 0.75rem !important;
        }
        .wsc-edit-fields .wsc-field-label { color: #92400e; }

        /* ── Grid scroll area ────────────────────────────────────── */
        .wsc-grid-scroll {
          flex: 1;
          min-height: 0;
          overflow: auto;
        }
        .wsc-grid-wrap {
          display: flex;
          flex-direction: column;
          gap: 0.65rem;
          flex: 1;
          min-height: 0;
        }
        .wsc-grid-row-wrap {
          display: flex;
          align-items: stretch;
          gap: 0.65rem;
          flex: 1;
          min-height: 0;
        }
        .wsc-grid-board {
          display: grid;
          gap: 8px;
          flex: 1;
          padding: 10px;
          background: var(--bg-app, #f5f7fa);
          border-radius: var(--radius-md, 10px);
          border: 1px solid var(--border-color, #e4e9f0);
          align-content: start;
          overflow: auto;
          min-height: 0;
        }

        /* ── Board label ─────────────────────────────────────────── */
        .wsc-board-label {
          display: flex;
          align-items: center;
          justify-content: center;
          gap: 6px;
          background: #374151;
          color: #fff;
          padding: 0.32rem 0.7rem;
          border-radius: 6px;
          font-size: 0.78rem;
          font-weight: 700;
          letter-spacing: 0.04em;
          align-self: center;
          width: 55%;
        }
        .wsc-board-label--vert {
          writing-mode: vertical-lr;
          text-orientation: mixed;
          width: auto;
          padding: 0.6rem 0.35rem;
          align-self: stretch;
          height: auto;
        }
        .wsc-board-label--vert span { margin-top: 4px; }

        /* ── Grid cells ──────────────────────────────────────────── */
        .wsc-grid-cell {
          min-height: 118px;
          border: 1px solid var(--border-color, #e4e9f0);
          border-radius: 10px;
          display: flex;
          flex-direction: column;
          justify-content: center;
          align-items: center;
          padding: 0.5rem 0.4rem;
          position: relative;
          transition: var(--transition, all 0.15s);
          background: #f9fafb;
          cursor: default;
        }
        .wsc-grid-cell.wsc-cell--editing {
          border: 1.5px dashed var(--border-color, #e4e9f0) !important;
          cursor: pointer;
        }
        .wsc-grid-cell.wsc-cell--locked {
          background: #e5e7eb;
          cursor: default;
        }
        .wsc-grid-cell.wsc-cell--dragover {
          border-color: var(--accent, #bb2126) !important;
          background: #fff0f0 !important;
          box-shadow: 0 0 0 2px rgba(187,33,38,0.15);
        }
        .wsc-grid-cell.wsc-cell--online {
          background: linear-gradient(180deg,#ecfdf5 0%,#ffffff 55%);
          cursor: grab;
        }
        .wsc-grid-cell.wsc-cell--occupied {
          background: linear-gradient(180deg,#f8fafc 0%,#ffffff 55%);
          cursor: grab;
        }

        /* ── Locked cell ─────────────────────────────────────────── */
        .wsc-cell-locked-inner {
          display: flex;
          flex-direction: column;
          align-items: center;
          gap: 4px;
          color: #9ca3af;
        }
        .wsc-cell-locked-label {
          font-size: 0.68rem;
          font-weight: 600;
          color: #9ca3af;
        }

        /* ── Occupied seat card ──────────────────────────────────── */
        .wsc-seat-card {
          display: flex;
          flex-direction: column;
          align-items: center;
          text-align: center;
          width: 100%;
          gap: 0.18rem;
        }
        .wsc-seat-card[style*="pointer"],
        .wsc-seat-card { cursor: default; }
        .wsc-unseat-btn {
          position: absolute;
          top: 4px;
          right: 4px;
          border: none;
          background: #fee2e2;
          color: var(--danger, #dc2626);
          width: 20px;
          height: 20px;
          border-radius: 50%;
          display: flex;
          align-items: center;
          justify-content: center;
          cursor: pointer;
          font-weight: 700;
          padding: 0;
          transition: background 0.15s;
        }
        .wsc-unseat-btn:hover { background: #fecaca; }
        .wsc-seat-name {
          font-size: 0.72rem;
          font-weight: 700;
          margin-top: 2px;
          display: -webkit-box;
          -webkit-line-clamp: 3;
          -webkit-box-orient: vertical;
          overflow: hidden;
          word-break: break-word;
          width: 100%;
          line-height: 1.25;
          max-height: 3.75em;
        }
        .wsc-seat-code {
          font-size: 0.67rem;
          color: var(--text-secondary);
          font-family: monospace;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
          width: 100%;
        }
        .wsc-seat-paper {
          display: inline-flex;
          align-items: center;
          gap: 3px;
          font-size: 0.64rem;
          background: var(--accent-light, #fef2f2);
          color: var(--accent, #bb2126);
          padding: 2px 6px;
          border-radius: 4px;
          margin-top: 1px;
          font-weight: 600;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
          max-width: 100%;
        }

        /* ── Empty cell ──────────────────────────────────────────── */
        .wsc-cell-empty {
          display: flex;
          flex-direction: column;
          align-items: center;
          opacity: 0.38;
          gap: 2px;
        }
        .wsc-cell-coord {
          font-size: 0.73rem;
          color: var(--text-muted);
          font-weight: 600;
        }
        .wsc-cell-empty-label {
          font-size: 0.67rem;
          color: var(--text-muted);
        }

        /* ── List view ───────────────────────────────────────────── */
        .wsc-list-wrap {
          display: flex;
          flex-direction: column;
          flex: 1;
          min-height: 0;
          gap: 8px;
        }
        .wsc-list-search-wrap {
          display: flex;
          align-items: center;
          gap: 6px;
          color: var(--text-muted);
          max-width: 320px;
        }
        .wsc-list-search {
          flex: 1;
          padding: 0.38rem 0.6rem !important;
          font-size: 0.84rem !important;
        }
        .wsc-list-table-wrap {
          flex: 1;
          overflow-y: auto;
          border: 1px solid var(--border-color);
          border-radius: var(--radius-sm, 6px);
        }
        .wsc-list-empty {
          display: flex;
          flex-direction: column;
          align-items: center;
          gap: 0.5rem;
          padding: 2.5rem 1rem;
          color: var(--text-muted);
          font-size: 0.85rem;
        }
        .wsc-th {
          padding: 0.5rem 0.8rem;
          background: var(--bg-subtle);
          font-weight: 700;
          font-size: 0.72rem;
          color: var(--text-muted);
          text-transform: uppercase;
          letter-spacing: 0.03em;
          text-align: left;
        }
        .wsc-th--right { text-align: right; }
        .wsc-td {
          padding: 0.5rem 0.8rem;
          font-size: 0.82rem;
          color: var(--text-primary);
        }
        .wsc-td--right { text-align: right; }
        .wsc-list-row { border-bottom: 1px solid var(--border-light, #f0f3f7); }
        .wsc-td-student {
          display: flex;
          align-items: center;
          gap: 0.5rem;
        }
        .wsc-td-name { font-weight: 600; }

        /* ── Sidebar ─────────────────────────────────────────────── */
        .wsc-sidebar {
          border-left: 1px solid var(--border-color, #e4e9f0);
          padding-left: 1.25rem;
          display: flex;
          flex-direction: column;
          gap: 0.6rem;
          overflow: hidden;
          flex: 1;
          min-height: 0;
        }
        .wsc-sidebar-header {
          display: flex;
          justify-content: space-between;
          align-items: center;
        }
        .wsc-sidebar-title {
          font-size: 0.9rem;
          font-weight: 700;
          color: var(--text-primary);
        }
        .wsc-unseated-badge {
          display: inline-flex;
          align-items: center;
          background: var(--accent-light, #fef2f2);
          color: var(--accent, #bb2126);
          font-size: 0.72rem;
          font-weight: 700;
          padding: 0.15rem 0.45rem;
          border-radius: 10px;
        }
        .wsc-sidebar-hint {
          margin: 0;
          color: var(--text-secondary);
          font-size: 0.77rem;
          margin-top: -0.2rem;
        }
        .wsc-sidebar-search-wrap {
          display: flex;
          align-items: center;
          gap: 5px;
          color: var(--text-muted);
        }
        .wsc-sidebar-search {
          flex: 1;
          padding: 0.38rem 0.55rem !important;
          font-size: 0.78rem !important;
        }
        .wsc-unseated-list {
          flex: 1;
          overflow-y: auto;
          display: flex;
          flex-direction: column;
          gap: 5px;
          padding-right: 3px;
          min-height: 160px;
        }
        .wsc-unseated-empty {
          text-align: center;
          padding: 1.5rem 0;
          color: var(--text-muted);
          font-size: 0.8rem;
        }
        .wsc-unseated-card {
          display: flex;
          align-items: center;
          gap: 0.45rem;
          padding: 0.45rem 0.55rem;
          border: 1px solid var(--border-color, #e4e9f0);
          border-radius: 9px;
          background: #fff;
          cursor: grab;
          transition: var(--transition, all 0.15s);
          box-shadow: var(--shadow-sm, 0 1px 3px rgba(0,0,0,0.06));
        }
        .wsc-unseated-card:hover {
          border-color: var(--accent, #bb2126);
          box-shadow: 0 2px 8px rgba(187,33,38,0.1);
        }
        .wsc-unseated-info {
          display: flex;
          flex-direction: column;
          overflow: hidden;
          flex: 1;
          min-width: 0;
          gap: 1px;
        }
        .wsc-unseated-name {
          font-size: 0.79rem;
          font-weight: 600;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
        }
        .wsc-unseated-code {
          font-size: 0.69rem;
          color: var(--text-secondary);
          font-family: monospace;
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
          display: inline-flex;
          align-items: center;
          gap: 3px;
        }

        /* ── Save toast ──────────────────────────────────────────── */
        .wsc-toast {
          position: fixed;
          bottom: 24px;
          right: 24px;
          padding: 0.6rem 1.1rem;
          border-radius: 8px;
          box-shadow: var(--shadow-lg, 0 4px 24px rgba(0,0,0,0.14));
          font-size: 0.84rem;
          font-weight: 600;
          z-index: 1000;
          display: flex;
          align-items: center;
          gap: 7px;
          max-width: min(420px, calc(100vw - 48px));
          color: #fff;
          animation: wsc-toast-in 0.2s ease;
        }
        .wsc-toast--success { background: #10b981; }
        .wsc-toast--error   { background: #ef4444; }
        @keyframes wsc-toast-in {
          from { opacity: 0; transform: translateY(8px); }
          to   { opacity: 1; transform: translateY(0); }
        }
      `}</style>
    </div>
  );
};
