/* ╔═══════════════════════════════════════════════════════════════╗
   ║  AgPen' Organizer — веб-панель. Стили и система тем.          ║
   ╚═══════════════════════════════════════════════════════════════╝

   Палитры перенесены один-в-один из десктопного клиента
   (clients/desktop/src/ui.rs, static CYBERPUNK/WIN95/WINXP/WIN11/FUSION).
   Роли переменных совпадают с полями struct Palette, чтобы правки цвета
   в одном клиенте можно было механически повторить в другом.

   Тема выбирается атрибутом data-theme="cyberpunk|win95|winxp|win11|fusion" на <html>.
   Селектор без тега [data-theme=...] нарочно: тот же атрибут на любом вложенном
   элементе (например .tp-swatch в js/theme-picker.js) локально переопределяет
   переменные внутри себя — так превью темы рисуется без переключения всей страницы.
   Масштаб интерфейса — CSS-свойством zoom на <html> (см. js/theme.js).           */

/* ── Cyberpunk (по умолчанию) ─────────────────────────────────── */
:root,
[data-theme="cyberpunk"] {
  --accent:          rgb(0, 220, 175);
  --accent2:         rgb(255, 50, 150);
  --bg-void:         rgb(0, 0, 0);
  --bg-panel:        rgb(0, 0, 0);
  --bg-widget:       rgb(0, 0, 0);
  --input-bg:        rgb(0, 0, 0);
  --text-main:       rgb(185, 255, 230);
  --text-dim:        rgb(75, 135, 105);
  --border-dim:      rgb(0, 70, 52);
  --warn:            rgb(255, 255, 0);
  --ok:              rgb(0, 255, 0);
  --selection-bg:    rgb(0, 75, 60);
  --inactive-border: rgb(0, 110, 80);
  --hover-bg:        rgb(0, 32, 25);
  --active-bg:       rgb(0, 58, 44);
  --open-bg:         rgb(0, 42, 32);
  --card-bg:         rgb(0, 0, 0);
  --card-local-bg:   rgb(0, 30, 40);
  --active-text:     rgb(255, 255, 255);
  --rounding: 2px;
  --shadow: 0 6px 26px rgba(0, 0, 0, .75);
  color-scheme: dark;
}

/* ── Windows 95 ───────────────────────────────────────────────── */
[data-theme="win95"] {
  --accent:          rgb(0, 0, 128);
  --accent2:         rgb(128, 0, 0);
  --bg-void:         rgb(0, 128, 128);
  --bg-panel:        rgb(192, 192, 192);
  --bg-widget:       rgb(212, 208, 200);
  --input-bg:        rgb(255, 255, 255);
  --text-main:       rgb(0, 0, 0);
  --text-dim:        rgb(70, 70, 70);
  --border-dim:      rgb(128, 128, 128);
  --warn:            rgb(160, 95, 0);
  --ok:              rgb(0, 110, 0);
  --selection-bg:    rgb(178, 180, 191);
  --inactive-border: rgb(100, 100, 100);
  --hover-bg:        rgb(224, 221, 214);
  --active-bg:       rgb(176, 176, 176);
  --open-bg:         rgb(200, 200, 200);
  --card-bg:         rgb(255, 255, 255);
  --card-local-bg:   rgb(225, 240, 250);
  --active-text:     rgb(0, 0, 0);
  --rounding: 0px;
  --shadow: 2px 2px 0 rgba(0, 0, 0, .45);
  color-scheme: light;
}

/* ── Windows XP ───────────────────────────────────────────────── */
[data-theme="winxp"] {
  --accent:          rgb(49, 106, 197);
  --accent2:         rgb(210, 105, 30);
  --bg-void:         rgb(93, 136, 218);
  --bg-panel:        rgb(236, 233, 216);
  --bg-widget:       rgb(245, 243, 231);
  --input-bg:        rgb(255, 255, 255);
  --text-main:       rgb(30, 30, 30);
  --text-dim:        rgb(105, 100, 90);
  --border-dim:      rgb(145, 155, 156);
  --warn:            rgb(175, 115, 0);
  --ok:              rgb(55, 135, 55);
  --selection-bg:    rgb(182, 205, 240);
  --inactive-border: rgb(172, 168, 153);
  --hover-bg:        rgb(252, 244, 220);
  --active-bg:       rgb(222, 215, 190);
  --open-bg:         rgb(240, 236, 222);
  --card-bg:         rgb(255, 255, 255);
  --card-local-bg:   rgb(224, 238, 255);
  --active-text:     rgb(0, 0, 0);
  --rounding: 3px;
  --shadow: 0 4px 14px rgba(0, 0, 0, .3);
  color-scheme: light;
}

/* ── Windows 11 ───────────────────────────────────────────────── */
[data-theme="win11"] {
  --accent:          rgb(0, 103, 192);
  --accent2:         rgb(196, 43, 28);
  --bg-void:         rgb(243, 243, 243);
  --bg-panel:        rgb(251, 251, 251);
  --bg-widget:       rgb(255, 255, 255);
  --input-bg:        rgb(255, 255, 255);
  --text-main:       rgb(28, 28, 28);
  --text-dim:        rgb(96, 96, 96);
  --border-dim:      rgb(224, 224, 224);
  --warn:            rgb(157, 93, 0);
  --ok:              rgb(15, 123, 15);
  --selection-bg:    rgb(204, 228, 247);
  --inactive-border: rgb(208, 208, 208);
  --hover-bg:        rgb(246, 246, 246);
  --active-bg:       rgb(238, 238, 238);
  --open-bg:         rgb(249, 249, 249);
  --card-bg:         rgb(255, 255, 255);
  --card-local-bg:   rgb(235, 244, 255);
  --active-text:     rgb(0, 0, 0);
  --rounding: 6px;
  --shadow: 0 8px 28px rgba(0, 0, 0, .12);
  color-scheme: light;
}

/* ── Fusion ───────────────────────────────────────────────────── */
[data-theme="fusion"] {
  --accent:          rgb(42, 130, 218);
  --accent2:         rgb(230, 120, 60);
  --bg-void:         rgb(37, 37, 37);
  --bg-panel:        rgb(53, 53, 53);
  --bg-widget:       rgb(66, 66, 66);
  --input-bg:        rgb(42, 42, 42);
  --text-main:       rgb(220, 220, 220);
  --text-dim:        rgb(150, 150, 150);
  --border-dim:      rgb(80, 80, 80);
  --warn:            rgb(230, 200, 80);
  --ok:              rgb(100, 200, 100);
  --selection-bg:    rgb(42, 90, 140);
  --inactive-border: rgb(100, 100, 100);
  --hover-bg:        rgb(70, 70, 70);
  --active-bg:       rgb(85, 85, 85);
  --open-bg:         rgb(60, 60, 60);
  --card-bg:         rgb(45, 45, 45);
  --card-local-bg:   rgb(40, 55, 70);
  --active-text:     rgb(255, 255, 255);
  --rounding: 2px;
  --shadow: 0 6px 22px rgba(0, 0, 0, .55);
  color-scheme: dark;
}

/* ── Claude ───────────────────────────────────────────────────── */
[data-theme="claude"] {
  --accent:          rgb(204, 120, 92);
  --accent2:         rgb(178, 74, 59);
  --bg-void:         rgb(246, 244, 235);
  --bg-panel:        rgb(255, 253, 246);
  --bg-widget:       rgb(240, 237, 225);
  --input-bg:        rgb(255, 255, 255);
  --text-main:       rgb(38, 35, 32);
  --text-dim:        rgb(120, 113, 104);
  --border-dim:      rgb(223, 216, 202);
  --warn:            rgb(180, 130, 40);
  --ok:              rgb(107, 142, 90);
  --selection-bg:    rgb(240, 220, 208);
  --inactive-border: rgb(205, 197, 182);
  --hover-bg:        rgb(238, 233, 220);
  --active-bg:       rgb(230, 223, 208);
  --open-bg:         rgb(243, 238, 227);
  --card-bg:         rgb(255, 255, 255);
  --card-local-bg:   rgb(250, 234, 224);
  --active-text:     rgb(30, 26, 22);
  --rounding: 10px;
  --shadow: 0 6px 20px rgba(60, 45, 30, .12);
  color-scheme: light;
}

