diff --git a/reference/index.html b/reference/index.html
new file mode 100644
index 0000000..ca6d3ec
--- /dev/null
+++ b/reference/index.html
@@ -0,0 +1,250 @@
+
+
+
+
+
+ Twitch Panels Creator
+
+
+
+
+
+
+
+
+
+
+
+
+ Настройки текста
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Фоновое изображение
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Добавьте тексты для создания панелей
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/script.js b/reference/script.js
new file mode 100644
index 0000000..8955e59
--- /dev/null
+++ b/reference/script.js
@@ -0,0 +1,570 @@
+// State
+let texts = [];
+let panels = [];
+let currentPanelIndex = 0;
+let backgroundImage = null;
+let originalImage = null;
+let settings = {
+ fontSize: 18,
+ fontFamily: "Arial",
+ textColor: "#ffffff",
+ alignment: "left",
+ sidePadding: 10,
+ centerOffset: 0,
+ bgBrightness: 100,
+ bgContrast: 100,
+};
+
+// Crop state
+let cropBox = {
+ x: 0,
+ y: 0,
+ width: 0,
+ height: 0,
+};
+let isDragging = false;
+let isResizing = false;
+let resizeHandle = null;
+let dragStart = { x: 0, y: 0 };
+let cropBoxStart = { x: 0, y: 0, width: 0, height: 0 };
+
+// Initialize
+document.addEventListener("DOMContentLoaded", () => {
+ initializeTheme();
+ initializeEventListeners();
+ loadDefaultBackground();
+ addDefaultTexts();
+});
+
+// Theme Management
+function initializeTheme() {
+ const savedTheme = localStorage.getItem("theme") || "light";
+ document.documentElement.setAttribute("data-theme", savedTheme);
+}
+
+function toggleTheme() {
+ const currentTheme = document.documentElement.getAttribute("data-theme");
+ const newTheme = currentTheme === "light" ? "dark" : "light";
+ document.documentElement.setAttribute("data-theme", newTheme);
+ localStorage.setItem("theme", newTheme);
+}
+
+// Event Listeners
+function initializeEventListeners() {
+ // Theme toggle
+ document.getElementById("themeToggle").addEventListener("click", toggleTheme);
+
+ // Add text
+ document.getElementById("addTextBtn").addEventListener("click", addText);
+ document.getElementById("panelTextInput").addEventListener("keypress", (e) => {
+ if (e.key === "Enter") addText();
+ });
+
+ // Settings
+ document.getElementById("fontSize").addEventListener("input", (e) => {
+ settings.fontSize = parseInt(e.target.value);
+ document.getElementById("fontSizeValue").textContent = e.target.value;
+ updateAllPanels();
+ });
+
+ document.getElementById("fontFamily").addEventListener("change", (e) => {
+ settings.fontFamily = e.target.value;
+ updateAllPanels();
+ });
+
+ document.getElementById("textColor").addEventListener("input", (e) => {
+ settings.textColor = e.target.value;
+ document.getElementById("textColorValue").textContent = e.target.value;
+ updateAllPanels();
+ });
+
+ document.querySelectorAll(".align-btn").forEach((btn) => {
+ btn.addEventListener("click", (e) => {
+ document.querySelectorAll(".align-btn").forEach((b) => b.classList.remove("active"));
+ btn.classList.add("active");
+ settings.alignment = btn.dataset.align;
+ updateAllPanels();
+ });
+ });
+
+ document.getElementById("sidePadding").addEventListener("input", (e) => {
+ settings.sidePadding = parseInt(e.target.value);
+ document.getElementById("sidePaddingValue").textContent = e.target.value;
+ updateAllPanels();
+ });
+
+ document.getElementById("centerOffset").addEventListener("input", (e) => {
+ settings.centerOffset = parseInt(e.target.value);
+ document.getElementById("centerOffsetValue").textContent = e.target.value;
+ updateAllPanels();
+ });
+
+ // Background controls
+ document.getElementById("uploadBgBtn").addEventListener("click", () => {
+ document.getElementById("bgImageInput").click();
+ });
+
+ document.getElementById("bgImageInput").addEventListener("change", handleBackgroundUpload);
+
+ document.getElementById("bgBrightness").addEventListener("input", (e) => {
+ settings.bgBrightness = parseInt(e.target.value);
+ document.getElementById("bgBrightnessValue").textContent = e.target.value;
+ drawCropCanvas();
+ updateAllPanels();
+ });
+
+ document.getElementById("bgContrast").addEventListener("input", (e) => {
+ settings.bgContrast = parseInt(e.target.value);
+ document.getElementById("bgContrastValue").textContent = e.target.value;
+ drawCropCanvas();
+ updateAllPanels();
+ });
+
+ document.getElementById("resetCropBtn").addEventListener("click", resetCrop);
+
+ // Crop canvas events
+ const canvas = document.getElementById("cropCanvas");
+ canvas.addEventListener("mousedown", handleCropMouseDown);
+ canvas.addEventListener("mousemove", handleCropMouseMove);
+ canvas.addEventListener("mouseup", handleCropMouseUp);
+ canvas.addEventListener("mouseleave", handleCropMouseUp);
+
+ // Panel navigation
+ document.getElementById("prevPanel").addEventListener("click", () => {
+ if (currentPanelIndex > 0) {
+ currentPanelIndex--;
+ displayCurrentPanel();
+ }
+ });
+
+ document.getElementById("nextPanel").addEventListener("click", () => {
+ if (currentPanelIndex < panels.length - 1) {
+ currentPanelIndex++;
+ displayCurrentPanel();
+ }
+ });
+
+ document.getElementById("downloadCurrentBtn").addEventListener("click", downloadCurrentPanel);
+ document.getElementById("downloadAllBtn").addEventListener("click", downloadAllPanels);
+}
+
+// Load default background
+function loadDefaultBackground() {
+ const img = new Image();
+ img.crossOrigin = "anonymous";
+ img.onload = () => {
+ originalImage = img;
+ backgroundImage = img;
+ initializeCropBox();
+ drawCropCanvas();
+ updateAllPanels();
+ };
+ img.src = "https://images.unsplash.com/photo-1579546929518-9e396f3cc809?w=800&h=250&fit=crop";
+}
+
+// Add default texts
+function addDefaultTexts() {
+ const defaultTexts = ["links", "about me", "projects"];
+ defaultTexts.forEach((text) => {
+ texts.push({ id: Date.now() + Math.random(), text });
+ });
+ renderTexts();
+ updateAllPanels();
+}
+
+// Add text
+function addText() {
+ const input = document.getElementById("panelTextInput");
+ const text = input.value.trim();
+
+ if (!text) return;
+
+ texts.push({ id: Date.now(), text });
+ input.value = "";
+
+ renderTexts();
+ updateAllPanels();
+}
+
+// Render texts list
+function renderTexts() {
+ const container = document.getElementById("textsList");
+
+ if (texts.length === 0) {
+ container.innerHTML = `
+
+
+
Добавьте тексты
+
+ `;
+ return;
+ }
+
+ container.innerHTML = texts
+ .map(
+ (item) => `
+
+
+
+
+ `,
+ )
+ .join("");
+}
+
+// Update text
+window.updateText = function (id, newText) {
+ const item = texts.find((t) => t.id === id);
+ if (item) {
+ item.text = newText;
+ updateAllPanels();
+ }
+};
+
+// Delete text
+window.deleteText = function (id) {
+ texts = texts.filter((t) => t.id !== id);
+ renderTexts();
+ updateAllPanels();
+};
+// Handle background upload
+function handleBackgroundUpload(e) {
+ const file = e.target.files[0];
+ if (!file) return;
+
+ const reader = new FileReader();
+ reader.onload = (event) => {
+ const img = new Image();
+ img.onload = () => {
+ originalImage = img;
+ backgroundImage = img;
+ initializeCropBox();
+ drawCropCanvas();
+ updateAllPanels();
+ };
+ img.src = event.target.result;
+ };
+ reader.readAsDataURL(file);
+}
+
+// Initialize crop box
+function initializeCropBox() {
+ const canvas = document.getElementById("cropCanvas");
+ const container = document.getElementById("cropCanvasContainer");
+ const rect = container.getBoundingClientRect();
+
+ canvas.width = rect.width;
+ canvas.height = rect.height;
+
+ // Set crop box to full canvas initially
+ cropBox = {
+ x: 0,
+ y: 0,
+ width: canvas.width,
+ height: canvas.height,
+ };
+
+ updateCropBoxElement();
+ document.getElementById("cropBox").classList.add("active");
+}
+
+// Draw crop canvas
+function drawCropCanvas() {
+ const canvas = document.getElementById("cropCanvas");
+ const ctx = canvas.getContext("2d");
+
+ if (!originalImage) return;
+
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+ // Apply filters
+ ctx.filter = `brightness(${settings.bgBrightness}%) contrast(${settings.bgContrast}%)`;
+
+ // Draw image to fit canvas
+ const scale = Math.max(canvas.width / originalImage.width, canvas.height / originalImage.height);
+ const scaledWidth = originalImage.width * scale;
+ const scaledHeight = originalImage.height * scale;
+ const x = (canvas.width - scaledWidth) / 2;
+ const y = (canvas.height - scaledHeight) / 2;
+
+ ctx.drawImage(originalImage, x, y, scaledWidth, scaledHeight);
+ ctx.filter = "none";
+}
+
+// Update crop box element
+function updateCropBoxElement() {
+ const element = document.getElementById("cropBox");
+ element.style.left = cropBox.x + "px";
+ element.style.top = cropBox.y + "px";
+ element.style.width = cropBox.width + "px";
+ element.style.height = cropBox.height + "px";
+}
+
+// Crop mouse handlers
+function handleCropMouseDown(e) {
+ const rect = e.target.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+
+ // Check if clicking on a handle
+ const handles = document.querySelectorAll(".crop-handle");
+ let clickedHandle = null;
+
+ handles.forEach((handle) => {
+ const handleRect = handle.getBoundingClientRect();
+ const handleX = handleRect.left - rect.left + handleRect.width / 2;
+ const handleY = handleRect.top - rect.top + handleRect.height / 2;
+
+ if (Math.abs(x - handleX) < 10 && Math.abs(y - handleY) < 10) {
+ clickedHandle = handle.classList[1]; // Get handle class (nw, ne, etc.)
+ }
+ });
+
+ if (clickedHandle) {
+ isResizing = true;
+ resizeHandle = clickedHandle;
+ } else if (x >= cropBox.x && x <= cropBox.x + cropBox.width && y >= cropBox.y && y <= cropBox.y + cropBox.height) {
+ isDragging = true;
+ }
+
+ dragStart = { x, y };
+ cropBoxStart = { ...cropBox };
+}
+
+function handleCropMouseMove(e) {
+ if (!isDragging && !isResizing) return;
+
+ const rect = e.target.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+ const dx = x - dragStart.x;
+ const dy = y - dragStart.y;
+
+ if (isDragging) {
+ cropBox.x = Math.max(0, Math.min(cropBoxStart.x + dx, rect.width - cropBox.width));
+ cropBox.y = Math.max(0, Math.min(cropBoxStart.y + dy, rect.height - cropBox.height));
+ } else if (isResizing) {
+ const minSize = 50;
+
+ switch (resizeHandle) {
+ case "nw":
+ cropBox.x = Math.max(0, Math.min(cropBoxStart.x + dx, cropBoxStart.x + cropBoxStart.width - minSize));
+ cropBox.y = Math.max(0, Math.min(cropBoxStart.y + dy, cropBoxStart.y + cropBoxStart.height - minSize));
+ cropBox.width = cropBoxStart.width - (cropBox.x - cropBoxStart.x);
+ cropBox.height = cropBoxStart.height - (cropBox.y - cropBoxStart.y);
+ break;
+ case "ne":
+ cropBox.y = Math.max(0, Math.min(cropBoxStart.y + dy, cropBoxStart.y + cropBoxStart.height - minSize));
+ cropBox.width = Math.max(minSize, Math.min(cropBoxStart.width + dx, rect.width - cropBoxStart.x));
+ cropBox.height = cropBoxStart.height - (cropBox.y - cropBoxStart.y);
+ break;
+ case "sw":
+ cropBox.x = Math.max(0, Math.min(cropBoxStart.x + dx, cropBoxStart.x + cropBoxStart.width - minSize));
+ cropBox.width = cropBoxStart.width - (cropBox.x - cropBoxStart.x);
+ cropBox.height = Math.max(minSize, Math.min(cropBoxStart.height + dy, rect.height - cropBoxStart.y));
+ break;
+ case "se":
+ cropBox.width = Math.max(minSize, Math.min(cropBoxStart.width + dx, rect.width - cropBoxStart.x));
+ cropBox.height = Math.max(minSize, Math.min(cropBoxStart.height + dy, rect.height - cropBoxStart.y));
+ break;
+ case "n":
+ cropBox.y = Math.max(0, Math.min(cropBoxStart.y + dy, cropBoxStart.y + cropBoxStart.height - minSize));
+ cropBox.height = cropBoxStart.height - (cropBox.y - cropBoxStart.y);
+ break;
+ case "s":
+ cropBox.height = Math.max(minSize, Math.min(cropBoxStart.height + dy, rect.height - cropBoxStart.y));
+ break;
+ case "w":
+ cropBox.x = Math.max(0, Math.min(cropBoxStart.x + dx, cropBoxStart.x + cropBoxStart.width - minSize));
+ cropBox.width = cropBoxStart.width - (cropBox.x - cropBoxStart.x);
+ break;
+ case "e":
+ cropBox.width = Math.max(minSize, Math.min(cropBoxStart.width + dx, rect.width - cropBoxStart.x));
+ break;
+ }
+ }
+
+ updateCropBoxElement();
+}
+
+function handleCropMouseUp() {
+ if (isDragging || isResizing) {
+ applyCrop();
+ }
+ isDragging = false;
+ isResizing = false;
+ resizeHandle = null;
+}
+
+// Apply crop
+function applyCrop() {
+ if (!originalImage) return;
+
+ const canvas = document.getElementById("cropCanvas");
+ const tempCanvas = document.createElement("canvas");
+ const tempCtx = tempCanvas.getContext("2d");
+
+ // Calculate scale factor
+ const scale = Math.max(canvas.width / originalImage.width, canvas.height / originalImage.height);
+ const scaledWidth = originalImage.width * scale;
+ const scaledHeight = originalImage.height * scale;
+ const offsetX = (canvas.width - scaledWidth) / 2;
+ const offsetY = (canvas.height - scaledHeight) / 2;
+
+ // Calculate crop area in original image coordinates
+ const cropX = (cropBox.x - offsetX) / scale;
+ const cropY = (cropBox.y - offsetY) / scale;
+ const cropWidth = cropBox.width / scale;
+ const cropHeight = cropBox.height / scale;
+
+ tempCanvas.width = cropWidth;
+ tempCanvas.height = cropHeight;
+
+ tempCtx.drawImage(originalImage, cropX, cropY, cropWidth, cropHeight, 0, 0, cropWidth, cropHeight);
+
+ const img = new Image();
+ img.onload = () => {
+ backgroundImage = img;
+ updateAllPanels();
+ };
+ img.src = tempCanvas.toDataURL();
+}
+
+// Reset crop
+function resetCrop() {
+ loadDefaultBackground();
+}
+// Update all panels
+function updateAllPanels() {
+ panels = texts.map((item) => ({
+ id: item.id,
+ text: item.text,
+ }));
+
+ currentPanelIndex = Math.min(currentPanelIndex, Math.max(0, panels.length - 1));
+ displayCurrentPanel();
+ updatePanelNavigation();
+}
+
+// Display current panel
+function displayCurrentPanel() {
+ const container = document.getElementById("panelDisplay");
+
+ if (panels.length === 0) {
+ container.innerHTML = `
+
+
+
Добавьте тексты для создания панелей
+
+ `;
+ return;
+ }
+
+ const panel = panels[currentPanelIndex];
+ container.innerHTML = ``;
+
+ setTimeout(() => {
+ drawPanel(panel, "currentPanelCanvas");
+ }, 0);
+}
+
+// Update panel navigation
+function updatePanelNavigation() {
+ document.getElementById("panelCount").textContent = panels.length;
+ document.getElementById("panelIndicator").textContent =
+ panels.length > 0 ? `${currentPanelIndex + 1} / ${panels.length}` : "0 / 0";
+
+ document.getElementById("prevPanel").disabled = currentPanelIndex === 0 || panels.length === 0;
+ document.getElementById("nextPanel").disabled = currentPanelIndex >= panels.length - 1 || panels.length === 0;
+ document.getElementById("downloadCurrentBtn").disabled = panels.length === 0;
+ document.getElementById("downloadAllBtn").disabled = panels.length === 0;
+}
+
+// Draw panel
+function drawPanel(panel, canvasId) {
+ const canvas = document.getElementById(canvasId);
+ if (!canvas) return;
+
+ const ctx = canvas.getContext("2d");
+ canvas.width = 320;
+ canvas.height = 100;
+
+ // Draw background
+ if (backgroundImage) {
+ ctx.filter = `brightness(${settings.bgBrightness}%) contrast(${settings.bgContrast}%)`;
+
+ const scale = Math.max(canvas.width / backgroundImage.width, canvas.height / backgroundImage.height);
+ const scaledWidth = backgroundImage.width * scale;
+ const scaledHeight = backgroundImage.height * scale;
+ const x = (canvas.width - scaledWidth) / 2;
+ const y = (canvas.height - scaledHeight) / 2;
+
+ ctx.drawImage(backgroundImage, x, y, scaledWidth, scaledHeight);
+ ctx.filter = "none";
+ } else {
+ ctx.fillStyle = "#667eea";
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+ }
+
+ // Draw text
+ ctx.font = `${settings.fontSize}px ${settings.fontFamily}`;
+ ctx.fillStyle = settings.textColor;
+ ctx.textBaseline = "middle";
+
+ const text = panel.text;
+
+ let x;
+ if (settings.alignment === "left") {
+ x = settings.sidePadding;
+ ctx.textAlign = "left";
+ } else if (settings.alignment === "center") {
+ x = canvas.width / 2 + settings.centerOffset;
+ ctx.textAlign = "center";
+ } else {
+ x = canvas.width - settings.sidePadding;
+ ctx.textAlign = "right";
+ }
+
+ const y = canvas.height / 2;
+ ctx.fillText(text, x, y);
+}
+
+// Download current panel
+function downloadCurrentPanel() {
+ if (panels.length === 0) return;
+
+ const canvas = document.getElementById("currentPanelCanvas");
+ const panel = panels[currentPanelIndex];
+
+ if (canvas && panel) {
+ const link = document.createElement("a");
+ link.download = `${panel.text}.png`;
+ link.href = canvas.toDataURL();
+ link.click();
+ }
+}
+
+// Download all panels
+function downloadAllPanels() {
+ panels.forEach((panel, index) => {
+ setTimeout(() => {
+ const tempCanvas = document.createElement("canvas");
+ tempCanvas.id = `temp-canvas-${panel.id}`;
+ document.body.appendChild(tempCanvas);
+
+ drawPanel(panel, tempCanvas.id);
+
+ const link = document.createElement("a");
+ link.download = `${panel.text}.png`;
+ link.href = tempCanvas.toDataURL();
+ link.click();
+
+ document.body.removeChild(tempCanvas);
+ }, 100 * index);
+ });
+}
diff --git a/reference/styles.css b/reference/styles.css
new file mode 100644
index 0000000..13b8474
--- /dev/null
+++ b/reference/styles.css
@@ -0,0 +1,763 @@
+:root {
+ --bg-primary: #ffffff;
+ --bg-secondary: #fafafa;
+ --bg-card: #ffffff;
+ --bg-hover: #f5f5f5;
+
+ --text-primary: #1a1a1a;
+ --text-secondary: #666666;
+ --text-tertiary: #999999;
+
+ --border-color: #e5e5e5;
+ --border-hover: #d4d4d4;
+
+ --accent-primary: #6366f1;
+ --accent-hover: #4f46e5;
+ --accent-light: #eef2ff;
+
+ --danger: #ef4444;
+
+ --shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
+ --shadow-md: 0 2px 8px rgba(0, 0, 0, 0.1);
+
+ --radius: 8px;
+ --transition: all 0.15s ease;
+}
+
+[data-theme="dark"] {
+ --bg-primary: #0a0a0a;
+ --bg-secondary: #1a1a1a;
+ --bg-card: #1a1a1a;
+ --bg-hover: #2a2a2a;
+
+ --text-primary: #f5f5f5;
+ --text-secondary: #a3a3a3;
+ --text-tertiary: #737373;
+
+ --border-color: #2a2a2a;
+ --border-hover: #3a3a3a;
+
+ --accent-primary: #818cf8;
+ --accent-hover: #6366f1;
+ --accent-light: #312e81;
+
+ --shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
+ --shadow-md: 0 2px 8px rgba(0, 0, 0, 0.4);
+}
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
+ background: var(--bg-primary);
+ color: var(--text-primary);
+ min-height: 100vh;
+ padding: 16px;
+ transition: var(--transition);
+ line-height: 1.5;
+}
+
+.container {
+ max-width: 1400px;
+ margin: 0 auto;
+}
+
+/* Header */
+.header {
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ color: white;
+ padding: 16px 20px;
+ border-radius: var(--radius);
+ margin-bottom: 16px;
+}
+
+.header-content {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.header h1 {
+ font-size: 20px;
+ font-weight: 600;
+}
+
+.theme-toggle {
+ width: 36px;
+ height: 36px;
+ border-radius: 6px;
+ border: none;
+ background: rgba(255, 255, 255, 0.2);
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: var(--transition);
+ position: relative;
+}
+
+.theme-toggle:hover {
+ background: rgba(255, 255, 255, 0.3);
+}
+
+.theme-toggle svg {
+ width: 18px;
+ height: 18px;
+ position: absolute;
+ transition: var(--transition);
+}
+
+.sun-icon {
+ opacity: 1;
+ transform: rotate(0deg);
+}
+
+.moon-icon {
+ opacity: 0;
+ transform: rotate(90deg);
+}
+
+[data-theme="dark"] .sun-icon {
+ opacity: 0;
+ transform: rotate(90deg);
+}
+
+[data-theme="dark"] .moon-icon {
+ opacity: 1;
+ transform: rotate(0deg);
+}
+
+/* Main Grid */
+.main-grid {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: 16px;
+}
+
+@media (min-width: 1024px) {
+ .main-grid {
+ grid-template-columns: 1fr 1fr;
+ }
+}
+
+/* Card */
+.card {
+ background: var(--bg-card);
+ border: 1px solid var(--border-color);
+ border-radius: var(--radius);
+ padding: 16px;
+ margin-bottom: 16px;
+ transition: var(--transition);
+}
+
+.card-title {
+ font-size: 15px;
+ font-weight: 600;
+ color: var(--text-primary);
+ margin-bottom: 12px;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.card-header-row {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 12px;
+}
+
+/* Badge */
+.badge {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 20px;
+ height: 20px;
+ padding: 0 6px;
+ background: var(--accent-light);
+ color: var(--accent-primary);
+ border-radius: 10px;
+ font-size: 11px;
+ font-weight: 600;
+}
+
+/* Input Group */
+.input-group {
+ display: flex;
+ gap: 8px;
+ margin-bottom: 12px;
+}
+
+.text-input {
+ flex: 1;
+ padding: 10px 12px;
+ border: 1px solid var(--border-color);
+ border-radius: var(--radius);
+ font-size: 14px;
+ background: var(--bg-primary);
+ color: var(--text-primary);
+ transition: var(--transition);
+ font-family: inherit;
+}
+
+.text-input:focus {
+ outline: none;
+ border-color: var(--accent-primary);
+}
+
+.text-input::placeholder {
+ color: var(--text-tertiary);
+}
+
+/* Buttons */
+.btn {
+ padding: 10px 16px;
+ border: none;
+ border-radius: var(--radius);
+ font-size: 13px;
+ font-weight: 500;
+ cursor: pointer;
+ transition: var(--transition);
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ font-family: inherit;
+ white-space: nowrap;
+}
+
+.btn svg {
+ width: 16px;
+ height: 16px;
+}
+
+.btn-primary {
+ background: var(--accent-primary);
+ color: white;
+}
+
+.btn-primary:hover:not(:disabled) {
+ background: var(--accent-hover);
+}
+
+.btn-primary:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+
+.btn-secondary {
+ background: var(--bg-secondary);
+ color: var(--text-primary);
+ border: 1px solid var(--border-color);
+}
+
+.btn-secondary:hover {
+ background: var(--bg-hover);
+}
+
+.btn-outline {
+ background: transparent;
+ color: var(--text-secondary);
+ border: 1px solid var(--border-color);
+}
+
+.btn-outline:hover:not(:disabled) {
+ background: var(--bg-hover);
+ border-color: var(--accent-primary);
+ color: var(--accent-primary);
+}
+
+.btn-outline:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+
+.btn-delete {
+ background: var(--danger);
+ color: white;
+ padding: 6px 10px;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 14px;
+ font-weight: 600;
+ transition: var(--transition);
+ min-width: 32px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.btn-delete:hover {
+ background: #dc2626;
+}
+
+/* Texts List */
+.texts-list {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+
+.text-item {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 8px 10px;
+ background: var(--bg-secondary);
+ border: 1px solid var(--border-color);
+ border-radius: var(--radius);
+ transition: var(--transition);
+}
+
+.text-item:hover {
+ border-color: var(--border-hover);
+}
+
+.text-item input {
+ flex: 1;
+ padding: 6px 10px;
+ border: 1px solid var(--border-color);
+ border-radius: 4px;
+ font-size: 14px;
+ background: var(--bg-primary);
+ color: var(--text-primary);
+ transition: var(--transition);
+ font-family: inherit;
+}
+
+.text-item input:focus {
+ outline: none;
+ border-color: var(--accent-primary);
+}
+
+/* Settings */
+.settings-grid {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.setting-row {
+ display: grid;
+ grid-template-columns: 100px 1fr;
+ align-items: center;
+ gap: 12px;
+}
+
+.setting-label {
+ color: var(--text-secondary);
+ font-size: 13px;
+ font-weight: 500;
+}
+
+.setting-control {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+
+.slider {
+ flex: 1;
+ height: 4px;
+ border-radius: 2px;
+ background: var(--bg-secondary);
+ outline: none;
+ -webkit-appearance: none;
+ appearance: none;
+}
+
+.slider::-webkit-slider-thumb {
+ -webkit-appearance: none;
+ appearance: none;
+ width: 16px;
+ height: 16px;
+ border-radius: 50%;
+ background: var(--accent-primary);
+ cursor: pointer;
+ transition: var(--transition);
+}
+
+.slider::-webkit-slider-thumb:hover {
+ transform: scale(1.1);
+}
+
+.slider::-moz-range-thumb {
+ width: 16px;
+ height: 16px;
+ border-radius: 50%;
+ background: var(--accent-primary);
+ cursor: pointer;
+ border: none;
+ transition: var(--transition);
+}
+
+.slider::-moz-range-thumb:hover {
+ transform: scale(1.1);
+}
+
+.value-display {
+ color: var(--text-primary);
+ font-weight: 500;
+ min-width: 40px;
+ text-align: right;
+ font-size: 13px;
+ padding: 4px 8px;
+ background: var(--bg-secondary);
+ border-radius: 4px;
+}
+
+.select-input {
+ padding: 8px 10px;
+ border: 1px solid var(--border-color);
+ border-radius: var(--radius);
+ background: var(--bg-primary);
+ color: var(--text-primary);
+ font-size: 13px;
+ cursor: pointer;
+ transition: var(--transition);
+ font-family: inherit;
+ width: 100%;
+}
+
+.select-input:focus {
+ outline: none;
+ border-color: var(--accent-primary);
+}
+
+.color-input {
+ width: 40px;
+ height: 32px;
+ border: 1px solid var(--border-color);
+ border-radius: var(--radius);
+ cursor: pointer;
+ transition: var(--transition);
+ background: var(--bg-primary);
+}
+
+.color-input:hover {
+ border-color: var(--accent-primary);
+}
+
+.color-value {
+ font-family: 'Courier New', monospace;
+ font-size: 12px;
+ font-weight: 500;
+ color: var(--text-secondary);
+ padding: 4px 8px;
+ background: var(--bg-secondary);
+ border-radius: 4px;
+}
+
+.alignment-buttons {
+ display: flex;
+ gap: 6px;
+}
+
+.align-btn {
+ flex: 1;
+ padding: 8px;
+ border: 1px solid var(--border-color);
+ background: var(--bg-primary);
+ border-radius: var(--radius);
+ cursor: pointer;
+ transition: var(--transition);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.align-btn svg {
+ width: 16px;
+ height: 16px;
+ stroke: var(--text-secondary);
+ transition: var(--transition);
+}
+
+.align-btn:hover {
+ background: var(--bg-hover);
+ border-color: var(--accent-primary);
+}
+
+.align-btn:hover svg {
+ stroke: var(--accent-primary);
+}
+
+.align-btn.active {
+ background: var(--accent-primary);
+ border-color: var(--accent-primary);
+}
+
+.align-btn.active svg {
+ stroke: white;
+}
+
+/* Crop Editor */
+.crop-editor {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.crop-canvas-container {
+ position: relative;
+ width: 100%;
+ aspect-ratio: 16 / 5;
+ background: var(--bg-secondary);
+ border-radius: var(--radius);
+ overflow: hidden;
+ cursor: crosshair;
+}
+
+.crop-canvas {
+ width: 100%;
+ height: 100%;
+ display: block;
+}
+
+.crop-box {
+ position: absolute;
+ border: 2px solid var(--accent-primary);
+ box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.5);
+ cursor: move;
+ display: none;
+}
+
+.crop-box.active {
+ display: block;
+}
+
+.crop-handle {
+ position: absolute;
+ width: 10px;
+ height: 10px;
+ background: white;
+ border: 2px solid var(--accent-primary);
+ border-radius: 50%;
+}
+
+.crop-handle.nw {
+ top: -5px;
+ left: -5px;
+ cursor: nw-resize;
+}
+
+.crop-handle.ne {
+ top: -5px;
+ right: -5px;
+ cursor: ne-resize;
+}
+
+.crop-handle.sw {
+ bottom: -5px;
+ left: -5px;
+ cursor: sw-resize;
+}
+
+.crop-handle.se {
+ bottom: -5px;
+ right: -5px;
+ cursor: se-resize;
+}
+
+.crop-handle.n {
+ top: -5px;
+ left: 50%;
+ transform: translateX(-50%);
+ cursor: n-resize;
+}
+
+.crop-handle.s {
+ bottom: -5px;
+ left: 50%;
+ transform: translateX(-50%);
+ cursor: s-resize;
+}
+
+.crop-handle.w {
+ left: -5px;
+ top: 50%;
+ transform: translateY(-50%);
+ cursor: w-resize;
+}
+
+.crop-handle.e {
+ right: -5px;
+ top: 50%;
+ transform: translateY(-50%);
+ cursor: e-resize;
+}
+
+.crop-controls {
+ display: flex;
+ gap: 8px;
+ flex-wrap: wrap;
+}
+
+/* Panel Viewer */
+.panel-nav {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.nav-btn {
+ width: 32px;
+ height: 32px;
+ padding: 0;
+ border: 1px solid var(--border-color);
+ background: var(--bg-primary);
+ border-radius: var(--radius);
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: var(--transition);
+}
+
+.nav-btn:hover:not(:disabled) {
+ background: var(--bg-hover);
+ border-color: var(--accent-primary);
+}
+
+.nav-btn:hover:not(:disabled) svg {
+ stroke: var(--accent-primary);
+}
+
+.nav-btn:disabled {
+ opacity: 0.3;
+ cursor: not-allowed;
+}
+
+.nav-btn svg {
+ width: 16px;
+ height: 16px;
+ stroke: var(--text-secondary);
+}
+
+.panel-indicator {
+ font-size: 13px;
+ color: var(--text-secondary);
+ font-weight: 500;
+ min-width: 50px;
+ text-align: center;
+}
+
+.panel-viewer {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.panel-display {
+ background: var(--bg-secondary);
+ border-radius: var(--radius);
+ padding: 20px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ min-height: 150px;
+}
+
+.panel-canvas {
+ border-radius: var(--radius);
+ display: block;
+ max-width: 100%;
+ box-shadow: var(--shadow-md);
+}
+
+.panel-actions {
+ display: flex;
+ gap: 8px;
+}
+
+.panel-actions .btn {
+ flex: 1;
+ justify-content: center;
+}
+
+/* Empty State */
+.empty-state {
+ text-align: center;
+ padding: 32px 16px;
+ color: var(--text-tertiary);
+}
+
+.empty-state svg {
+ width: 48px;
+ height: 48px;
+ margin: 0 auto 12px;
+ opacity: 0.5;
+}
+
+.empty-state p {
+ font-size: 14px;
+}
+
+/* Responsive */
+@media (max-width: 768px) {
+ body {
+ padding: 12px;
+ }
+
+ .header {
+ padding: 12px 16px;
+ }
+
+ .header h1 {
+ font-size: 18px;
+ }
+
+ .setting-row {
+ grid-template-columns: 80px 1fr;
+ gap: 10px;
+ }
+
+ .crop-controls {
+ flex-direction: column;
+ }
+
+ .crop-controls .btn {
+ width: 100%;
+ justify-content: center;
+ }
+}
+
+/* Animations */
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ transform: translateY(4px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+.text-item {
+ animation: fadeIn 0.2s ease-out;
+}
+
+/* Scrollbar */
+::-webkit-scrollbar {
+ width: 8px;
+ height: 8px;
+}
+
+::-webkit-scrollbar-track {
+ background: var(--bg-secondary);
+}
+
+::-webkit-scrollbar-thumb {
+ background: var(--border-color);
+ border-radius: 4px;
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background: var(--border-hover);
+}