// Room layout canvas - Phase B.2.8b.
const ROOM_LAYOUT_EMBEDDED_APP_SHELL = new URLSearchParams(window.location.search).get("embed") === "shell";
const ROOM_DND = {
furnitureKind: "application/x-scrubstack-furniture-kind",
furnitureId: "application/x-scrubstack-furniture-id",
furnitureOffset: "application/x-scrubstack-furniture-offset",
itemId: "application/x-scrubstack-item-id",
};
const ROOM_FURNITURE = {
anesthesia_station: { label: "Anesthesia", icon: "A", w: 0.28, h: 0.13, bg: "#E3E8DE", bd: "#8DA18D", fg: "#3F523F", fixedLabel: "Default widget" },
nurses_workstation: { label: "Nurses Station", icon: "NS", w: 0.28, h: 0.13, bg: "#E3E8DE", bd: "#7A8E7B", fg: "#3F523F", fixedLabel: "Default widget" },
or_bed: { label: "OR bed", icon: "BED", w: 0.30, h: 0.14, bg: "#E8EBEA", bd: "#6E6962", fg: "#3A3833", paletteNote: "Optional; record removal reason" },
boom: { label: "Boom", icon: "BM", w: 0.16, h: 0.16, bg: "#E7EFE9", bd: "#789B86", fg: "#3F523F", paletteNote: "Optional equipment target" },
back_table: { label: "Back table", icon: "BT", glyph: "table_wheels", w: 0.24, h: 0.11, bg: "#FAF7F2", bd: "#C7765A", fg: "#7A3F2A" },
mayo_stand: { label: "Mayo", icon: "M", glyph: "mayo_stand", w: 0.10, h: 0.10, bg: "#F1DDD2", bd: "#C7765A", fg: "#7A3F2A" },
equipment_cart: { label: "Equip cart", icon: "EC", glyph: "equipment_cart", w: 0.14, h: 0.11, bg: "#DCE2E6", bd: "#6B7A85", fg: "#3A4651", paletteNote: "Optional equipment target" },
bovie_tower: { label: "Bovie", icon: "B", glyph: "bovie_pencil", w: 0.10, h: 0.13, bg: "#F4E6CC", bd: "#D9A14A", fg: "#7A5615" },
suction_tower: { label: "Suction", icon: "S", glyph: "suction_canister", w: 0.10, h: 0.13, bg: "#EEE7DA", bd: "#9A8C66", fg: "#5F563F" },
c_arm: { label: "C-arm", icon: "C", glyph: "xray", w: 0.18, h: 0.16, bg: "#E2E2DA", bd: "#6E6962", fg: "#3A3833" },
prep_station: { label: "Prep", icon: "P", glyph: "prep_stick", w: 0.16, h: 0.11, bg: "#F1DDD2", bd: "#A05F47", fg: "#7A3F2A" },
custom: { label: "Custom", icon: "+", w: 0.13, h: 0.10, bg: "#FAF7F2", bd: "#ABA59C", fg: "#3A3833", paletteNote: "GUDID lookup" },
};
const ROOM_PALETTE = [
"or_bed",
"boom",
"back_table",
"mayo_stand",
"equipment_cart",
"bovie_tower",
"suction_tower",
"c_arm",
"prep_station",
"custom",
];
const ROOM_DEFAULT_RULES = [
{
id: "esu",
label: "ESU",
defaultLabel: "ESU assumed in room",
reasonLabel: "Bovie pencil/tip listed",
accessoryPattern: /\b(bovie|cautery|electrosurgical)\b.*\b(pencil|tip|cord|pad|blade)\b|\b(pencil|tip)\b.*\b(bovie|cautery|electrosurgical)\b/i,
equipmentPattern: /\b(esu|electrosurgical unit|cautery generator|bovie generator|valleylab|force triad)\b/i,
targetKinds: ["boom", "equipment_cart", "bovie_tower"],
},
{
id: "suction",
label: "Suction",
defaultLabel: "Suction assumed in room",
reasonLabel: "Suction accessory listed",
accessoryPattern: /\b(yankauer|poole|suction tubing|suction tip|suction canister|suction liner)\b/i,
equipmentPattern: /\b(suction machine|suction pump|suction tower|suction regulator|wall suction)\b/i,
targetKinds: ["boom", "equipment_cart", "suction_tower"],
},
];
const ROOM_STORAGE_PREFIX = "scrubstack-room-layout";
const ROOM_SEED = [
{ furniture_kind: "anesthesia_station", zone_label: "anesthesia", position_x: 0.15, position_y: 0.30, rotation: 0, is_fixed: true, width_pct: 0.28, height_pct: 0.13, item_count: 0 },
{ furniture_kind: "nurses_workstation", zone_label: "nurses-station", position_x: 0.85, position_y: 0.30, rotation: 0, is_fixed: true, width_pct: 0.28, height_pct: 0.13, item_count: 0 },
];
function RoomLayoutView({ mobile = false, viewTabs = null }) {
const cardId = window.PREFCARD_CONFIG?.cardId || 3;
const compact = useRoomCompactLayout(mobile);
const [cardSnapshot] = React.useState(window.PREFCARD);
const [furniture, setFurniture] = React.useState(ROOM_SEED);
const [items, setItems] = React.useState([]);
const [assignments, setAssignments] = React.useState({});
const [selectedZone, setSelectedZone] = React.useState(null);
const [loadState, setLoadState] = React.useState({ phase: "loading", message: "" });
const [saveState, setSaveState] = React.useState({ phase: "idle", message: "" });
const [toast, setToast] = React.useState("");
const [layoutSide, setLayoutSide] = React.useState(() => readRoomSetting(cardId, "side", "right") || "right");
const [layoutNotes, setLayoutNotes] = React.useState(() => readRoomSetting(cardId, "notes", { bedRemovalReason: "" }) || { bedRemovalReason: "" });
React.useEffect(() => {
let alive = true;
fetch(window.prefcardApiPath(`/api/cards/${cardId}/room-layout`), {
credentials: "same-origin",
headers: { "Accept": "application/json" },
})
.then((response) => {
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
})
.then((payload) => {
if (!alive) return;
applyRoomPayload(payload, setFurniture, setItems, setAssignments);
setLoadState({ phase: "done", message: "" });
})
.catch((err) => {
if (!alive) return;
setItems(fallbackItems());
setLoadState({ phase: "error", message: err.message || "Room layout unavailable" });
});
return () => { alive = false; };
}, [cardId]);
const selectedFurniture = React.useMemo(
() => furniture.find((row) => row.zone_label === selectedZone) || null,
[furniture, selectedZone]
);
const itemCounts = React.useMemo(() => countAssignments(assignments), [assignments]);
const assignedItems = selectedFurniture ? itemsForZone(items, assignments, selectedFurniture.zone_label) : [];
const unassignedItems = React.useMemo(
() => items.filter((item) => !assignments[String(item.id)]),
[items, assignments]
);
const detailOpen = Boolean(selectedFurniture);
const bedPlaced = furniture.some((row) => row.furniture_kind === "or_bed");
const boomPlaced = furniture.some((row) => row.furniture_kind === "boom");
const cartPlaced = furniture.some((row) => row.furniture_kind === "equipment_cart");
const roomDefaults = React.useMemo(() => inferredRoomDefaults(items), [items]);
const highlightItemId = new URLSearchParams(window.location.search).get("highlight_item");
React.useEffect(() => {
writeRoomSetting(cardId, "side", layoutSide);
}, [cardId, layoutSide]);
React.useEffect(() => {
writeRoomSetting(cardId, "notes", layoutNotes);
}, [cardId, layoutNotes]);
function addFurniture(kind, position) {
const meta = ROOM_FURNITURE[kind];
const zoneLabel = nextZoneLabel(furniture, kind);
const row = {
furniture_kind: kind,
zone_label: zoneLabel,
position_x: position.x,
position_y: position.y,
rotation: 0,
is_fixed: false,
width_pct: meta.w,
height_pct: meta.h,
item_count: 0,
};
setFurniture((prev) => [...prev, row]);
setSelectedZone(zoneLabel);
setSaveState({ phase: "idle", message: "" });
}
function moveFurniture(zoneLabel, position) {
setFurniture((prev) => prev.map((row) => row.zone_label === zoneLabel ? {
...row,
position_x: position.x,
position_y: position.y,
} : row));
setSaveState({ phase: "idle", message: "" });
}
function rotateFurniture(zoneLabel, delta) {
setFurniture((prev) => prev.map((row) => row.zone_label === zoneLabel ? {
...row,
rotation: (Number(row.rotation || 0) + delta + 360) % 360,
} : row));
}
function deleteFurniture(zoneLabel) {
const row = furniture.find((candidate) => candidate.zone_label === zoneLabel);
if (!row || row.is_fixed) return;
setFurniture((prev) => prev.filter((candidate) => candidate.zone_label !== zoneLabel));
setAssignments((prev) => clearZone(prev, zoneLabel));
setSelectedZone(null);
}
function setBedRemovalReason(reason) {
setLayoutNotes((prev) => ({ ...prev, bedRemovalReason: reason }));
}
function assignItem(itemId, zoneLabel) {
setAssignments((prev) => ({ ...prev, [String(itemId)]: zoneLabel }));
setSelectedZone(zoneLabel);
setSaveState({ phase: "idle", message: "" });
}
function removeItem(itemId) {
setAssignments((prev) => ({ ...prev, [String(itemId)]: null }));
setSaveState({ phase: "idle", message: "" });
}
async function saveLayout() {
setSaveState({ phase: "saving", message: "" });
try {
const response = await fetch(window.prefcardApiPath(`/api/cards/${cardId}/room-layout`), {
method: "PUT",
credentials: "same-origin",
headers: { "Content-Type": "application/json", "Accept": "application/json" },
body: JSON.stringify({
furniture: furniture.map((row) => ({
zone_label: row.zone_label,
furniture_kind: row.furniture_kind,
position_x: Number(row.position_x),
position_y: Number(row.position_y),
rotation: Number(row.rotation || 0),
is_fixed: Boolean(row.is_fixed),
width_pct: Number(row.width_pct),
height_pct: Number(row.height_pct),
})),
item_zone_assignments: items.map((item) => ({
item_id: numericItemId(item.id),
zone_label: assignments[String(item.id)] || null,
})).filter((row) => Number.isFinite(row.item_id)),
}),
});
const payload = await response.json();
if (!response.ok) throw new Error(payload.detail || `HTTP ${response.status}`);
applyRoomPayload(payload, setFurniture, setItems, setAssignments);
setSaveState({ phase: "done", message: "" });
setToast("Layout saved");
setTimeout(() => setToast(""), 1400);
} catch (err) {
setSaveState({ phase: "error", message: err.message || "Save failed" });
}
}
return (
{!ROOM_LAYOUT_EMBEDDED_APP_SHELL && (mobile ?
:
)}
{viewTabs}
{saveState.phase === "error" &&
}
{loadState.phase === "error" &&
}
{!mobile && (
)}
setSelectedZone(null)}
onRotate={rotateFurniture}
onDelete={deleteFurniture}
onRemoveItem={removeItem}
onBedRemovalReasonChange={setBedRemovalReason}
/>
{toast &&
{toast}
}
);
}
function useRoomCompactLayout(mobile) {
const [compact, setCompact] = React.useState(() => !mobile && window.innerWidth <= 980);
React.useEffect(() => {
if (mobile) {
setCompact(false);
return undefined;
}
const media = window.matchMedia("(max-width: 980px)");
const update = () => setCompact(media.matches);
update();
media.addEventListener?.("change", update);
window.addEventListener("resize", update);
return () => {
media.removeEventListener?.("change", update);
window.removeEventListener("resize", update);
};
}, [mobile]);
return compact;
}
function RoomPageHeader({ card, mobile, loadState, saveState, onSave, side, onSideChange }) {
return (
Room layout
{card.fullName || card.name || "Preference Card"}
{card.maintainer && (
{card.maintainer}
)}
{loadState.phase === "loading" ? "loading" : "live"}
{!mobile && (
)}
Side
{["left", "right"].map((value) => {
const active = side === value;
return (
);
})}
{mobile &&
view only}
);
}
function FurniturePalette({
bedPlaced,
boomPlaced,
cartPlaced,
roomDefaults,
highlightItemId,
bedRemovalReason,
onBedRemovalReasonChange,
}) {
return (
);
}
function RoomOptionalSetup({ bedPlaced, boomPlaced, cartPlaced, roomDefaults, highlightItemId, reason, onReasonChange }) {
return (
Optional targets
{!bedPlaced && (
onReasonChange(event.target.value)}
placeholder="Reason: stretcher, inpatient bed..."
style={roomInputStyle}
/>
)}
);
}
function OptionalTargetStatus({ label, placed }) {
return (
{label}
{placed ? "placed" : "not placed"}
);
}
function RoomCanvas({ furniture, itemCounts, mobile, selectedZone, onSelect, onAddFurniture, onMoveFurniture, onAssignItem }) {
const canvasRef = React.useRef(null);
function dropOnCanvas(event) {
if (mobile) return;
event.preventDefault();
const rect = canvasRef.current.getBoundingClientRect();
const kind = event.dataTransfer.getData(ROOM_DND.furnitureKind);
const zoneLabel = event.dataTransfer.getData(ROOM_DND.furnitureId);
const offset = parseOffset(event.dataTransfer.getData(ROOM_DND.furnitureOffset));
if (kind) {
onAddFurniture(kind, pointFromEvent(event, rect));
return;
}
if (zoneLabel) {
const row = furniture.find((candidate) => candidate.zone_label === zoneLabel);
if (!row) return;
const x = (event.clientX - rect.left - offset.x + (row.width_pct * rect.width) / 2) / rect.width;
const y = (event.clientY - rect.top - offset.y + (row.height_pct * rect.height) / 2) / rect.height;
onMoveFurniture(zoneLabel, { x: clamp01(x), y: clamp01(y) });
}
}
return (
!mobile && event.preventDefault()}
onDrop={dropOnCanvas}
style={{
position: "relative",
width: mobile ? "100vw" : "min(100%, 1100px)",
aspectRatio: "4 / 3",
margin: mobile ? "0 calc(50% - 50vw)" : "0 auto",
border: "1px solid var(--ss-line)",
borderRadius: mobile ? 0 : 6,
backgroundColor: "var(--ss-cream)",
backgroundImage: "linear-gradient(rgba(122,142,123,0.11) 1px, transparent 1px), linear-gradient(90deg, rgba(122,142,123,0.11) 1px, transparent 1px)",
backgroundSize: mobile ? "28px 28px" : "34px 34px",
boxShadow: "var(--ss-shadow-card)",
overflow: "hidden",
}}
>
{furniture.map((row) => (
))}
);
}
function FurniturePiece({ row, count, mobile, selected, onSelect, onAssignItem }) {
const meta = ROOM_FURNITURE[row.furniture_kind] || ROOM_FURNITURE.custom;
const title = furnitureTitle(row, meta);
const subtitle = furnitureSubtitle(row, meta);
return (
);
}
function RoomRightPanel({
mobile,
compact,
selectedFurniture,
assignedItems,
unassignedItems,
allItems,
roomDefaults,
highlightItemId,
bedRemovalReason,
onClose,
onRotate,
onDelete,
onRemoveItem,
onBedRemovalReasonChange,
}) {
const [collapsed, setCollapsed] = React.useState(false);
if (selectedFurniture) {
const meta = ROOM_FURNITURE[selectedFurniture.furniture_kind] || ROOM_FURNITURE.custom;
const title = furnitureTitle(selectedFurniture, meta);
const needsBedReason = selectedFurniture.furniture_kind === "or_bed";
const deleteDisabled = selectedFurniture.is_fixed;
return (
);
}
return (
);
}
function RoomDetailControls({ selectedFurniture, meta, roomDefaults, bedRemovalReason, onBedRemovalReasonChange }) {
const defaultsForZone = roomDefaultsForFurniture(roomDefaults, selectedFurniture.furniture_kind);
if (selectedFurniture.furniture_kind === "boom" || selectedFurniture.furniture_kind === "equipment_cart") {
return (
Equipment target
Drag supplies onto this widget to assign equipment here.
);
}
if (selectedFurniture.furniture_kind === "custom") {
return (
);
}
if (selectedFurniture.furniture_kind === "or_bed") {
return (
);
}
if (defaultsForZone.length) {
return (
);
}
return null;
}
function RoomDefaultsList({ defaults, compact = false, highlightedSourceId = null }) {
const rowRefs = React.useRef({});
const [activeHighlight, setActiveHighlight] = React.useState(Boolean(highlightedSourceId));
React.useEffect(() => {
if (!highlightedSourceId) return undefined;
setActiveHighlight(true);
const node = rowRefs.current[String(highlightedSourceId)];
node?.scrollIntoView?.({ block: "center", behavior: "smooth" });
const timer = window.setTimeout(() => setActiveHighlight(false), 2200);
return () => window.clearTimeout(timer);
}, [highlightedSourceId]);
if (!defaults || !defaults.length) return null;
return (
{!compact &&
Room defaults
}
{defaults.map((entry) => {
const highlighted = highlightedSourceId && String(entry.sourceId) === String(highlightedSourceId) && activeHighlight;
return (
{
if (entry.sourceId != null) rowRefs.current[String(entry.sourceId)] = node;
}}
style={{
display: "grid",
gap: 2,
padding: compact ? "7px 8px" : "8px 9px",
borderRadius: 5,
border: highlighted ? "2px solid #E1CC9E" : "1px solid #C9D8CC",
background: highlighted ? "var(--ss-open-bg)" : "rgba(231,239,233,0.72)",
boxShadow: highlighted ? "0 0 0 4px rgba(225,204,158,0.35)" : "none",
transition: "box-shadow 180ms ease, background 180ms ease, border-color 180ms ease",
}}
>
{entry.defaultLabel}
{entry.reasonLabel}{entry.sourceName ? `: ${entry.sourceName}` : ""}
);
})}
);
}
function SupplyDragRow({ item, mobile, assigned }) {
return (
event.dataTransfer.setData(ROOM_DND.itemId, String(item.id))}
style={{
padding: "9px 10px",
border: "1px solid var(--ss-line-soft)",
borderRadius: 6,
background: assigned ? "var(--ss-cream)" : "var(--ss-warm-white)",
cursor: mobile ? "default" : "grab",
}}
>
);
}
function SupplyRow({ item, actionLabel, onAction, mobile }) {
return (
{!mobile && }
);
}
function SupplyText({ item }) {
const qty = (item.qty_open ?? item.expected ?? 1) + (item.qty_hold ?? 0);
return (
<>
{item.item_name || item.name || "Unnamed item"}
qty {qty}
{item.section && {item.section}}
{(item.vendor || item.mfg) && {item.vendor || item.mfg}}
>
);
}
function RoomMobileHeader({ card }) {
const maintainer = card?.maintainer || "Maintainer";
return (
);
}
function RoomKindIcon({ meta, small = false }) {
return (
{meta.glyph ? : meta.icon}
);
}
function RoomFurnitureGlyph({ kind, color, small }) {
if (kind === "table_wheels") {
const stroke = color || "currentColor";
return (
);
}
if (kind === "mayo_stand") {
const stroke = color || "currentColor";
return (
);
}
if (kind === "equipment_cart") {
const stroke = color || "currentColor";
return (
);
}
if (kind === "bovie_pencil") {
const stroke = color || "currentColor";
return (
);
}
if (kind === "suction_canister") {
const stroke = color || "currentColor";
return (
);
}
if (kind === "xray") {
const stroke = color || "currentColor";
return (
);
}
if (kind === "prep_stick") {
const stroke = color || "currentColor";
return (
);
}
return null;
}
function RoomBanner({ tone, message, onRetry }) {
const error = tone === "error";
return (
{message}
{onRetry && }
);
}
function EmptyPanel({ text }) {
return {text}
;
}
function applyRoomPayload(payload, setFurniture, setItems, setAssignments) {
const rows = (payload.room_layout || []).map((row) => ({
...row,
is_fixed: Boolean(row.is_fixed),
position_x: Number(row.position_x),
position_y: Number(row.position_y),
rotation: Number(row.rotation || 0),
width_pct: Number(row.width_pct || ROOM_FURNITURE[row.furniture_kind]?.w || 0.12),
height_pct: Number(row.height_pct || ROOM_FURNITURE[row.furniture_kind]?.h || 0.08),
}));
const flatItems = [];
const nextAssignments = {};
for (const [zone, zoneItems] of Object.entries(payload.items_by_zone || {})) {
for (const item of zoneItems || []) {
if (!flatItems.some((existing) => String(existing.id) === String(item.id))) flatItems.push(item);
if (zone !== "_unassigned") nextAssignments[String(item.id)] = zone;
}
}
setFurniture(rows.length ? rows : ROOM_SEED);
setItems(flatItems);
setAssignments(nextAssignments);
}
function fallbackItems() {
return (window.PREFCARD?.supplies || []).map((item, index) => ({
id: numericItemId(item.id) || index + 1,
item_name: item.name,
vendor: item.mfg,
qty_open: item.expected || 1,
qty_hold: 0,
section: item.phase,
}));
}
function countAssignments(assignments) {
return Object.values(assignments).reduce((acc, zone) => {
if (zone) acc[zone] = (acc[zone] || 0) + 1;
return acc;
}, {});
}
function inferredRoomDefaults(items) {
const searchableItems = items.map((item) => ({
id: item.id,
name: item.item_name || item.name || item.raw_text || "Card item",
text: itemSearchText(item),
}));
return ROOM_DEFAULT_RULES.flatMap((rule) => {
const explicitEquipment = searchableItems.some((item) => rule.equipmentPattern.test(item.text));
if (explicitEquipment) return [];
const source = searchableItems.find((item) => rule.accessoryPattern.test(item.text));
if (!source) return [];
return [{
id: rule.id,
sourceId: source.id,
label: rule.label,
defaultLabel: rule.defaultLabel,
reasonLabel: rule.reasonLabel,
sourceName: source.name,
targetKinds: rule.targetKinds,
}];
});
}
function roomDefaultsForFurniture(roomDefaults, kind) {
return (roomDefaults || []).filter((entry) => (entry.targetKinds || []).includes(kind));
}
function itemSearchText(item) {
return [
item.item_name,
item.name,
item.raw_text,
item.vendor,
item.mfg,
item.section,
].filter(Boolean).join(" ");
}
function furnitureTitle(row, meta) {
return meta.label;
}
function furnitureSubtitle(row, meta) {
if (row.is_fixed && meta.fixedLabel) return meta.fixedLabel;
if (row.furniture_kind === "boom") return "ESU / lap equipment";
if (row.furniture_kind === "equipment_cart") return "assigned supplies";
if (row.furniture_kind === "custom") return "GUDID lookup";
return row.zone_label;
}
function itemsForZone(items, assignments, zoneLabel) {
return items.filter((item) => assignments[String(item.id)] === zoneLabel);
}
function clearZone(assignments, zoneLabel) {
const next = { ...assignments };
for (const [id, zone] of Object.entries(next)) if (zone === zoneLabel) next[id] = null;
return next;
}
function nextZoneLabel(furniture, kind) {
const base = kind.replaceAll("_", "-");
const used = new Set(furniture.map((row) => row.zone_label));
let n = 1;
while (used.has(`${base}-${n}`)) n += 1;
return `${base}-${n}`;
}
function pointFromEvent(event, rect) {
return {
x: clamp01((event.clientX - rect.left) / rect.width),
y: clamp01((event.clientY - rect.top) / rect.height),
};
}
function parseOffset(raw) {
try { return JSON.parse(raw || "{}"); }
catch (_) { return { x: 0, y: 0 }; }
}
function clamp01(value) {
if (!Number.isFinite(value)) return 0.5;
return Math.max(0, Math.min(1, value));
}
function numericItemId(value) {
if (typeof value === "number") return value;
const match = String(value || "").match(/\d+/);
return match ? Number(match[0]) : NaN;
}
function roomStorageKey(cardId, name) {
return `${ROOM_STORAGE_PREFIX}:${cardId}:${name}`;
}
function readRoomSetting(cardId, name, fallback) {
try {
const raw = window.localStorage.getItem(roomStorageKey(cardId, name));
return raw ? JSON.parse(raw) : fallback;
} catch (_) {
return fallback;
}
}
function writeRoomSetting(cardId, name, value) {
try {
window.localStorage.setItem(roomStorageKey(cardId, name), JSON.stringify(value));
} catch (_) {
// Local prototype persistence is best-effort.
}
}
function roomDrawerStyle(mobile) {
if (mobile) {
return {
position: "fixed",
left: 12,
right: 12,
bottom: 12,
zIndex: 20,
maxHeight: "72vh",
overflow: "auto",
};
}
return {
position: "fixed",
top: 96,
right: 24,
zIndex: 20,
width: 340,
maxHeight: "calc(100vh - 120px)",
overflow: "auto",
};
}
const roomPanelStyle = {
background: "var(--ss-warm-white)",
border: "1px solid var(--ss-line)",
borderRadius: 6,
boxShadow: "var(--ss-shadow-card)",
padding: 14,
};
const roomGhostButton = {
padding: "6px 10px",
borderRadius: 5,
background: "transparent",
border: "1px solid var(--ss-line)",
color: "var(--ss-gray-900)",
fontSize: 12,
fontWeight: 500,
cursor: "pointer",
fontFamily: "var(--ss-sans)",
};
const roomPrimaryButton = {
padding: "7px 12px",
borderRadius: 5,
background: "var(--ss-ink)",
border: "1px solid var(--ss-ink)",
color: "var(--ss-cream)",
fontSize: 12.5,
fontWeight: 600,
cursor: "pointer",
fontFamily: "var(--ss-sans)",
};
const roomDangerButton = {
...roomGhostButton,
border: "1px solid #DAB5AC",
color: "var(--ss-match-reject)",
};
const roomInputStyle = {
width: "100%",
minWidth: 0,
boxSizing: "border-box",
border: "1px solid var(--ss-line)",
borderRadius: 5,
background: "var(--ss-cream)",
color: "var(--ss-ink)",
padding: "7px 9px",
fontSize: 12.5,
fontFamily: "var(--ss-sans)",
};
const roomDetailSectionStyle = {
marginTop: 14,
display: "grid",
gap: 8,
paddingTop: 14,
borderTop: "1px solid var(--ss-line-soft)",
};
const roomToastStyle = {
position: "fixed",
right: 24,
bottom: 24,
zIndex: 30,
padding: "10px 14px",
borderRadius: 6,
background: "var(--ss-match-verified-bg)",
border: "1px solid #B9D0BE",
color: "var(--ss-match-verified)",
boxShadow: "var(--ss-shadow-pop)",
fontSize: 13,
fontWeight: 600,
};
Object.assign(window, { RoomLayoutView });