/* ── Claude (тёмная) ──────────────────────────────────────────── */
[data-theme="claude-dark"] {
  --accent:          rgb(214, 138, 111);
  --accent2:         rgb(224, 106, 84);
  --bg-void:         rgb(28, 26, 24);
  --bg-panel:        rgb(38, 35, 32);
  --bg-widget:       rgb(48, 44, 40);
  --input-bg:        rgb(32, 29, 27);
  --text-main:       rgb(237, 233, 225);
  --text-dim:        rgb(150, 143, 133);
  --border-dim:      rgb(64, 58, 52);
  --warn:            rgb(214, 168, 90);
  --ok:              rgb(133, 173, 113);
  --selection-bg:    rgb(72, 45, 36);
  --inactive-border: rgb(80, 73, 65);
  --hover-bg:        rgb(46, 42, 38);
  --active-bg:       rgb(58, 52, 47);
  --open-bg:         rgb(40, 37, 34);
  --card-bg:         rgb(38, 35, 32);
  --card-local-bg:   rgb(58, 38, 32);
  --active-text:     rgb(255, 250, 245);
  --rounding: 10px;
  --shadow: 0 8px 26px rgba(0, 0, 0, .45);
  color-scheme: dark;
}

/* ── «Я попросил Клода сделать тему, и вот что вышло» ────────────
   Своя тема, без ограничений. Взял то, над чем в интернете шутят —
   что все ИИ-интерфейсы по умолчанию тянутся к фиолетовому градиенту —
   и сделал это осознанным выбором, а не багом.                    */
[data-theme="askclaude"] {
  --accent:          rgb(139, 92, 246);
  --accent2:         rgb(236, 72, 153);
  --bg-void:         rgb(13, 10, 24);
  --bg-panel:        rgb(20, 16, 35);
  --bg-widget:       rgb(28, 22, 48);
  --input-bg:        rgb(24, 19, 40);
  --text-main:       rgb(230, 225, 245);
  --text-dim:        rgb(150, 140, 175);
  --border-dim:      rgb(55, 45, 85);
  --warn:            rgb(250, 190, 80);
  --ok:              rgb(110, 230, 180);
  --selection-bg:    rgb(60, 40, 100);
  --inactive-border: rgb(80, 65, 120);
  --hover-bg:        rgb(35, 27, 58);
  --active-bg:       rgb(48, 36, 80);
  --open-bg:         rgb(30, 23, 50);
  --card-bg:         rgb(20, 16, 35);
  --card-local-bg:   rgb(45, 25, 60);
  --active-text:     rgb(255, 255, 255);
  --rounding: 10px;
  --shadow: 0 10px 34px rgba(139, 92, 246, .28);
  color-scheme: dark;
}

/* ── Dracula ─────────────────────────────────────────────────── */
[data-theme="dracula"] {
  --accent:          rgb(189, 147, 249);
  --accent2:         rgb(255, 121, 198);
  --bg-void:         rgb(30, 32, 42);
  --bg-panel:        rgb(40, 42, 54);
  --bg-widget:       rgb(55, 58, 75);
  --input-bg:        rgb(45, 47, 62);
  --text-main:       rgb(248, 248, 242);
  --text-dim:        rgb(130, 140, 175);
  --border-dim:      rgb(75, 80, 105);
  --warn:            rgb(255, 184, 108);
  --ok:              rgb(80, 250, 123);
  --selection-bg:    rgb(68, 71, 90);
  --inactive-border: rgb(90, 95, 120);
  --hover-bg:        rgb(50, 52, 68);
  --active-bg:       rgb(65, 68, 88);
  --open-bg:         rgb(55, 58, 75);
  --card-bg:         rgb(40, 42, 54);
  --card-local-bg:   rgb(55, 48, 75);
  --active-text:     rgb(248, 248, 242);
  --rounding: 4px;
  --shadow: 0 6px 24px rgba(0, 0, 0, .5);
  color-scheme: dark;
}

/* ── Гламур ─────────────────────────────────────────────────────
   «Розовый — это цвет настоящих мужиков». Бархатный тёмный фон,
   неоновый Hot Pink и золотые акценты. Брутальная гламурность. */
[data-theme="glamour"] {
  --accent:          rgb(255, 20, 147);
  --accent2:         rgb(255, 215, 0);
  --bg-void:         rgb(15, 5, 10);
  --bg-panel:        rgb(25, 10, 20);
  --bg-widget:       rgb(45, 15, 35);
  --input-bg:        rgb(10, 0, 5);
  --text-main:       rgb(255, 230, 240);
  --text-dim:        rgb(180, 110, 140);
  --border-dim:      rgb(100, 30, 60);
  --warn:            rgb(255, 105, 180);
  --ok:              rgb(0, 250, 154);
  --selection-bg:    rgb(80, 20, 50);
  --inactive-border: rgb(120, 40, 70);
  --hover-bg:        rgb(55, 15, 40);
  --active-bg:       rgb(75, 20, 55);
  --open-bg:         rgb(35, 10, 25);
  --card-bg:         rgb(25, 10, 20);
  --card-local-bg:   rgb(40, 15, 35);
  --active-text:     rgb(255, 255, 255);
  --rounding: 12px;
  --shadow: 0 10px 30px rgba(255, 20, 147, .3), 0 0 15px rgba(255, 215, 0, .15);
  color-scheme: dark;
}

/* ── Гламур (светлый) ──────────────────────────────────────────
   Дневной гламур: розовый зефир, золото и жёсткая мужская элегантность. */
[data-theme="glamour-light"] {
  --accent:          rgb(219, 0, 110);
  --accent2:         rgb(191, 132, 0);
  --bg-void:         rgb(255, 221, 237);
  --bg-panel:        rgb(255, 225, 237);
  --bg-widget:       rgb(255, 197, 226);
  --input-bg:        rgb(255, 255, 255);
  --text-main:       rgb(70, 20, 45);
  --text-dim:        rgb(160, 95, 130);
  --border-dim:      rgb(240, 180, 210);
  --warn:            rgb(184, 90, 0);
  --ok:              rgb(0, 150, 90);
  --selection-bg:    rgb(255, 182, 213);
  --inactive-border: rgb(220, 150, 185);
  --hover-bg:        rgb(255, 224, 238);
  --active-bg:       rgb(255, 205, 228);
  --open-bg:         rgb(255, 232, 243);
  --card-bg:         rgb(255, 250, 252);
  --card-local-bg:   rgb(255, 238, 246);
  --active-text:     rgb(70, 20, 45);
  --rounding: 12px;
  --shadow: 0 10px 30px rgba(219, 0, 110, .18), 0 0 18px rgba(212, 175, 55, .25);
  color-scheme: light;
}

/* ── CRT Terminal ────────────────────────────────────────────────
   Старый зелёный терминал: phosphor green, янтарные предупреждения,
   почти чёрный фон и лёгкое свечение. */
[data-theme="crt-terminal"] {
  --accent:          rgb(80, 255, 120);
  --accent2:         rgb(255, 190, 70);
  --bg-void:         rgb(3, 8, 5);
  --bg-panel:        rgb(7, 15, 9);
  --bg-widget:       rgb(11, 23, 14);
  --input-bg:        rgb(5, 12, 7);
  --text-main:       rgb(185, 255, 195);
  --text-dim:        rgb(85, 150, 95);
  --border-dim:      rgb(35, 85, 45);
  --warn:            rgb(255, 190, 70);
  --ok:              rgb(80, 255, 120);
  --selection-bg:    rgb(20, 90, 35);
  --inactive-border: rgb(45, 105, 55);
  --hover-bg:        rgb(13, 35, 18);
  --active-bg:       rgb(17, 55, 25);
  --open-bg:         rgb(10, 28, 14);
  --card-bg:         rgb(7, 15, 9);
  --card-local-bg:   rgb(8, 32, 16);
  --active-text:     rgb(225, 255, 230);
  --rounding: 2px;
  --shadow: 0 0 12px rgba(80, 255, 120, .12),
             0 6px 24px rgba(0, 0, 0, .7);
  color-scheme: dark;
}

/* ── Чёрная ───────────────────────────────────────────────────────
   Чистый OLED-чёрный: на таких экранах нулевой пиксель не светится
   вовсе. Монохром — акцент отличается от текста только яркостью. */
[data-theme="black"] {
  --accent:          rgb(255, 255, 255);
  --accent2:         rgb(170, 170, 170);
  --bg-void:         rgb(0, 0, 0);
  --bg-panel:        rgb(0, 0, 0);
  --bg-widget:       rgb(10, 10, 10);
  --input-bg:        rgb(0, 0, 0);
  --text-main:       rgb(235, 235, 235);
  --text-dim:        rgb(130, 130, 130);
  --border-dim:      rgb(55, 55, 55);
  --warn:            rgb(230, 200, 110);
  --ok:              rgb(140, 210, 150);
  --selection-bg:    rgb(48, 48, 48);
  --inactive-border: rgb(80, 80, 80);
  --hover-bg:        rgb(20, 20, 20);
  --active-bg:       rgb(36, 36, 36);
  --open-bg:         rgb(14, 14, 14);
  --card-bg:         rgb(0, 0, 0);
  --card-local-bg:   rgb(18, 18, 18);
  --active-text:     rgb(255, 255, 255);
  --rounding: 2px;
  --shadow: 0 6px 24px rgba(0, 0, 0, .9);
  color-scheme: dark;
}

/* ── Белая ────────────────────────────────────────────────────────
   Зеркало «Чёрной»: чистая бумага без единого цветного пятна. */
[data-theme="white"] {
  --accent:          rgb(0, 0, 0);
  --accent2:         rgb(90, 90, 90);
  --bg-void:         rgb(255, 255, 255);
  --bg-panel:        rgb(255, 255, 255);
  --bg-widget:       rgb(247, 247, 247);
  --input-bg:        rgb(255, 255, 255);
  --text-main:       rgb(20, 20, 20);
  --text-dim:        rgb(110, 110, 110);
  --border-dim:      rgb(205, 205, 205);
  --warn:            rgb(150, 100, 0);
  --ok:              rgb(30, 110, 45);
  --selection-bg:    rgb(220, 220, 220);
  --inactive-border: rgb(175, 175, 175);
  --hover-bg:        rgb(242, 242, 242);
  --active-bg:       rgb(230, 230, 230);
  --open-bg:         rgb(250, 250, 250);
  --card-bg:         rgb(255, 255, 255);
  --card-local-bg:   rgb(240, 240, 240);
  --active-text:     rgb(0, 0, 0);
  --rounding: 2px;
  --shadow: 0 4px 16px rgba(0, 0, 0, .1);
  color-scheme: light;
}

/* ── Nord ─────────────────────────────────────────────────────────
   Холодная арктическая палитра: приглушённый сине-серый. */
[data-theme="nord"] {
  --accent:          rgb(136, 192, 208);
  --accent2:         rgb(191, 97, 106);
  --bg-void:         rgb(38, 44, 56);
  --bg-panel:        rgb(46, 52, 64);
  --bg-widget:       rgb(59, 66, 82);
  --input-bg:        rgb(42, 48, 60);
  --text-main:       rgb(216, 222, 233);
  --text-dim:        rgb(143, 155, 175);
  --border-dim:      rgb(67, 76, 94);
  --warn:            rgb(235, 203, 139);
  --ok:              rgb(163, 190, 140);
  --selection-bg:    rgb(67, 76, 94);
  --inactive-border: rgb(86, 95, 114);
  --hover-bg:        rgb(52, 59, 73);
  --active-bg:       rgb(67, 76, 94);
  --open-bg:         rgb(48, 55, 68);
  --card-bg:         rgb(46, 52, 64);
  --card-local-bg:   rgb(56, 68, 82);
  --active-text:     rgb(236, 239, 244);
  --rounding: 5px;
  --shadow: 0 6px 22px rgba(0, 0, 0, .45);
  color-scheme: dark;
}

/* ── Solarized (тёмная) ───────────────────────────────────────── */
[data-theme="solarized-dark"] {
  --accent:          rgb(38, 139, 210);
  --accent2:         rgb(203, 75, 22);
  --bg-void:         rgb(0, 43, 54);
  --bg-panel:        rgb(7, 54, 66);
  --bg-widget:       rgb(14, 65, 78);
  --input-bg:        rgb(0, 38, 48);
  --text-main:       rgb(147, 161, 161);
  --text-dim:        rgb(101, 123, 131);
  --border-dim:      rgb(28, 79, 92);
  --warn:            rgb(181, 137, 0);
  --ok:              rgb(133, 153, 0);
  --selection-bg:    rgb(20, 75, 89);
  --inactive-border: rgb(45, 96, 108);
  --hover-bg:        rgb(10, 58, 70);
  --active-bg:       rgb(18, 72, 85);
  --open-bg:         rgb(6, 50, 61);
  --card-bg:         rgb(7, 54, 66);
  --card-local-bg:   rgb(12, 62, 74);
  --active-text:     rgb(253, 246, 227);
  --rounding: 3px;
  --shadow: 0 6px 22px rgba(0, 0, 0, .5);
  color-scheme: dark;
}

/* ── Solarized (светлая) ──────────────────────────────────────── */
[data-theme="solarized-light"] {
  --accent:          rgb(38, 139, 210);
  --accent2:         rgb(203, 75, 22);
  --bg-void:         rgb(238, 232, 213);
  --bg-panel:        rgb(253, 246, 227);
  --bg-widget:       rgb(245, 238, 219);
  --input-bg:        rgb(255, 252, 242);
  --text-main:       rgb(88, 110, 117);
  --text-dim:        rgb(131, 148, 150);
  --border-dim:      rgb(216, 208, 187);
  --warn:            rgb(181, 137, 0);
  --ok:              rgb(110, 128, 0);
  --selection-bg:    rgb(223, 214, 190);
  --inactive-border: rgb(200, 192, 172);
  --hover-bg:        rgb(245, 239, 221);
  --active-bg:       rgb(233, 226, 205);
  --open-bg:         rgb(249, 243, 226);
  --card-bg:         rgb(253, 246, 227);
  --card-local-bg:   rgb(238, 240, 222);
  --active-text:     rgb(7, 54, 66);
  --rounding: 3px;
  --shadow: 0 4px 16px rgba(101, 123, 131, .2);
  color-scheme: light;
}

/* ── Gruvbox ──────────────────────────────────────────────────────
   Тёплая ретро-палитра: горчица и терракот по кофейному фону. */
[data-theme="gruvbox"] {
  --accent:          rgb(250, 189, 47);
  --accent2:         rgb(251, 73, 52);
  --bg-void:         rgb(29, 32, 33);
  --bg-panel:        rgb(40, 40, 40);
  --bg-widget:       rgb(60, 56, 54);
  --input-bg:        rgb(32, 32, 32);
  --text-main:       rgb(235, 219, 178);
  --text-dim:        rgb(168, 153, 132);
  --border-dim:      rgb(80, 73, 69);
  --warn:            rgb(254, 128, 25);
  --ok:              rgb(184, 187, 38);
  --selection-bg:    rgb(80, 73, 69);
  --inactive-border: rgb(102, 92, 84);
  --hover-bg:        rgb(50, 48, 47);
  --active-bg:       rgb(68, 64, 60);
  --open-bg:         rgb(44, 42, 41);
  --card-bg:         rgb(40, 40, 40);
  --card-local-bg:   rgb(55, 52, 44);
  --active-text:     rgb(251, 241, 199);
  --rounding: 3px;
  --shadow: 0 6px 22px rgba(0, 0, 0, .55);
  color-scheme: dark;
}

/* ── Matrix ───────────────────────────────────────────────────────
   Зелёный люминофор P1: один цвет, только разная яркость. */
[data-theme="matrix"] {
  --accent:          rgb(0, 255, 65);
  --accent2:         rgb(0, 180, 45);
  --bg-void:         rgb(0, 0, 0);
  --bg-panel:        rgb(0, 8, 2);
  --bg-widget:       rgb(0, 16, 5);
  --input-bg:        rgb(0, 5, 1);
  --text-main:       rgb(120, 255, 150);
  --text-dim:        rgb(0, 150, 45);
  --border-dim:      rgb(0, 80, 25);
  --warn:            rgb(180, 255, 100);
  --ok:              rgb(0, 255, 65);
  --selection-bg:    rgb(0, 70, 22);
  --inactive-border: rgb(0, 110, 35);
  --hover-bg:        rgb(0, 24, 8);
  --active-bg:       rgb(0, 45, 15);
  --open-bg:         rgb(0, 18, 6);
  --card-bg:         rgb(0, 8, 2);
  --card-local-bg:   rgb(0, 28, 10);
  --active-text:     rgb(200, 255, 210);
  --rounding: 0px;
  --shadow: 0 0 14px rgba(0, 255, 65, .18), 0 6px 24px rgba(0, 0, 0, .8);
  color-scheme: dark;
}

/* ── Amber ────────────────────────────────────────────────────────
   Янтарный монитор 80-х — тот же принцип, что Matrix, другой люминофор. */
[data-theme="amber"] {
  --accent:          rgb(255, 176, 0);
  --accent2:         rgb(255, 120, 0);
  --bg-void:         rgb(10, 6, 0);
  --bg-panel:        rgb(18, 11, 0);
  --bg-widget:       rgb(28, 18, 2);
  --input-bg:        rgb(13, 8, 0);
  --text-main:       rgb(255, 200, 90);
  --text-dim:        rgb(170, 115, 20);
  --border-dim:      rgb(92, 60, 5);
  --warn:            rgb(255, 225, 120);
  --ok:              rgb(230, 190, 60);
  --selection-bg:    rgb(80, 50, 0);
  --inactive-border: rgb(120, 78, 8);
  --hover-bg:        rgb(35, 22, 2);
  --active-bg:       rgb(58, 37, 3);
  --open-bg:         rgb(26, 16, 1);
  --card-bg:         rgb(18, 11, 0);
  --card-local-bg:   rgb(40, 25, 2);
  --active-text:     rgb(255, 228, 160);
  --rounding: 0px;
  --shadow: 0 0 14px rgba(255, 176, 0, .15), 0 6px 24px rgba(0, 0, 0, .8);
  color-scheme: dark;
}

/* ── Сепия ────────────────────────────────────────────────────────
   Режим чтения: тёплая бумага, минимум контрастных пятен. */
[data-theme="sepia"] {
  --accent:          rgb(140, 90, 40);
  --accent2:         rgb(160, 70, 45);
  --bg-void:         rgb(240, 228, 205);
  --bg-panel:        rgb(248, 238, 219);
  --bg-widget:       rgb(236, 223, 199);
  --input-bg:        rgb(252, 245, 231);
  --text-main:       rgb(60, 48, 34);
  --text-dim:        rgb(133, 116, 92);
  --border-dim:      rgb(213, 197, 169);
  --warn:            rgb(165, 115, 20);
  --ok:              rgb(95, 120, 60);
  --selection-bg:    rgb(226, 210, 180);
  --inactive-border: rgb(196, 178, 148);
  --hover-bg:        rgb(240, 229, 208);
  --active-bg:       rgb(228, 214, 188);
  --open-bg:         rgb(245, 235, 216);
  --card-bg:         rgb(250, 242, 226);
  --card-local-bg:   rgb(240, 231, 206);
  --active-text:     rgb(45, 35, 24);
  --rounding: 4px;
  --shadow: 0 4px 16px rgba(90, 70, 45, .18);
  color-scheme: light;
}

/* ── СамГУ ────────────────────────────────────────────────────────
   Фирменные цвета университета: синь со страницы входа в ЛК, белые
   карточки нового кабинета и мятная подсветка «своего» — той самой,
   которой там помечены зачётка и согласование работ.                */
[data-theme="ssau"] {
  --accent:          rgb(23, 105, 199);
  --accent2:         rgb(224, 106, 55);
  --bg-void:         rgb(238, 243, 250);
  --bg-panel:        rgb(255, 255, 255);
  --bg-widget:       rgb(246, 249, 253);
  --input-bg:        rgb(233, 240, 250);
  --text-main:       rgb(26, 37, 54);
  --text-dim:        rgb(108, 124, 146);
  --border-dim:      rgb(213, 224, 238);
  --warn:            rgb(190, 120, 10);
  --ok:              rgb(24, 145, 105);
  --selection-bg:    rgb(206, 226, 250);
  --inactive-border: rgb(188, 204, 226);
  --hover-bg:        rgb(238, 245, 253);
  --active-bg:       rgb(219, 233, 250);
  --open-bg:         rgb(245, 249, 254);
  --card-bg:         rgb(255, 255, 255);
  --card-local-bg:   rgb(223, 241, 234);
  --active-text:     rgb(255, 255, 255);
  --rounding: 8px;
  --shadow: 0 6px 22px rgba(23, 60, 120, .14);
  color-scheme: light;
}

/* ═══════════ База ═══════════ */
* { box-sizing: border-box; }

/* Фон — только на html, не на body: у body своего быть не должно, иначе он,
   как обычный непозиционированный блок, перекрывает #fx-canvas (position:fixed;
   z-index:-1) — непозиционированное содержимое всегда рисуется поверх
   отрицательных z-index, независимо от самого значения z-index. */
html { background: var(--bg-void); }

body {
  margin: 0;
  color: var(--text-main);
  font-family: "Cascadia Code", "Consolas", ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 14px;
  line-height: 1.5;
  -webkit-text-size-adjust: 100%;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

::selection { background: var(--selection-bg); color: var(--active-text); }

.hidden { display: none !important; }
/* Дубликат ☰ в шапке нужен только там, где список превращается в шторку. */
.mobile-only { display: none; }
@media (max-width: 900px) { .mobile-only { display: inline-block; } }
.accent  { color: var(--accent); }
.accent2 { color: var(--accent2); }
.dim, .muted { color: var(--text-dim); }
.ok   { color: var(--ok); }
.warn { color: var(--warn); }
.muted { font-size: 11px; }
.mono { font-family: inherit; }
.strong { font-weight: 700; }
.nowrap { white-space: nowrap; }
.grow { flex: 1; }
.row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.col { display: flex; flex-direction: column; gap: 6px; }
.sp8  { height: 8px; }
.sp16 { height: 16px; }

/* ═══════════ Управляющие элементы ═══════════ */
button {
  font-family: inherit;
  font-size: 13px;
  cursor: pointer;
  background: var(--bg-widget);
  color: var(--accent);
  border: 1px solid var(--border-dim);
  padding: 7px 12px;
  border-radius: var(--rounding);
  transition: background .12s ease, border-color .12s ease;
  /* Подписи вида "[ ТЕКСТ ]" не переносим внутри кнопки — иначе на узком
     экране закрывающая "]" может оторваться и уйти на вторую строку одна.
     Если кнопка целиком не влезает — пусть переносится сама кнопка (это уже
     умеют flex-контейнеры с flex-wrap, см. .modal-actions), а не текст внутри неё. */
  white-space: nowrap;
}
button:hover:not(:disabled) { border-color: var(--accent); background: var(--hover-bg); }
button:active:not(:disabled) { background: var(--active-bg); }
button:disabled { opacity: .45; cursor: not-allowed; }
button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
button.mini { padding: 3px 9px; font-size: 11px; }
button.danger { color: var(--accent2); }
button.danger:hover:not(:disabled) { border-color: var(--accent2); }
button.primary { border-color: var(--accent); color: var(--accent); font-weight: 700; }
button.ghost { background: none; border-color: transparent; }
button.ghost:hover:not(:disabled) { border-color: var(--border-dim); }

input, select, textarea {
  font-family: inherit;
  font-size: 13px;
  background: var(--input-bg);
  color: var(--text-main);
  border: 1px solid var(--border-dim);
  border-radius: var(--rounding);
  padding: 8px;
  width: 100%;
}
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--accent); }
input::placeholder, textarea::placeholder { color: var(--text-dim); opacity: .8; }
textarea { min-height: 68px; resize: vertical; }
input[type="checkbox"] { width: auto; accent-color: var(--accent); }
input[type="date"], input[type="datetime-local"], input[type="number"] { color-scheme: inherit; }

label.field { display: block; color: var(--text-dim); font-size: 11px; margin: 10px 0 3px; }
label.chk { display: flex; align-items: center; gap: 8px; margin-top: 10px; cursor: pointer; font-size: 13px; }
label.chk input { flex: 0 0 auto; }

/* ═══════════ Иконки (js/icons.js) ═══════════ */
/* Размер в em, а не в px: иконка масштабируется вместе с текстом кнопки. */
.ico {
  width: 1.15em;
  height: 1.15em;
  flex: none;
  vertical-align: -.2em;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* Кнопка из одной иконки: подпись живёт в title, поэтому paddings симметричны. */
button.icon-only { padding-left: 7px; padding-right: 7px; }
/* Иконка внутри кнопки/ссылки отбивается от подписи.
   Через .icon-only, а не :only-child: подпись рядом с иконкой — текстовый
   узел, а :only-child считает только элементы, поэтому SVG для него всегда
   «единственный ребёнок» и отступ не применялся бы никогда. */
button > .ico:first-child,
a > .ico:first-child,
.nt > .ico:first-child,
.assignee > .ico:first-child,
span > .ico:first-child { margin-right: 5px; }
button.icon-only > .ico { margin-right: 0; }

.badge {
  display: inline-block;
  font-size: 10px;
  border: 1px solid var(--border-dim);
  border-radius: 20px;
  padding: 1px 8px;
  margin-left: 6px;
  vertical-align: middle;
  white-space: nowrap;
}
.badge.b-accent  { color: var(--accent);  border-color: var(--accent); }
.badge.b-accent2 { color: var(--accent2); border-color: var(--accent2); }
.badge.b-warn    { color: var(--warn);    border-color: var(--warn); }

.frame {
  background: var(--bg-panel);
  border: 1px solid var(--border-dim);
  border-radius: var(--rounding);
  padding: 16px;
  margin: 12px 0;
  max-width: 460px;
}
.frame.wide { max-width: 100%; }
.frame > h3 {
  margin: 0 0 10px;
  color: var(--accent2);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .04em;
}

.sep { height: 1px; background: var(--border-dim); margin: 14px 0; border: 0; }

/* ═══════════ Таблицы ═══════════ */
.utable { border-collapse: collapse; width: 100%; font-size: 12px; }
.utable th {
  text-align: left;
  color: var(--text-dim);
  font-size: 10px;
  padding: 5px 8px;
  font-weight: 700;
  white-space: nowrap;
  border-bottom: 1px solid var(--border-dim);
}
.utable td { padding: 5px 8px; border-top: 1px solid var(--border-dim); vertical-align: middle; }
.utable tr:hover td { background: var(--hover-bg); }
.table-scroll { overflow-x: auto; }

/* ═══════════ Экран входа ═══════════ */
#login { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 20px; }
#login .box {
  width: 360px;
  max-width: 100%;
  /* Флекс-элементы по умолчанию не сжимаются меньше min-content своего
     содержимого, даже если max-width говорит иначе — из-за этого на узких
     экранах .box вылезал за viewport вместо того, чтобы ужаться. */
  min-width: 0;
  background: var(--bg-panel);
  border: 1.5px solid var(--accent);
  border-radius: var(--rounding);
  padding: 26px;
  box-shadow: var(--shadow);
}
#login h1 { margin: 0 0 2px; font-size: 30px; color: var(--accent); letter-spacing: .08em; }
#login .sub { color: var(--text-dim); font-size: 11px; margin-bottom: 20px; }
#login .mode { color: var(--accent2); font-size: 12px; margin-bottom: 10px; }
#login .msg { margin-top: 14px; font-size: 12px; min-height: 18px; }
#login .foot { margin-top: 22px; font-size: 9px; color: var(--border-dim); text-align: center; }

/* ─── Тема-пикер (нижний правый угол экрана входа) ─── */
#theme-picker { position: fixed; right: 16px; bottom: 16px; z-index: 50; }
.tp-trigger {
  display: flex; align-items: center; gap: 7px;
  padding: 7px 12px 7px 10px;
  border: 1px solid var(--border-dim);
  border-radius: 20px;
  background: var(--bg-panel);
  box-shadow: var(--shadow);
}
.tp-dot { width: 11px; height: 11px; border-radius: 50%; background: var(--accent); flex: none; }
.tp-trigger-label { font-size: 11px; color: var(--text-dim); }
#theme-picker.tp-open .tp-trigger { border-color: var(--accent); }

.tp-panel {
  display: none;
  position: absolute; right: 0; bottom: calc(100% + 8px);
  width: 260px;
  background: var(--bg-panel);
  border: 1px solid var(--accent);
  border-radius: var(--rounding);
  box-shadow: var(--shadow);
  padding: 6px;
}
/* Прокручивается только список — вкладки остаются на месте. */
.tp-list { max-height: 54vh; overflow-y: auto; }
#theme-picker.tp-open .tp-panel { display: block; }

.tp-group-label {
  font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-dim); padding: 6px 8px 4px;
}
.tp-item {
  display: flex; align-items: center; gap: 8px; width: 100%;
  text-align: left; padding: 6px 8px;
  border: 1px solid transparent; border-radius: var(--rounding);
  background: none; cursor: pointer;
}
.tp-item:hover { background: var(--hover-bg); }
.tp-item.active { border-color: var(--accent); background: var(--active-bg); }
.tp-name { flex: 1; font-size: 12px; }
/* Пометка происхождения темы — приглушённая: это справка, а не акцент. */
.tp-mark { flex: none; opacity: .5; margin-left: 4px; }

/* Вкладки внутри панели: Тема / Фон / Текстура. */
.tp-tabs { display: flex; gap: 4px; padding: 2px 2px 6px; }
.tp-tabs button {
  flex: 1;
  padding: 4px 2px;
  font-size: 10px;
  letter-spacing: .04em;
  border-color: transparent;
  background: none;
  color: var(--text-dim);
}
.tp-tabs button:hover:not(:disabled) { background: var(--hover-bg); border-color: transparent; }
.tp-tabs button.active { color: var(--accent); border-color: var(--accent); background: var(--active-bg); }

/* Миниатюры режимов фона: приблизительные CSS-иконки (шесть WebGL-канвасов
   в списке рисовать слишком дорого — сам эффект виден на весь экран по наведению). */
.tp-fxicon {
  width: 34px; height: 20px; flex: none;
  position: relative; overflow: hidden;
  border: 1px solid var(--border-dim);
  border-radius: 2px;
  background: var(--bg-void);
}
.tp-fxicon::after { content: ""; position: absolute; inset: 0; }
.tp-fxicon[data-fx="haze"]::after {
  inset: -25%;
  background:
    radial-gradient(60% 80% at 30% 40%, var(--accent), transparent 70%),
    radial-gradient(50% 70% at 75% 65%, var(--accent2), transparent 70%);
  filter: blur(3px);
}
.tp-fxicon[data-fx="aurora"]::after {
  background: linear-gradient(100deg, transparent 8%, var(--accent) 35%, var(--accent2) 62%, transparent 88%);
  filter: blur(2px);
}
.tp-fxicon[data-fx="rain"]::after {
  background: repeating-linear-gradient(to right, var(--accent) 0 1px, transparent 1px 5px);
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000);
  mask-image: linear-gradient(to bottom, transparent, #000);
}
.tp-fxicon[data-fx="grid"]::after {
  left: -60%; right: -60%; top: 45%;
  background:
    repeating-linear-gradient(to right, var(--accent) 0 1px, transparent 1px 9px),
    repeating-linear-gradient(to bottom, var(--accent) 0 1px, transparent 1px 5px);
  transform: perspective(14px) rotateX(32deg);
  transform-origin: bottom center;
}
.tp-fxicon[data-fx="plasma"]::after {
  inset: -12%;
  background: radial-gradient(circle at 35% 45%, var(--accent2) 0 16%, var(--accent) 32%, var(--bg-void) 64%);
  filter: blur(1.5px);
}
.tp-fxicon[data-fx="stars"]::after {
  color: var(--accent);
  background-image: radial-gradient(currentColor .8px, transparent 1px);
  background-size: 7px 6px;
}
.tp-fxicon[data-fx="waves"]::after {
  background: repeating-radial-gradient(circle at 50% 120%,
    var(--accent) 0 1px, transparent 1px 4px);
  opacity: .9;
}
.tp-fxicon[data-fx="tunnel"]::after {
  background: repeating-radial-gradient(circle at 50% 50%,
    var(--accent) 0 1px, transparent 1px 4px);
}
.tp-fxicon[data-fx="cells"]::after {
  background:
    radial-gradient(circle at 25% 35%, var(--accent) 0 1px, transparent 1px),
    radial-gradient(circle at 70% 60%, var(--accent) 0 1px, transparent 1px),
    repeating-conic-gradient(from 20deg at 45% 50%,
      var(--bg-void) 0 22%, var(--accent) 22% 24%);
  opacity: .85;
}
.tp-fxicon[data-fx="bokeh"]::after {
  background:
    radial-gradient(circle at 28% 40%, var(--accent) 0 22%, transparent 55%),
    radial-gradient(circle at 66% 62%, var(--accent2) 0 18%, transparent 52%),
    radial-gradient(circle at 82% 28%, var(--accent) 0 12%, transparent 45%);
  filter: blur(1px);
}
.tp-fxicon[data-fx="flow"]::after {
  background: repeating-linear-gradient(to bottom, var(--accent) 0 1px, transparent 1px 4px);
  transform: skewY(-8deg) scale(1.3);
}

/* Миниатюра текстуры: тот же .fx-texture, что и полноэкранный слой, но
   на своей подложке — иначе полупрозрачную фактуру не разглядеть. */
.tp-texbox {
  width: 34px; height: 20px; flex: none;
  position: relative; overflow: hidden;
  border: 1px solid var(--border-dim);
  border-radius: 2px;
  /* Нейтральная полутоновая подложка. На «родном» фоне темы (часто чисто
     чёрном) фактуру было бы не разглядеть: overlay поверх чёрного даёт чёрное. */
  background: linear-gradient(135deg, var(--text-dim), var(--bg-widget));
}
.tp-texbox .fx-texture {
  position: absolute; inset: 0;
  /* В миниатюре смешивание обычное, а не overlay — иначе рисунок съедается
     подложкой. Полноэкранный слой при этом остаётся деликатным. */
  mix-blend-mode: normal;
}
/* Текстуры рассчитаны на весь экран и в окошке 34×20 почти не видны —
   поднимаем контраст только для миниатюры. */
.tp-texbox .fx-texture[data-tex="grain"]  { opacity: .55; }
.tp-texbox .fx-texture[data-tex="paper"]  { opacity: .6; }
.tp-texbox .fx-texture[data-tex="dither"] { opacity: .5; }
.tp-texbox .fx-texture[data-tex="grid"]   { opacity: .9; }
.tp-texbox .fx-texture[data-tex="crt"]    { opacity: .8; }
.tp-texbox .fx-texture[data-tex="scanlines"] { opacity: .7; }
.tp-texbox .fx-texture[data-tex="hatch"]    { opacity: .6; }
.tp-texbox .fx-texture[data-tex="dots"]     { opacity: .6; }
.tp-texbox .fx-texture[data-tex="carbon"]   { opacity: .75; }
.tp-texbox .fx-texture[data-tex="vignette"] { opacity: .85; }

.tp-swatch { display: flex; gap: 2px; flex: none; }
.tp-swatch i { display: block; width: 6px; height: 18px; border-radius: 1px; font-style: normal; }
.tp-swatch .tp-sw-void    { background: var(--bg-void); }
.tp-swatch .tp-sw-panel   { background: var(--bg-panel); }
.tp-swatch .tp-sw-accent  { background: var(--accent); }
.tp-swatch .tp-sw-accent2 { background: var(--accent2); }

@media (max-width: 480px) {
  #theme-picker { right: 10px; bottom: 10px; }
  .tp-trigger-label { display: none; }
  .tp-panel { width: min(260px, calc(100vw - 20px)); }
}

/* ─── Пасхалка: логотип в левом нижнем углу экрана входа (js/easter.js) ─── */
/* Зеркало тема-пикера: тот же отступ от края, та же высота посадки. */
.egg { position: fixed; left: 16px; bottom: 16px; z-index: 50; }
.egg-trigger {
  display: block;
  padding: 6px;
  border: 1px solid transparent;
  border-radius: 50%;
  background: none;
  cursor: pointer;
  /* Фирменный оранжевый берётся не из темы: логотип узнают по цвету,
     и перекрашивать его под каждую палитру — значит его потерять. */
  color: #d97757;
  opacity: .55;
  transition: opacity .18s, transform .18s;
}
.egg-trigger:hover { opacity: 1; transform: scale(1.12); border-color: transparent; background: none; }
.egg-trigger:active { transform: scale(.94); }
.egg-logo { display: block; width: 26px; height: 26px; stroke: currentColor; stroke-linecap: round; }
/* Крутится сам логотип, а не кнопка: иначе вместе с ним уезжало бы облачко. */
.egg-spin .egg-logo { animation: egg-turn 14s linear infinite; }
@keyframes egg-turn { to { transform: rotate(360deg); } }

.egg-bubble {
  position: absolute; left: 0; bottom: calc(100% + 8px);
  width: max-content; max-width: min(260px, calc(100vw - 40px));
  padding: 7px 10px;
  font-size: 12px; line-height: 1.35;
  background: var(--bg-panel);
  color: var(--text-main);
  border: 1px solid var(--accent);
  border-radius: var(--rounding);
  box-shadow: var(--shadow);
  /* Не display:none — иначе фраза не дочитывалась бы скринридером
     (role="status" объявляет только изменения видимого содержимого). */
  opacity: 0; transform: translateY(4px); pointer-events: none;
  transition: opacity .18s, transform .18s;
}
.egg-say .egg-bubble { opacity: 1; transform: none; }

@media (max-width: 480px) { .egg { left: 10px; bottom: 10px; } }

/* ─── Брифинг (модалка ⓘ на экране входа, js/app.js) ─── */
.brief-img { display: block; width: 100%; border-radius: var(--rounding); margin-bottom: 12px; }
.brief-lead {
  margin-bottom: 10px;
  font-size: 15px; line-height: 1.3; letter-spacing: .05em;
  color: var(--accent2);
  text-shadow: 0 0 10px currentColor;
}
.brief-spec { margin: 12px 0 14px; font-size: 12px; line-height: 1.5; }
.brief-row { display: flex; gap: 7px; margin-bottom: 6px; }
.brief-row b { color: var(--accent); font-weight: 600; letter-spacing: .04em; }
.brief-mark { color: var(--accent2); flex: none; }
.brief-foot {
  font-size: 11px; letter-spacing: .06em;
  color: var(--warn);
  border-top: 1px solid var(--border-dim);
  padding-top: 10px;
}

/* ─── Фоновые эффекты (js/fx.js) ─── */
/* Канвас — за всем содержимым (z-index:-1), но перед html/body-фоном:
   так тема просвечивает только там, где сверху нет непрозрачной панели. */
#fx-canvas { position: fixed; inset: 0; width: 100%; height: 100%; z-index: -1; pointer-events: none; }

/* Текстура поверх всего экрана, включая модалки — как плёночное зерно поверх
   готового кадра. Целиком CSS: WebGL не нужен, работает даже там, где шейдер
   не завёлся.

   Сам вид задаётся классом .fx-texture + data-tex (его ставит js/fx.js), а не
   селектором по #fx-grain: те же правила переиспользуют миниатюры в списке
   выбора (.tp-texicon), поэтому превью гарантированно совпадает с результатом. */
#fx-grain { position: fixed; inset: 0; z-index: 80; pointer-events: none; display: none; }
#fx-grain.fx-texture { display: block; }
#fx-grain[data-tex="none"] { display: none; }

/* Мелкое плёночное зерно. */
.fx-texture[data-tex="grain"] {
  opacity: .035;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='180'%20height='180'%3E%3Cfilter%20id='n'%3E%3CfeTurbulence%20type='fractalNoise'%20baseFrequency='0.85'%20numOctaves='2'%20stitchTiles='stitch'/%3E%3C/filter%3E%3Crect%20width='100%25'%20height='100%25'%20filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 180px 180px;
}

/* Крупное мягкое волокно — фактура бумаги, а не шум камеры. */
.fx-texture[data-tex="paper"] {
  opacity: .09;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='300'%20height='300'%3E%3Cfilter%20id='p'%3E%3CfeTurbulence%20type='fractalNoise'%20baseFrequency='0.045'%20numOctaves='4'%20stitchTiles='stitch'/%3E%3C/filter%3E%3Crect%20width='100%25'%20height='100%25'%20filter='url(%23p)'/%3E%3C/svg%3E");
  background-size: 300px 300px;
}

/* Горизонтальные строки развёртки. */
.fx-texture[data-tex="scanlines"] {
  opacity: .18;
  background-image: repeating-linear-gradient(to bottom,
    rgba(0, 0, 0, .75) 0 1px, transparent 1px 3px);
}

/* Апертурная решётка ЭЛТ: цветная триада по горизонтали + строки развёртки. */
.fx-texture[data-tex="crt"] {
  opacity: .16;
  mix-blend-mode: overlay;
  background-image:
    repeating-linear-gradient(to right,
      rgba(255, 0, 0, .55) 0 1px,
      rgba(0, 255, 0, .55) 1px 2px,
      rgba(0, 0, 255, .55) 2px 3px),
    repeating-linear-gradient(to bottom,
      rgba(0, 0, 0, .8) 0 1px, transparent 1px 3px);
}

/* Шахматный дизеринг 1-битной эпохи. */
.fx-texture[data-tex="dither"] {
  opacity: .05;
  mix-blend-mode: overlay;
  background-image: conic-gradient(#fff 0 25%, #000 0 50%, #fff 0 75%, #000 0);
  background-size: 4px 4px;
}

/* Диагональная штриховка, как на гравюре. */
.fx-texture[data-tex="hatch"] {
  opacity: .06;
  color: var(--text-main);
  background-image: repeating-linear-gradient(45deg, currentColor 0 1px, transparent 1px 7px);
}

/* Полутоновая точечная сетка — газетная печать. */
.fx-texture[data-tex="dots"] {
  opacity: .07;
  color: var(--text-main);
  background-image: radial-gradient(currentColor .9px, transparent 1px);
  background-size: 8px 8px;
}

/* Карбоновое плетение: две встречные диагонали, свет и тень. */
.fx-texture[data-tex="carbon"] {
  opacity: .1;
  mix-blend-mode: overlay;
  background-image:
    repeating-linear-gradient(45deg, rgba(255, 255, 255, .5) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(-45deg, rgba(0, 0, 0, .5) 0 1px, transparent 1px 3px);
  background-size: 6px 6px;
}

/* Виньетка — единственная «текстура», которая не тайлится: один градиент
   на весь экран, притемняющий углы. Собирает внимание к центру. */
.fx-texture[data-tex="vignette"] {
  opacity: .5;
  background-image: radial-gradient(ellipse at center, transparent 45%, rgba(0, 0, 0, .6) 100%);
}

/* Миллиметровка/чертёж — линии в акцентном цвете темы через currentColor. */
.fx-texture[data-tex="grid"] {
  opacity: .09;
  color: var(--accent);
  background-image:
    repeating-linear-gradient(to right, currentColor 0 1px, transparent 1px 24px),
    repeating-linear-gradient(to bottom, currentColor 0 1px, transparent 1px 24px);
}

@media (prefers-reduced-motion: reduce) { #fx-canvas { display: none !important; } }

/* ═══════════ Каркас приложения ═══════════ */
header {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 18px;
  border-bottom: 1px solid var(--border-dim);
  background: var(--bg-panel);
  position: sticky;
  top: 0;
  /* Выше шторки предметов (30) и её подложки (29): шапка с дубликатом ☰
     остаётся видимой и кликабельной, когда шторка выдвинута. */
  z-index: 35;
  flex-wrap: wrap;
}
header .brand { color: var(--accent); font-weight: 700; font-size: 16px; letter-spacing: .05em; }
header .role {
  color: var(--accent2);
  font-size: 10px;
  border: 1px solid var(--border-dim);
  border-radius: 20px;
  padding: 2px 10px;
  white-space: nowrap;
}
header .spacer { flex: 1; }

.tabs {
  display: flex;
  gap: 6px;
  padding: 10px 18px 0;
  flex-wrap: wrap;
  border-bottom: 1px solid var(--border-dim);
}
.tabs button { border-bottom-left-radius: 0; border-bottom-right-radius: 0; margin-bottom: -1px; color: var(--text-main); }
.tabs button.active { color: var(--accent); border-color: var(--accent); border-bottom-color: var(--bg-void); background: var(--open-bg); }

main { padding: 12px 18px 70px; max-width: 1240px; }

.toolbar { display: flex; align-items: center; gap: 10px; margin: 6px 0 16px; flex-wrap: wrap; }
h2.sec { color: var(--accent); font-size: 20px; margin: 0; font-weight: 700; }
.status-line { font-size: 12px; min-height: 16px; }

/* Индикатор потери связи с сервером */
#offline-bar {
  position: fixed; left: 0; right: 0; bottom: 0;
  background: var(--accent2); color: var(--active-text);
  text-align: center; padding: 7px; font-size: 12px; z-index: 60;
}

/* ═══════════ Тосты ═══════════ */
#toasts {
  position: fixed;
  right: 14px;
  bottom: 14px;
  z-index: 70;
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-width: min(380px, 92vw);
}
.toast {
  background: var(--bg-panel);
  border: 1px solid var(--border-dim);
  border-left-width: 3px;
  border-radius: var(--rounding);
  padding: 9px 12px;
  font-size: 12px;
  box-shadow: var(--shadow);
  cursor: pointer;
  animation: toast-in .16s ease-out;
  word-break: break-word;
}
.toast.t-ok   { border-left-color: var(--ok); }
.toast.t-err  { border-left-color: var(--accent2); }
.toast.t-warn { border-left-color: var(--warn); }
.toast.t-info { border-left-color: var(--accent); }
@keyframes toast-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* ═══════════ Модалки ═══════════ */
#overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, .6);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  z-index: 40;
}
#overlay .modal {
  width: 460px;
  max-width: 100%;
  max-height: 90vh;
  overflow: auto;
  background: var(--bg-panel);
  border: 1px solid var(--accent);
  border-radius: var(--rounding);
  padding: 20px;
  box-shadow: var(--shadow);
}
#overlay .modal.wide { width: 640px; }
.modal h3 { margin: 0 0 8px; color: var(--accent); font-size: 16px; padding-right: 30px; }
.modal .close { float: right; margin: -6px -6px 0 0; }
.kv { color: var(--text-dim); font-size: 13px; margin: 2px 0; word-break: break-word; }
.modal-actions { display: flex; gap: 8px; margin-top: 16px; flex-wrap: wrap; }
/* Кнопки в ряду действий — одного размера, растягиваются поровну (и вместе,
   и когда переносятся каждая на свою строку). Свой контент каждая кнопка
   всё равно не сожмёт меньше своей ширины (min-width:auto по умолчанию) —
   так flex-wrap на .modal-actions по-прежнему сам решает, влезают ли они в ряд. */
.modal-actions button { flex: 1 1 0; }

/* ═══════════ Расписание ═══════════ */
/* Широкий экран — сетка «время × дни», как в десктопе. */
.sched-grid { display: grid; gap: 4px; min-width: 0; }
.sched-grid .hcell {
  color: var(--accent);
  font-size: 10px;
  font-weight: 700;
  padding: 4px 6px;
  text-transform: uppercase;
  border-bottom: 1px solid var(--border-dim);
}
.sched-grid .hcell.today { color: var(--active-text); background: var(--selection-bg); border-radius: var(--rounding); }
.sched-grid .tcell {
  color: var(--text-main);
  font-size: 11px;
  font-weight: 700;
  padding: 8px 4px 0 0;
  white-space: nowrap;
}
.sched-grid .slot { min-height: 44px; padding-top: 4px; }
.sched-grid .row-sep { grid-column: 1 / -1; height: 1px; background: var(--border-dim); }

/* Узкий экран — колонки по дням. */
.sched-days { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 10px; }
.day-col {
  background: var(--bg-panel);
  border: 1px solid var(--border-dim);
  border-radius: var(--rounding);
  padding: 8px;
  min-width: 0;
}
.day-col.today { border-color: var(--accent); }
.day-col h4 { margin: 0 0 8px; color: var(--accent); font-size: 12px; }
.day-col h4 .dnum { color: var(--text-dim); font-weight: 400; margin-left: 6px; }

.lesson {
  background: var(--card-bg);
  border: 2px solid var(--accent);
  border-radius: var(--rounding);
  padding: 6px 8px;
  margin-bottom: 5px;
  cursor: pointer;
  min-width: 0;
}
.lesson.local { background: var(--card-local-bg); border-width: 1.5px; }
.lesson.now { box-shadow: 0 0 0 2px var(--warn) inset; }
.lesson:hover { background: var(--hover-bg); }
.lesson .tm { font-size: 10px; color: var(--warn); font-weight: 700; }
.lesson .t { font-size: 12px; font-weight: 700; word-break: break-word; }
.lesson .m { font-size: 10px; color: var(--text-dim); word-break: break-word; }
.lesson .skipmark { font-size: 10px; color: var(--accent2); }

/* ═══════════ Задачи ═══════════ */
.task-layout { display: flex; gap: 12px; align-items: flex-start; }
.subj-list {
  width: 220px;
  flex: 0 0 220px;
  background: var(--bg-panel);
  border: 1px solid var(--border-dim);
  border-radius: var(--rounding);
  padding: 6px;
  max-height: 74vh;
  overflow: auto;
}
.subj-list.collapsed { display: none; }
.subj-item {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  border-left: 2px solid transparent;
  color: var(--text-main);
  padding: 8px;
  border-radius: 0 var(--rounding) var(--rounding) 0;
  font-size: 12px;
  word-break: break-word;
}
.subj-item:hover { background: var(--hover-bg); border-color: transparent; border-left-color: var(--border-dim); }
.subj-item.active { background: var(--open-bg); color: var(--accent); border-left-color: var(--accent); }
.subj-item.personal { color: var(--accent2); }
.subj-item.active.personal { color: var(--accent); }
.task-main { flex: 1; min-width: 0; }

#subj-backdrop { position: fixed; left: 0; right: 0; bottom: 0; top: var(--header-h, 54px); background: rgba(0, 0, 0, .45); z-index: 29; }

#view-banner {
  background: var(--bg-panel);
  border: 1px solid var(--accent2);
  border-radius: var(--rounding);
  padding: 8px 12px;
  margin-bottom: 10px;
  color: var(--accent2);
  font-size: 12px;
  display: flex;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
}

/* Узел дерева. Отступ вложенности задаётся инлайн через margin-left. */
.node {
  border: 1px solid var(--border-dim);
  border-radius: var(--rounding);
  padding: 9px 11px;
  margin: 6px 0;
  background: var(--bg-widget);
  min-width: 0;
}
.node.pool { border-color: var(--border-dim); }
.node.pool.wasted { border-color: var(--accent2); }
.node.folder { background: none; border-style: dashed; }
.node .nt { font-weight: 700; color: var(--accent); font-size: 14px; word-break: break-word; }
.node.pool .nt { font-size: 15px; }
.node .nd { font-size: 12px; color: var(--text-main); white-space: pre-wrap; word-break: break-word; margin-top: 4px; }
.node .meta { font-size: 10px; color: var(--text-dim); margin-top: 3px; }
.node .meta.slots { font-size: 11px; }
.node .meta.slots.wasted { color: var(--accent2); }
.ops { margin-top: 7px; display: flex; gap: 6px; flex-wrap: wrap; }
.node-head { display: flex; gap: 8px; align-items: flex-start; justify-content: space-between; flex-wrap: wrap; }

/* Строка-тема внутри пула бронирования */
.claim-row {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  padding: 5px 0;
  border-bottom: 1px dotted var(--border-dim);
  font-size: 12px;
}
.claim-row:last-child { border-bottom: none; }
.claim-row .ct { flex: 1; min-width: 120px; word-break: break-word; }

.assignee { font-size: 11px; color: var(--accent); margin-right: 4px; white-space: nowrap; }
.attach-line { font-size: 11px; margin-top: 3px; display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.attach-line .sol { color: var(--accent2); }

.req {
  border: 1px solid var(--accent2);
  border-radius: var(--rounding);
  padding: 10px;
  margin: 6px 0;
  background: var(--bg-widget);
}

/* ═══════════ Доска услуг ═══════════ */
.svc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 12px; }
.svc-card {
  background: var(--card-bg);
  border: 1px solid var(--border-dim);
  border-radius: var(--rounding);
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 7px;
  min-width: 0;
}
.svc-card.mine { border-color: var(--accent); }
.svc-card:hover { border-color: var(--inactive-border); }
.svc-card.mine:hover { border-color: var(--accent); }
/* flex-wrap, а не жёсткий ряд: цена — свободный текст (пользователь мог
   вписать «500 Рублей за Доклад (+150Р за презентацию).», а не короткий тег
   вроде «500 ₽/час»), и она переносится на свою строку, если не влезает
   рядом с заголовком. */
.svc-head { display: flex; gap: 6px 10px; align-items: flex-start; justify-content: space-between; flex-wrap: wrap; }
.svc-title {
  font-weight: 700;
  color: var(--accent);
  font-size: 14px;
  overflow-wrap: anywhere;
  /* Ключевая строка: без min-width:0 flex-элемент с переносом текста не
     сжимается по правилам обычного текста, а схлопывается до ширины
     min-content — а с переносом «где угодно» это ширина ОДНОГО символа.
     Ряд из соседнего nowrap-элемента (цены) забирает всё место, и заголовок
     рушится в вертикальный столбик из одной буквы на строку. */
  flex: 1 1 160px;
  min-width: 0;
}
.svc-price {
  color: var(--warn);
  font-weight: 700;
  font-size: 13px;
  border: 1px solid var(--border-dim);
  border-radius: 20px;
  padding: 1px 10px;
  flex: 0 1 auto;
  min-width: 0;
  max-width: 100%;
  /* Не nowrap: длинная «цена»-фраза переносится по словам вместо того,
     чтобы вжимать заголовок в соседнюю колонку. */
  white-space: normal;
  overflow-wrap: anywhere;
}
.svc-desc {
  font-size: 12px;
  color: var(--text-main);
  white-space: pre-wrap;
  /* anywhere, а не break-word: спасает от «слова» на 500 символов без пробелов. */
  overflow-wrap: anywhere;
}
/* Свёрнутое описание — как в объявлениях: несколько строк и «показать полностью». */
.svc-desc.clamped {
  display: -webkit-box;
  -webkit-line-clamp: 7;
  line-clamp: 7;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.svc-more {
  align-self: flex-start;
  padding: 0;
  font-size: 11px;
  background: none;
  border: none;
  color: var(--accent);
  text-decoration: underline;
}
.svc-more:hover { background: none; border: none; }
.svc-contact-line { display: block; }
.svc-contact { font-size: 12px; word-break: break-word; }
.svc-foot {
  display: flex;
  gap: 8px;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  font-size: 10px;
  border-top: 1px dotted var(--border-dim);
  padding-top: 7px;
  margin-top: auto;
}

/* Сводка */
.dash-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 12px; }
.dash-grid .frame { max-width: 100%; margin: 0; }
.dash-item { font-size: 12px; padding: 4px 0; border-bottom: 1px dotted var(--border-dim); }
.dash-item:last-child { border-bottom: none; }
.dash-item .when { color: var(--text-dim); font-size: 10px; }
.dash-item.overdue .when { color: var(--accent2); }
.dash-item.soon .when { color: var(--warn); }

/* ═══════════ Мобильная адаптация ═══════════ */
@media (max-width: 900px) {
  body { font-size: 15px; }
  button { padding: 10px 13px; }
  button.mini { padding: 5px 10px; }
  input, select, textarea { padding: 10px; font-size: 16px; } /* 16px — iOS не зумит поле */
  main { padding: 10px 12px 70px; }
  header { padding: 9px 12px; }
  .tabs { padding: 8px 12px 0; }
  .sched-days { grid-template-columns: 1fr; }
  #overlay { padding: 0; align-items: flex-end; }
  #overlay .modal { width: 100%; max-height: 92vh; border-radius: var(--rounding) var(--rounding) 0 0; }
  #toasts { left: 10px; right: 10px; max-width: none; bottom: 10px; }

  /* Список предметов превращается в выезжающую шторку. */
  .subj-list {
    /* --header-h измеряется в JS: шапка переносится на две строки при длинном
       логине, поэтому фиксированное значение здесь врало бы. */
    position: fixed; top: var(--header-h, 54px); left: 0; bottom: 0; right: auto;
    width: min(280px, 84vw);
    max-height: none;
    border-radius: 0 var(--rounding) var(--rounding) 0;
    flex-basis: auto;
    z-index: 30;
    padding-top: 8px;
    transform: translateX(-106%);
    transition: transform .22s ease;
    box-shadow: var(--shadow);
  }
  .subj-list.collapsed { display: block; transform: translateX(-106%); }
  .subj-list:not(.collapsed) { transform: translateX(0); }
  /* Бургер в тулбаре намеренно НЕ поднимается над шторкой: выдвинутая шторка
     его накрывает. Иначе он повисает посреди списка предметов и перекрывает
     их названия. Закрывают шторку дубликатом в шапке (#subj-toggle-top),
     подложкой или Esc. */
}
@media (min-width: 901px) { #subj-backdrop { display: none; } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

@media print {
  header, .tabs, .toolbar, #toasts, #overlay, .subj-list { display: none !important; }
  body { background: #fff; color: #000; }
}

/* Черновик карточки, который разбор ДЗ оставил админу на подтверждение
   (вкладка «Управление» → очередь сообщений из топика). Пунктирная рамка
   отделяет предложение модели от того, что реально написали в чате: спутать
   одно с другим — значит подтвердить не глядя. */
.review-draft {
  margin-top: 9px;
  padding: 8px 10px 10px;
  border: 1px dashed var(--accent2);
  border-radius: var(--rounding);
}
.review-draft label.field { margin-top: 7px; }
.review-draft textarea { min-height: 54px; }
.review-draft .row { margin-top: 9px; }

/* Превью картинки-вложения под строкой файла. Ограничение по высоте, а не по
   ширине: фотографии доски приходят и вертикальные, и горизонтальные, а карточка
   задания не должна из-за одной из них растянуться на весь экран. */
.attach-preview { display: block; margin-top: 5px; }
.attach-img {
  display: block;
  max-width: 100%;
  max-height: 240px;
  border: 1px solid var(--border-dim);
  border-radius: var(--rounding);
}

/* Предпросмотр раскладки «задание → пара» перед простановкой дат. */
.date-plan { margin-top: 10px; max-height: 320px; overflow-y: auto; }
.date-plan-line {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  padding: 4px 0;
  border-bottom: 1px solid var(--border-dim);
  font-size: 12px;
}

/* Второй путь в черновике — приложить файл к существующему заданию вместо
   создания нового. Отделён линией, чтобы не путался с основной формой. */
.review-alt { margin-top: 12px; padding-top: 10px; border-top: 1px dashed var(--border-dim); }
