Codex commited on
Commit
0725350
·
1 Parent(s): 9d12b14

Redesign full UI with system theming

Browse files
static/admin-v020.js CHANGED
@@ -1,4 +1,4 @@
1
- (function () {
2
  const bootstrap = window.__ADMIN_BOOTSTRAP__ || {};
3
  const state = {
4
  adminPage: bootstrap.adminPage || "schedule",
@@ -55,10 +55,6 @@
55
  return payload;
56
  }
57
 
58
- function clamp(value, min, max) {
59
- return Math.min(Math.max(value, min), max);
60
- }
61
-
62
  function toMinutes(value) {
63
  const [hour, minute] = String(value).split(":").map(Number);
64
  return (hour * 60) + minute;
@@ -88,30 +84,34 @@
88
  return ["一", "二", "三", "四", "五", "六", "日"][Number(value) - 1] || "";
89
  }
90
 
 
 
 
 
91
  function getConfiguredTimeSlots() {
92
  const slots = Array.isArray(state.scheduleSettings.time_slots) && state.scheduleSettings.time_slots.length
93
  ? state.scheduleSettings.time_slots
94
  : state.defaultTimeSlots;
95
  return slots.map((slot, index) => ({
96
- label: slot.label || `第${String(index + 1).padStart(2, "0")}节课`,
97
  start: slot.start,
98
  end: slot.end,
99
  }));
100
  }
101
 
102
  function buildScheduleSegmentsFromSlots(timeSlots) {
103
- const slots = (timeSlots || [])
104
- .map((slot, index) => ({
105
- kind: "class",
106
- label: `第${String(index + 1).padStart(2, "0")}节课`,
107
- durationMinutes: Math.max(25, toMinutes(slot.end) - toMinutes(slot.start)),
108
- }));
109
 
110
  const segments = [];
111
  slots.forEach((slot, index) => {
112
  if (index > 0) {
113
  const previous = timeSlots[index - 1];
114
- const gap = Math.max(5, toMinutes(timeSlots[index].start) - toMinutes(previous.end));
 
115
  segments.push({
116
  id: `break-${index}`,
117
  kind: "break",
@@ -134,7 +134,7 @@
134
  let breakIndex = 1;
135
  segments.forEach((segment) => {
136
  if (segment.kind === "class") {
137
- segment.label = `第${String(classIndex).padStart(2, "0")}节课`;
138
  classIndex += 1;
139
  } else {
140
  segment.label = `课间 ${breakIndex}`;
@@ -144,7 +144,11 @@
144
  }
145
 
146
  function reflowSegments() {
147
- const baseStart = toMinutes(document.getElementById("dayStartInput").value);
 
 
 
 
148
  let cursor = baseStart;
149
  renumberSegments(state.scheduleEditor.segments);
150
  state.scheduleEditor.segments.forEach((segment) => {
@@ -232,7 +236,8 @@
232
 
233
  const marks = buildScheduleAxisMarks();
234
  const visibleMarks = [];
235
- marks.forEach((minute, index) => {
 
236
  const top = Math.round((minute - startMinutes) * getEditorPixelsPerMinute());
237
  const line = document.createElement("div");
238
  line.className = "schedule-editor-line";
@@ -268,13 +273,13 @@
268
  });
269
 
270
  segments.forEach((segment, index) => {
 
271
  const block = document.createElement("article");
272
- const height = Math.max(Math.round(segment.durationMinutes * getEditorPixelsPerMinute()), 36);
273
  block.className = `schedule-editor-segment ${segment.kind}`;
274
  block.style.top = `${Math.round((segment.startMinutes - startMinutes) * getEditorPixelsPerMinute())}px`;
275
- block.style.height = `${height}px`;
276
- block.classList.toggle("is-compact", height < 88);
277
- block.classList.toggle("is-tight", height < 56);
278
  block.innerHTML = `
279
  <div class="schedule-editor-segment-copy">
280
  <strong>${segment.label}</strong>
@@ -290,6 +295,7 @@
290
  scheduleEditorDropzone.style.top = `${dropzoneTop}px`;
291
  scheduleEditorDropzone.style.bottom = "auto";
292
  scheduleEditorTrack.appendChild(scheduleEditorDropzone);
 
293
  if (scheduleSegmentCount) {
294
  scheduleSegmentCount.textContent = `${segments.length} 段`;
295
  }
@@ -387,7 +393,7 @@
387
  day_end: dayEnd,
388
  default_task_duration_minutes: Number(document.getElementById("defaultDurationInput").value),
389
  time_slots: classSegments.map((segment, index) => ({
390
- label: `第${String(index + 1).padStart(2, "0")}节课`,
391
  start: minutesToTime(segment.startMinutes),
392
  end: minutesToTime(segment.endMinutes),
393
  })),
@@ -401,8 +407,7 @@
401
  }
402
 
403
  function buildPeriodOptions() {
404
- const slots = getConfiguredTimeSlots();
405
- return slots.map((slot, index) => ({
406
  value: String(index + 1),
407
  label: `第${String(index + 1).padStart(2, "0")}节 · ${slot.start}-${slot.end}`,
408
  }));
@@ -578,15 +583,10 @@
578
 
579
  scheduleEditorTrack.addEventListener("click", (event) => {
580
  const deleteButton = event.target.closest("[data-delete-segment]");
581
- if (deleteButton) {
582
- deleteClassSegment(Number(deleteButton.dataset.deleteSegment));
583
- return;
584
- }
585
-
586
- const resizeHandle = event.target.closest("[data-resize-segment]");
587
- if (resizeHandle) {
588
  return;
589
  }
 
590
  });
591
 
592
  scheduleEditorTrack.addEventListener("pointerdown", (event) => {
@@ -691,11 +691,11 @@
691
  }
692
 
693
  populateCoursePeriodOptions();
694
- resetCourseForm(null);
695
  renderCourses();
696
 
697
  if (resetCourseEditorButton) {
698
- resetCourseEditorButton.addEventListener("click", () => resetCourseForm(null));
699
  }
700
 
701
  courseForm.addEventListener("submit", async (event) => {
@@ -715,7 +715,7 @@
715
  showToast("课程已创建");
716
  }
717
  renderCourses();
718
- resetCourseForm(null);
719
  } catch (error) {
720
  showToast(error.message, "error");
721
  }
@@ -743,7 +743,7 @@
743
  });
744
  state.courses = state.courses.filter((course) => course.id !== deleteButton.dataset.deleteCourse);
745
  renderCourses();
746
- resetCourseForm(null);
747
  showToast("课程已删除");
748
  } catch (error) {
749
  showToast(error.message, "error");
 
1
+ (function () {
2
  const bootstrap = window.__ADMIN_BOOTSTRAP__ || {};
3
  const state = {
4
  adminPage: bootstrap.adminPage || "schedule",
 
55
  return payload;
56
  }
57
 
 
 
 
 
58
  function toMinutes(value) {
59
  const [hour, minute] = String(value).split(":").map(Number);
60
  return (hour * 60) + minute;
 
84
  return ["一", "二", "三", "四", "五", "六", "日"][Number(value) - 1] || "";
85
  }
86
 
87
+ function buildSlotLabel(index) {
88
+ return `第${String(index + 1).padStart(2, "0")}节课`;
89
+ }
90
+
91
  function getConfiguredTimeSlots() {
92
  const slots = Array.isArray(state.scheduleSettings.time_slots) && state.scheduleSettings.time_slots.length
93
  ? state.scheduleSettings.time_slots
94
  : state.defaultTimeSlots;
95
  return slots.map((slot, index) => ({
96
+ label: buildSlotLabel(index),
97
  start: slot.start,
98
  end: slot.end,
99
  }));
100
  }
101
 
102
  function buildScheduleSegmentsFromSlots(timeSlots) {
103
+ const slots = (timeSlots || []).map((slot, index) => ({
104
+ kind: "class",
105
+ label: buildSlotLabel(index),
106
+ durationMinutes: Math.max(25, toMinutes(slot.end) - toMinutes(slot.start)),
107
+ }));
 
108
 
109
  const segments = [];
110
  slots.forEach((slot, index) => {
111
  if (index > 0) {
112
  const previous = timeSlots[index - 1];
113
+ const current = timeSlots[index];
114
+ const gap = Math.max(5, toMinutes(current.start) - toMinutes(previous.end));
115
  segments.push({
116
  id: `break-${index}`,
117
  kind: "break",
 
134
  let breakIndex = 1;
135
  segments.forEach((segment) => {
136
  if (segment.kind === "class") {
137
+ segment.label = buildSlotLabel(classIndex - 1);
138
  classIndex += 1;
139
  } else {
140
  segment.label = `课间 ${breakIndex}`;
 
144
  }
145
 
146
  function reflowSegments() {
147
+ const dayStartInput = document.getElementById("dayStartInput");
148
+ if (!dayStartInput) {
149
+ return;
150
+ }
151
+ const baseStart = toMinutes(dayStartInput.value);
152
  let cursor = baseStart;
153
  renumberSegments(state.scheduleEditor.segments);
154
  state.scheduleEditor.segments.forEach((segment) => {
 
236
 
237
  const marks = buildScheduleAxisMarks();
238
  const visibleMarks = [];
239
+
240
+ marks.forEach((minute) => {
241
  const top = Math.round((minute - startMinutes) * getEditorPixelsPerMinute());
242
  const line = document.createElement("div");
243
  line.className = "schedule-editor-line";
 
273
  });
274
 
275
  segments.forEach((segment, index) => {
276
+ const segmentHeight = Math.max(Math.round(segment.durationMinutes * getEditorPixelsPerMinute()), 36);
277
  const block = document.createElement("article");
 
278
  block.className = `schedule-editor-segment ${segment.kind}`;
279
  block.style.top = `${Math.round((segment.startMinutes - startMinutes) * getEditorPixelsPerMinute())}px`;
280
+ block.style.height = `${segmentHeight}px`;
281
+ block.classList.toggle("is-compact", segmentHeight < 88);
282
+ block.classList.toggle("is-tight", segmentHeight < 56);
283
  block.innerHTML = `
284
  <div class="schedule-editor-segment-copy">
285
  <strong>${segment.label}</strong>
 
295
  scheduleEditorDropzone.style.top = `${dropzoneTop}px`;
296
  scheduleEditorDropzone.style.bottom = "auto";
297
  scheduleEditorTrack.appendChild(scheduleEditorDropzone);
298
+
299
  if (scheduleSegmentCount) {
300
  scheduleSegmentCount.textContent = `${segments.length} 段`;
301
  }
 
393
  day_end: dayEnd,
394
  default_task_duration_minutes: Number(document.getElementById("defaultDurationInput").value),
395
  time_slots: classSegments.map((segment, index) => ({
396
+ label: buildSlotLabel(index),
397
  start: minutesToTime(segment.startMinutes),
398
  end: minutesToTime(segment.endMinutes),
399
  })),
 
407
  }
408
 
409
  function buildPeriodOptions() {
410
+ return getConfiguredTimeSlots().map((slot, index) => ({
 
411
  value: String(index + 1),
412
  label: `第${String(index + 1).padStart(2, "0")}节 · ${slot.start}-${slot.end}`,
413
  }));
 
583
 
584
  scheduleEditorTrack.addEventListener("click", (event) => {
585
  const deleteButton = event.target.closest("[data-delete-segment]");
586
+ if (!deleteButton) {
 
 
 
 
 
 
587
  return;
588
  }
589
+ deleteClassSegment(Number(deleteButton.dataset.deleteSegment));
590
  });
591
 
592
  scheduleEditorTrack.addEventListener("pointerdown", (event) => {
 
691
  }
692
 
693
  populateCoursePeriodOptions();
694
+ resetCourseForm();
695
  renderCourses();
696
 
697
  if (resetCourseEditorButton) {
698
+ resetCourseEditorButton.addEventListener("click", () => resetCourseForm());
699
  }
700
 
701
  courseForm.addEventListener("submit", async (event) => {
 
715
  showToast("课程已创建");
716
  }
717
  renderCourses();
718
+ resetCourseForm();
719
  } catch (error) {
720
  showToast(error.message, "error");
721
  }
 
743
  });
744
  state.courses = state.courses.filter((course) => course.id !== deleteButton.dataset.deleteCourse);
745
  renderCourses();
746
+ resetCourseForm();
747
  showToast("课程已删除");
748
  } catch (error) {
749
  showToast(error.message, "error");
static/styles.css CHANGED
@@ -1,36 +1,77 @@
1
  :root {
2
- --bg: #081524;
3
- --bg-soft: rgba(10, 23, 37, 0.75);
4
- --surface: rgba(9, 22, 35, 0.76);
5
- --surface-border: rgba(255, 255, 255, 0.08);
6
- --surface-strong: rgba(255, 255, 255, 0.08);
7
- --text: #eef4fb;
8
- --muted: rgba(238, 244, 251, 0.68);
9
- --muted-strong: rgba(238, 244, 251, 0.84);
10
- --accent: #5ce1e6;
11
- --accent-2: #73d883;
12
- --warning: #ffc857;
13
- --danger: #ff6b5c;
14
- --shadow: 0 24px 80px rgba(0, 0, 0, 0.28);
15
- --radius-xl: 30px;
16
- --radius-lg: 24px;
17
- --radius-md: 18px;
18
- --radius-sm: 14px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  }
20
 
21
  * {
22
  box-sizing: border-box;
23
  }
24
 
25
- html, body {
 
26
  margin: 0;
27
  min-height: 100%;
28
  background:
29
- radial-gradient(circle at top left, rgba(92, 225, 230, 0.18), transparent 28%),
30
- radial-gradient(circle at 85% 15%, rgba(255, 200, 87, 0.16), transparent 24%),
31
- linear-gradient(180deg, #0b1625 0%, #07111d 100%);
 
32
  color: var(--text);
33
- font-family: "Noto Sans SC", "PingFang SC", sans-serif;
 
 
34
  }
35
 
36
  body {
@@ -40,7 +81,8 @@ body {
40
 
41
  button,
42
  input,
43
- textarea {
 
44
  font: inherit;
45
  }
46
 
@@ -62,102 +104,92 @@ a {
62
  .ambient {
63
  position: fixed;
64
  inset: auto;
65
- width: 42vw;
66
- height: 42vw;
67
- border-radius: 999px;
68
- filter: blur(46px);
69
- opacity: 0.34;
70
  z-index: -1;
71
- animation: floatGlow 18s ease-in-out infinite;
 
72
  }
73
 
74
  .ambient-one {
75
- top: -10vw;
76
- left: -12vw;
77
- background: rgba(92, 225, 230, 0.3);
78
  }
79
 
80
  .ambient-two {
81
  right: -8vw;
82
- bottom: -10vw;
83
- background: rgba(255, 200, 87, 0.22);
84
- animation-delay: -6s;
 
 
 
 
 
 
 
85
  }
86
 
87
  .layout,
88
  .admin-layout {
89
- width: min(1340px, calc(100% - 32px));
90
  margin: 0 auto;
91
- padding: 28px 0 56px;
92
  }
93
 
94
- .hero-card,
95
  .card-surface,
 
96
  .admin-card,
97
  .modal-card {
98
- border: 1px solid var(--surface-border);
99
- background: linear-gradient(180deg, rgba(13, 28, 44, 0.9) 0%, rgba(8, 20, 32, 0.86) 100%);
100
- box-shadow: var(--shadow);
101
- backdrop-filter: blur(18px);
102
- }
103
-
104
- .hero-card {
105
- min-height: 31vh;
106
- padding: 28px;
107
- border-radius: var(--radius-xl);
108
- display: flex;
109
- flex-direction: column;
110
- justify-content: space-between;
111
- overflow: hidden;
112
  position: relative;
 
 
 
 
113
  }
114
 
115
- .hero-card::after {
 
 
 
116
  content: "";
117
  position: absolute;
118
- inset: auto -12% -28% auto;
119
- width: 300px;
120
- height: 300px;
121
- border-radius: 999px;
122
- background: radial-gradient(circle, rgba(92, 225, 230, 0.18), transparent 72%);
123
  pointer-events: none;
124
  }
125
 
126
- .hero-topbar,
127
- .column-header,
128
- .section-header,
129
- .admin-card-head,
130
- .action-group,
131
- .column-actions,
132
- .task-main,
133
- .form-actions {
134
- display: flex;
135
- align-items: center;
136
- }
137
-
138
- .hero-topbar,
139
- .section-header,
140
- .admin-card-head {
141
- justify-content: space-between;
142
- gap: 16px;
143
  }
144
 
145
  .brand-mark {
146
  display: inline-flex;
147
  align-items: center;
148
  gap: 10px;
149
- padding: 8px 12px;
150
- border-radius: 999px;
151
- background: rgba(255, 255, 255, 0.06);
 
 
152
  color: var(--muted-strong);
 
153
  }
154
 
155
  .brand-dot {
156
  width: 10px;
157
  height: 10px;
158
- border-radius: 999px;
159
- background: linear-gradient(180deg, var(--accent) 0%, #7effa7 100%);
160
- box-shadow: 0 0 18px rgba(92, 225, 230, 0.72);
161
  }
162
 
163
  .ghost-link,
@@ -167,7 +199,13 @@ a {
167
  .danger-button,
168
  .icon-button,
169
  .task-delete {
170
- transition: transform 160ms ease, background 160ms ease, border-color 160ms ease, color 160ms ease, opacity 160ms ease;
 
 
 
 
 
 
171
  }
172
 
173
  .ghost-link,
@@ -179,53 +217,63 @@ a {
179
  align-items: center;
180
  justify-content: center;
181
  gap: 8px;
182
- min-height: 44px;
183
- border-radius: 999px;
184
- padding: 0 18px;
185
- border: 1px solid rgba(255, 255, 255, 0.08);
 
 
 
186
  }
187
 
188
- .ghost-link,
189
- .pill-button {
190
- background: rgba(255, 255, 255, 0.05);
191
- color: var(--text);
 
 
 
 
192
  }
193
 
194
  .pill-button.accent,
195
  .primary-button {
196
- background: linear-gradient(135deg, #7be7ea 0%, #61d29f 100%);
197
  border-color: transparent;
198
- color: #082030;
199
- font-weight: 700;
200
  }
201
 
202
- .secondary-button {
203
- background: rgba(255, 255, 255, 0.06);
204
  color: var(--text);
205
  }
206
 
 
 
 
 
207
  .danger-button {
208
- background: rgba(255, 107, 92, 0.12);
209
- border-color: rgba(255, 107, 92, 0.25);
210
- color: #ff9388;
211
  }
212
 
213
- .ghost-link:hover,
214
- .pill-button:hover,
215
- .primary-button:hover,
216
- .secondary-button:hover,
217
- .danger-button:hover,
218
- .icon-button:hover,
219
- .task-delete:hover {
220
- transform: translateY(-2px);
 
 
 
 
221
  }
222
 
223
- .clock-wrap {
224
- display: grid;
225
- place-items: center;
226
- gap: 8px;
227
- text-align: center;
228
- padding: 10px 0 8px;
229
  }
230
 
231
  .eyebrow,
@@ -233,80 +281,107 @@ a {
233
  .column-label,
234
  .modal-kicker {
235
  margin: 0;
236
- letter-spacing: 0.12em;
 
237
  text-transform: uppercase;
238
  color: var(--muted);
239
- font-size: 0.82rem;
240
- }
241
-
242
- .clock-display {
243
- margin: 0;
244
- font-family: "Sora", "Noto Sans SC", sans-serif;
245
- font-weight: 800;
246
- font-size: clamp(2.8rem, 8vw, 5.2rem);
247
- letter-spacing: 0.08em;
248
- line-height: 1;
249
  }
250
 
251
- .clock-meta {
 
 
 
 
 
 
 
252
  display: flex;
253
- flex-wrap: wrap;
254
  align-items: center;
255
- justify-content: center;
256
- gap: 10px 18px;
257
- color: var(--muted-strong);
258
- font-size: 1rem;
259
- }
260
-
261
- .clock-meta span {
262
- padding: 8px 14px;
263
- border-radius: 999px;
264
- background: rgba(255, 255, 255, 0.06);
265
  }
266
 
267
- .board-section {
268
- padding-top: 24px;
269
- }
270
-
271
- .section-header {
272
- margin-bottom: 18px;
273
  }
274
 
275
  .section-header h2,
276
  .admin-hero h1,
277
  .admin-card h2,
278
  .modal-head h3 {
279
- margin: 6px 0 0;
280
- font-family: "Sora", "Noto Sans SC", sans-serif;
 
 
281
  }
282
 
283
  .section-note,
284
  .admin-copy,
285
  .admin-card-copy {
 
286
  color: var(--muted);
 
287
  }
288
 
289
- .board-grid {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
290
  display: grid;
291
- gap: 18px;
292
- grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
293
- align-items: start;
294
  }
295
 
296
- .todo-column {
297
- padding: 20px;
298
- border-radius: var(--radius-lg);
299
- min-height: 460px;
300
- animation: riseIn 360ms ease both;
 
 
 
 
 
 
301
  }
302
 
303
- .column-title {
304
- margin: 6px 0 0;
305
- font-size: 1.45rem;
 
 
 
306
  }
307
 
308
- .column-actions {
309
- gap: 8px;
 
 
 
 
 
 
 
 
 
 
 
 
310
  }
311
 
312
  .menu-wrap {
@@ -317,16 +392,16 @@ a {
317
  position: absolute;
318
  top: calc(100% + 8px);
319
  right: 0;
320
- min-width: 140px;
321
  padding: 8px;
322
- border-radius: 16px;
323
- border: 1px solid rgba(255, 255, 255, 0.08);
324
- background: rgba(8, 20, 32, 0.98);
325
- box-shadow: 0 18px 32px rgba(0, 0, 0, 0.3);
326
  opacity: 0;
327
  pointer-events: none;
328
- transform: translateY(-6px);
329
- transition: opacity 160ms ease, transform 160ms ease;
330
  }
331
 
332
  .menu-panel.is-open {
@@ -341,60 +416,43 @@ a {
341
  background: transparent;
342
  color: var(--text);
343
  padding: 12px 14px;
344
- border-radius: 12px;
345
  text-align: left;
346
  }
347
 
348
  .menu-panel button:hover {
349
- background: rgba(255, 255, 255, 0.06);
350
- }
351
-
352
- .icon-button {
353
- width: 42px;
354
- height: 42px;
355
- border-radius: 14px;
356
- border: 1px solid rgba(255, 255, 255, 0.09);
357
- background: linear-gradient(180deg, rgba(123, 231, 234, 0.16) 0%, rgba(255, 255, 255, 0.04) 100%);
358
- color: var(--text);
359
- font-size: 1.4rem;
360
- }
361
-
362
- .icon-button.muted {
363
- font-size: 1.55rem;
364
- }
365
-
366
- .task-list {
367
- display: grid;
368
- gap: 14px;
369
- margin-top: 18px;
370
  }
371
 
372
  .task-card {
373
- padding: 16px;
374
- border-radius: 20px;
375
- background: linear-gradient(180deg, rgba(255, 255, 255, 0.06) 0%, rgba(255, 255, 255, 0.03) 100%);
376
- border: 1px solid rgba(255, 255, 255, 0.06);
377
- display: grid;
378
- gap: 14px;
379
  position: relative;
 
 
 
 
 
 
380
  overflow: hidden;
381
  }
382
 
383
  .task-card::before {
384
  content: "";
385
  position: absolute;
386
- inset: 0 0 auto;
387
- height: 1px;
388
- background: linear-gradient(90deg, rgba(123, 231, 234, 0.6), transparent);
 
389
  }
390
 
391
  .task-copy {
392
  flex: 1;
 
393
  }
394
 
395
  .task-copy h4 {
396
  margin: 0 0 10px;
397
- font-size: 1.08rem;
 
398
  }
399
 
400
  .meta-line {
@@ -404,20 +462,21 @@ a {
404
  gap: 8px;
405
  }
406
 
407
- .meta-badge {
 
408
  display: inline-flex;
409
  align-items: center;
410
- gap: 6px;
411
- padding: 7px 10px;
412
- border-radius: 999px;
413
  background: rgba(255, 255, 255, 0.06);
414
  color: var(--muted-strong);
415
- font-size: 0.88rem;
416
  }
417
 
418
  .progress-shell {
419
- height: 10px;
420
- border-radius: 999px;
421
  background: rgba(255, 255, 255, 0.08);
422
  overflow: hidden;
423
  }
@@ -427,20 +486,21 @@ a {
427
  height: 100%;
428
  border-radius: inherit;
429
  background: linear-gradient(90deg, #73d883 0%, #ffd166 55%, #ff6b5c 100%);
430
- transition: width 360ms ease, filter 360ms ease;
431
  }
432
 
433
  .task-card.task-complete .progress-bar {
434
- background: linear-gradient(90deg, #66d0ff 0%, #7be7ea 100%);
435
  }
436
 
437
  .task-card.task-complete h4 {
438
- color: rgba(238, 244, 251, 0.66);
439
  text-decoration: line-through;
440
  }
441
 
442
  .check-wrap {
443
  position: relative;
 
444
  }
445
 
446
  .task-check {
@@ -450,18 +510,17 @@ a {
450
  }
451
 
452
  .custom-check {
453
- display: inline-flex;
454
  width: 24px;
455
  height: 24px;
456
- border-radius: 8px;
457
- border: 1.5px solid rgba(255, 255, 255, 0.36);
458
- background: rgba(255, 255, 255, 0.02);
459
  position: relative;
460
  flex-shrink: 0;
461
  }
462
 
463
  .task-check:checked + .custom-check {
464
- background: linear-gradient(135deg, #7be7ea 0%, #61d29f 100%);
465
  border-color: transparent;
466
  }
467
 
@@ -472,26 +531,16 @@ a {
472
  top: 3px;
473
  width: 6px;
474
  height: 12px;
475
- border-right: 2px solid #082030;
476
- border-bottom: 2px solid #082030;
477
  transform: rotate(45deg);
478
  }
479
 
480
- body[data-authenticated="false"] .task-check,
481
- body[data-authenticated="false"] .icon-button,
482
- body[data-authenticated="false"] [data-rename-category] {
483
- cursor: pointer;
484
- }
485
-
486
- body[data-authenticated="false"] .task-delete {
487
- display: none;
488
- }
489
-
490
  .task-delete {
491
  justify-self: flex-end;
492
  border: 0;
493
  background: transparent;
494
- color: rgba(255, 255, 255, 0.42);
495
  padding: 0;
496
  }
497
 
@@ -499,26 +548,26 @@ body[data-authenticated="false"] .task-delete {
499
  min-height: 180px;
500
  display: grid;
501
  place-items: center;
502
- text-align: center;
503
  gap: 8px;
504
- padding: 22px;
505
- border-radius: 20px;
506
- background: rgba(255, 255, 255, 0.03);
507
  color: var(--muted);
 
508
  }
509
 
510
  .modal-backdrop {
511
  position: fixed;
512
  inset: 0;
513
- background: rgba(3, 10, 18, 0.64);
514
- backdrop-filter: blur(10px);
515
  display: grid;
516
  place-items: center;
517
  padding: 24px;
518
  opacity: 0;
519
  pointer-events: none;
520
  transition: opacity 180ms ease;
521
- z-index: 30;
522
  }
523
 
524
  .modal-backdrop.is-open {
@@ -527,9 +576,9 @@ body[data-authenticated="false"] .task-delete {
527
  }
528
 
529
  .modal-card {
530
- width: min(500px, 100%);
531
  padding: 28px;
532
- border-radius: 28px;
533
  }
534
 
535
  .modal-form {
@@ -551,80 +600,78 @@ body[data-authenticated="false"] .task-delete {
551
  color: var(--muted-strong);
552
  }
553
 
554
- .modal-form input {
 
 
555
  width: 100%;
556
- min-height: 50px;
557
  padding: 0 16px;
558
- border-radius: 16px;
559
- border: 1px solid rgba(255, 255, 255, 0.1);
560
- background: rgba(255, 255, 255, 0.04);
561
  color: var(--text);
562
  outline: none;
563
  }
564
 
565
- .modal-form input:focus {
566
- border-color: rgba(123, 231, 234, 0.7);
567
- box-shadow: 0 0 0 3px rgba(123, 231, 234, 0.14);
 
 
568
  }
569
 
570
  .form-actions {
571
  justify-content: flex-end;
572
  gap: 10px;
573
- padding-top: 6px;
574
  }
575
 
576
  .toast-stack {
577
  position: fixed;
578
- top: 20px;
579
- right: 20px;
580
  display: grid;
581
  gap: 10px;
582
- z-index: 40;
583
  }
584
 
585
  .toast {
586
  min-width: 220px;
587
- max-width: 320px;
588
  padding: 14px 16px;
589
  border-radius: 18px;
590
- border: 1px solid rgba(255, 255, 255, 0.08);
591
- background: rgba(7, 18, 30, 0.96);
592
- box-shadow: var(--shadow);
593
- color: var(--text);
594
  animation: riseIn 220ms ease both;
595
  }
596
 
597
- .toast.error {
598
- border-color: rgba(255, 107, 92, 0.26);
599
  }
600
 
601
- .toast.success {
602
- border-color: rgba(115, 216, 131, 0.24);
603
  }
604
 
605
  .admin-hero {
606
- border-radius: var(--radius-xl);
607
- padding: 28px;
608
  margin-bottom: 22px;
609
- display: flex;
610
- justify-content: space-between;
611
- gap: 18px;
612
- align-items: center;
613
  }
614
 
615
  .admin-grid {
616
  display: grid;
617
- gap: 18px;
618
- grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
619
  }
620
 
621
  .admin-card {
622
- border-radius: 26px;
623
- padding: 22px;
624
- min-height: 240px;
625
  display: flex;
626
  flex-direction: column;
627
  justify-content: space-between;
 
 
628
  }
629
 
630
  .create-card {
@@ -635,26 +682,20 @@ body[data-authenticated="false"] .task-delete {
635
  .create-icon {
636
  width: 56px;
637
  height: 56px;
638
- border-radius: 18px;
639
  display: grid;
640
  place-items: center;
641
- font-size: 2rem;
642
- background: linear-gradient(135deg, rgba(123, 231, 234, 0.18) 0%, rgba(97, 210, 159, 0.12) 100%);
643
- }
644
-
645
- .task-count {
646
- padding: 8px 12px;
647
- border-radius: 999px;
648
- background: rgba(255, 255, 255, 0.06);
649
- color: var(--muted-strong);
650
  }
651
 
652
  @keyframes floatGlow {
653
- 0%, 100% {
 
654
  transform: translate3d(0, 0, 0) scale(1);
655
  }
656
  50% {
657
- transform: translate3d(3vw, 2vw, 0) scale(1.05);
658
  }
659
  }
660
 
@@ -669,49 +710,36 @@ body[data-authenticated="false"] .task-delete {
669
  }
670
  }
671
 
672
- @media (max-width: 840px) {
673
- .hero-topbar,
 
 
 
 
 
674
  .section-header,
675
- .admin-hero {
676
  flex-direction: column;
677
  align-items: flex-start;
678
  }
679
-
680
- .action-group {
681
- width: 100%;
682
- flex-wrap: wrap;
683
- }
684
-
685
- .clock-display {
686
- letter-spacing: 0.03em;
687
- }
688
-
689
- .clock-meta {
690
- gap: 10px;
691
- }
692
  }
693
 
694
- @media (max-width: 560px) {
695
  .layout,
696
  .admin-layout {
697
- width: min(100% - 18px, 1340px);
698
  padding-top: 18px;
699
- padding-bottom: 32px;
700
  }
701
 
702
  .hero-card,
703
- .todo-column,
704
- .modal-card,
705
  .admin-card,
 
706
  .admin-hero {
707
- padding: 18px;
708
  border-radius: 24px;
709
  }
710
 
711
- .clock-display {
712
- font-size: clamp(2.4rem, 16vw, 4.2rem);
713
- }
714
-
715
  .form-actions {
716
  flex-direction: column-reverse;
717
  align-items: stretch;
 
1
  :root {
2
+ color-scheme: light dark;
3
+ --font-sans: "Manrope", "Noto Sans SC", sans-serif;
4
+ --font-mono: "IBM Plex Mono", monospace;
5
+
6
+ --bg: #f4f0e8;
7
+ --bg-2: #efe8df;
8
+ --surface: rgba(255, 252, 247, 0.74);
9
+ --surface-strong: rgba(255, 255, 255, 0.88);
10
+ --surface-soft: rgba(255, 255, 255, 0.52);
11
+ --line: rgba(27, 31, 35, 0.08);
12
+ --line-strong: rgba(27, 31, 35, 0.14);
13
+ --text: #15191d;
14
+ --muted: rgba(21, 25, 29, 0.62);
15
+ --muted-strong: rgba(21, 25, 29, 0.78);
16
+ --accent: #0e6b67;
17
+ --accent-soft: rgba(14, 107, 103, 0.12);
18
+ --accent-strong: #0b5a57;
19
+ --accent-2: #ae6f48;
20
+ --warning: #c99743;
21
+ --danger: #c45b57;
22
+ --success: #2f7d58;
23
+ --shadow-xl: 0 26px 80px rgba(25, 32, 37, 0.14);
24
+ --shadow-lg: 0 16px 44px rgba(25, 32, 37, 0.1);
25
+ --shadow-sm: 0 8px 22px rgba(25, 32, 37, 0.06);
26
+ --radius-shell: 34px;
27
+ --radius-card: 26px;
28
+ --radius-panel: 22px;
29
+ --radius-button: 16px;
30
+ --radius-pill: 999px;
31
+ }
32
+
33
+ @media (prefers-color-scheme: dark) {
34
+ :root {
35
+ --bg: #0c1015;
36
+ --bg-2: #131821;
37
+ --surface: rgba(18, 25, 33, 0.74);
38
+ --surface-strong: rgba(19, 27, 36, 0.92);
39
+ --surface-soft: rgba(255, 255, 255, 0.05);
40
+ --line: rgba(255, 255, 255, 0.07);
41
+ --line-strong: rgba(255, 255, 255, 0.12);
42
+ --text: #eef2f6;
43
+ --muted: rgba(238, 242, 246, 0.62);
44
+ --muted-strong: rgba(238, 242, 246, 0.8);
45
+ --accent: #7cd7d1;
46
+ --accent-soft: rgba(124, 215, 209, 0.12);
47
+ --accent-strong: #8de6db;
48
+ --accent-2: #d39b70;
49
+ --warning: #d2ab5e;
50
+ --danger: #f08e86;
51
+ --success: #77d49d;
52
+ --shadow-xl: 0 26px 80px rgba(0, 0, 0, 0.42);
53
+ --shadow-lg: 0 16px 44px rgba(0, 0, 0, 0.34);
54
+ --shadow-sm: 0 8px 22px rgba(0, 0, 0, 0.22);
55
+ }
56
  }
57
 
58
  * {
59
  box-sizing: border-box;
60
  }
61
 
62
+ html,
63
+ body {
64
  margin: 0;
65
  min-height: 100%;
66
  background:
67
+ radial-gradient(circle at 14% 12%, rgba(124, 215, 209, 0.22), transparent 24%),
68
+ radial-gradient(circle at 88% 18%, rgba(211, 155, 112, 0.14), transparent 26%),
69
+ radial-gradient(circle at 50% 86%, rgba(124, 215, 209, 0.08), transparent 30%),
70
+ linear-gradient(180deg, var(--bg) 0%, var(--bg-2) 100%);
71
  color: var(--text);
72
+ font-family: var(--font-sans);
73
+ -webkit-font-smoothing: antialiased;
74
+ text-rendering: optimizeLegibility;
75
  }
76
 
77
  body {
 
81
 
82
  button,
83
  input,
84
+ textarea,
85
+ select {
86
  font: inherit;
87
  }
88
 
 
104
  .ambient {
105
  position: fixed;
106
  inset: auto;
107
+ width: 46vw;
108
+ height: 46vw;
109
+ border-radius: 50%;
110
+ filter: blur(70px);
111
+ opacity: 0.48;
112
  z-index: -1;
113
+ animation: floatGlow 22s ease-in-out infinite;
114
+ pointer-events: none;
115
  }
116
 
117
  .ambient-one {
118
+ top: -16vw;
119
+ left: -10vw;
120
+ background: rgba(124, 215, 209, 0.2);
121
  }
122
 
123
  .ambient-two {
124
  right: -8vw;
125
+ top: 28vh;
126
+ background: rgba(211, 155, 112, 0.12);
127
+ animation-delay: -8s;
128
+ }
129
+
130
+ .ambient-three {
131
+ right: 18vw;
132
+ bottom: -20vw;
133
+ background: rgba(124, 215, 209, 0.1);
134
+ animation-delay: -14s;
135
  }
136
 
137
  .layout,
138
  .admin-layout {
139
+ width: min(1520px, calc(100% - 32px));
140
  margin: 0 auto;
141
+ padding: 24px 0 40px;
142
  }
143
 
 
144
  .card-surface,
145
+ .hero-card,
146
  .admin-card,
147
  .modal-card {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  position: relative;
149
+ border: 1px solid var(--line);
150
+ background: linear-gradient(180deg, var(--surface-strong) 0%, var(--surface) 100%);
151
+ box-shadow: var(--shadow-xl);
152
+ backdrop-filter: blur(18px) saturate(135%);
153
  }
154
 
155
+ .card-surface::before,
156
+ .hero-card::before,
157
+ .admin-card::before,
158
+ .modal-card::before {
159
  content: "";
160
  position: absolute;
161
+ inset: 0;
162
+ border-radius: inherit;
163
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.22), transparent 24%, transparent 76%, rgba(255, 255, 255, 0.04));
 
 
164
  pointer-events: none;
165
  }
166
 
167
+ .hero-card,
168
+ .card-surface,
169
+ .admin-card,
170
+ .modal-card {
171
+ border-radius: var(--radius-card);
 
 
 
 
 
 
 
 
 
 
 
 
172
  }
173
 
174
  .brand-mark {
175
  display: inline-flex;
176
  align-items: center;
177
  gap: 10px;
178
+ min-height: 42px;
179
+ padding: 0 14px;
180
+ border-radius: var(--radius-pill);
181
+ background: var(--surface-soft);
182
+ border: 1px solid var(--line);
183
  color: var(--muted-strong);
184
+ font-weight: 700;
185
  }
186
 
187
  .brand-dot {
188
  width: 10px;
189
  height: 10px;
190
+ border-radius: 50%;
191
+ background: linear-gradient(180deg, var(--accent) 0%, var(--accent-2) 100%);
192
+ box-shadow: 0 0 0 6px rgba(124, 215, 209, 0.08);
193
  }
194
 
195
  .ghost-link,
 
199
  .danger-button,
200
  .icon-button,
201
  .task-delete {
202
+ transition:
203
+ transform 180ms cubic-bezier(0.22, 1, 0.36, 1),
204
+ background 180ms ease,
205
+ border-color 180ms ease,
206
+ color 180ms ease,
207
+ box-shadow 180ms ease,
208
+ opacity 180ms ease;
209
  }
210
 
211
  .ghost-link,
 
217
  align-items: center;
218
  justify-content: center;
219
  gap: 8px;
220
+ min-height: 42px;
221
+ padding: 0 16px;
222
+ border-radius: var(--radius-button);
223
+ border: 1px solid var(--line);
224
+ background: var(--surface-soft);
225
+ color: var(--text);
226
+ box-shadow: var(--shadow-sm);
227
  }
228
 
229
+ .ghost-link:hover,
230
+ .pill-button:hover,
231
+ .primary-button:hover,
232
+ .secondary-button:hover,
233
+ .danger-button:hover,
234
+ .icon-button:hover,
235
+ .task-delete:hover {
236
+ transform: translateY(-1px) scale(1.01);
237
  }
238
 
239
  .pill-button.accent,
240
  .primary-button {
241
+ background: linear-gradient(135deg, var(--accent) 0%, var(--accent-strong) 100%);
242
  border-color: transparent;
243
+ color: #f8fbfb;
 
244
  }
245
 
246
+ .pill-button.accent-soft {
247
+ background: linear-gradient(135deg, rgba(124, 215, 209, 0.18) 0%, rgba(124, 215, 209, 0.08) 100%);
248
  color: var(--text);
249
  }
250
 
251
+ .secondary-button {
252
+ background: rgba(255, 255, 255, 0.05);
253
+ }
254
+
255
  .danger-button {
256
+ background: rgba(196, 91, 87, 0.12);
257
+ border-color: rgba(196, 91, 87, 0.24);
258
+ color: var(--danger);
259
  }
260
 
261
+ .icon-button {
262
+ width: 42px;
263
+ height: 42px;
264
+ border-radius: 15px;
265
+ border: 1px solid var(--line);
266
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.12) 0%, rgba(255, 255, 255, 0.04) 100%);
267
+ color: var(--text);
268
+ box-shadow: var(--shadow-sm);
269
+ display: inline-flex;
270
+ align-items: center;
271
+ justify-content: center;
272
+ font-size: 1.28rem;
273
  }
274
 
275
+ .icon-button.muted {
276
+ font-size: 1.44rem;
 
 
 
 
277
  }
278
 
279
  .eyebrow,
 
281
  .column-label,
282
  .modal-kicker {
283
  margin: 0;
284
+ font-size: 0.76rem;
285
+ letter-spacing: 0.14em;
286
  text-transform: uppercase;
287
  color: var(--muted);
288
+ font-weight: 700;
 
 
 
 
 
 
 
 
 
289
  }
290
 
291
+ .section-header,
292
+ .hero-topbar,
293
+ .column-header,
294
+ .admin-card-head,
295
+ .action-group,
296
+ .column-actions,
297
+ .task-main,
298
+ .form-actions {
299
  display: flex;
 
300
  align-items: center;
 
 
 
 
 
 
 
 
 
 
301
  }
302
 
303
+ .section-header,
304
+ .hero-topbar,
305
+ .admin-card-head {
306
+ justify-content: space-between;
307
+ gap: 18px;
 
308
  }
309
 
310
  .section-header h2,
311
  .admin-hero h1,
312
  .admin-card h2,
313
  .modal-head h3 {
314
+ margin: 4px 0 0;
315
+ font-family: var(--font-sans);
316
+ font-weight: 800;
317
+ letter-spacing: -0.04em;
318
  }
319
 
320
  .section-note,
321
  .admin-copy,
322
  .admin-card-copy {
323
+ margin: 0;
324
  color: var(--muted);
325
+ line-height: 1.62;
326
  }
327
 
328
+ .hero-card {
329
+ overflow: hidden;
330
+ }
331
+
332
+ .hero-card::after {
333
+ content: "";
334
+ position: absolute;
335
+ inset: auto -12% -18% auto;
336
+ width: 280px;
337
+ height: 280px;
338
+ border-radius: 50%;
339
+ background: radial-gradient(circle, rgba(124, 215, 209, 0.18), transparent 72%);
340
+ pointer-events: none;
341
+ }
342
+
343
+ .clock-wrap {
344
  display: grid;
345
+ place-items: center;
346
+ gap: 10px;
347
+ text-align: center;
348
  }
349
 
350
+ .clock-caption {
351
+ display: inline-flex;
352
+ align-items: center;
353
+ min-height: 34px;
354
+ padding: 0 14px;
355
+ border-radius: var(--radius-pill);
356
+ background: rgba(255, 255, 255, 0.06);
357
+ color: var(--muted-strong);
358
+ font-size: 0.74rem;
359
+ letter-spacing: 0.12em;
360
+ text-transform: uppercase;
361
  }
362
 
363
+ .clock-display {
364
+ margin: 0;
365
+ font-family: var(--font-sans);
366
+ font-weight: 800;
367
+ letter-spacing: -0.06em;
368
+ line-height: 0.92;
369
  }
370
 
371
+ .clock-meta {
372
+ display: flex;
373
+ flex-wrap: wrap;
374
+ align-items: center;
375
+ justify-content: center;
376
+ gap: 10px;
377
+ color: var(--muted-strong);
378
+ }
379
+
380
+ .clock-meta span {
381
+ padding: 8px 14px;
382
+ border-radius: var(--radius-pill);
383
+ background: rgba(255, 255, 255, 0.06);
384
+ font-size: 0.9rem;
385
  }
386
 
387
  .menu-wrap {
 
392
  position: absolute;
393
  top: calc(100% + 8px);
394
  right: 0;
395
+ min-width: 148px;
396
  padding: 8px;
397
+ border-radius: 18px;
398
+ border: 1px solid var(--line-strong);
399
+ background: var(--surface-strong);
400
+ box-shadow: var(--shadow-lg);
401
  opacity: 0;
402
  pointer-events: none;
403
+ transform: translateY(-4px);
404
+ transition: opacity 180ms ease, transform 180ms ease;
405
  }
406
 
407
  .menu-panel.is-open {
 
416
  background: transparent;
417
  color: var(--text);
418
  padding: 12px 14px;
419
+ border-radius: 14px;
420
  text-align: left;
421
  }
422
 
423
  .menu-panel button:hover {
424
+ background: rgba(255, 255, 255, 0.08);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
425
  }
426
 
427
  .task-card {
 
 
 
 
 
 
428
  position: relative;
429
+ display: grid;
430
+ gap: 12px;
431
+ padding: 16px;
432
+ border-radius: var(--radius-panel);
433
+ border: 1px solid var(--line);
434
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0.04) 100%);
435
  overflow: hidden;
436
  }
437
 
438
  .task-card::before {
439
  content: "";
440
  position: absolute;
441
+ inset: 0 auto 0 0;
442
+ width: 3px;
443
+ background: linear-gradient(180deg, var(--accent) 0%, transparent 100%);
444
+ opacity: 0.78;
445
  }
446
 
447
  .task-copy {
448
  flex: 1;
449
+ min-width: 0;
450
  }
451
 
452
  .task-copy h4 {
453
  margin: 0 0 10px;
454
+ font-size: 1rem;
455
+ line-height: 1.32;
456
  }
457
 
458
  .meta-line {
 
462
  gap: 8px;
463
  }
464
 
465
+ .meta-badge,
466
+ .task-count {
467
  display: inline-flex;
468
  align-items: center;
469
+ min-height: 32px;
470
+ padding: 0 12px;
471
+ border-radius: var(--radius-pill);
472
  background: rgba(255, 255, 255, 0.06);
473
  color: var(--muted-strong);
474
+ font-size: 0.82rem;
475
  }
476
 
477
  .progress-shell {
478
+ height: 8px;
479
+ border-radius: var(--radius-pill);
480
  background: rgba(255, 255, 255, 0.08);
481
  overflow: hidden;
482
  }
 
486
  height: 100%;
487
  border-radius: inherit;
488
  background: linear-gradient(90deg, #73d883 0%, #ffd166 55%, #ff6b5c 100%);
489
+ transition: width 360ms ease;
490
  }
491
 
492
  .task-card.task-complete .progress-bar {
493
+ background: linear-gradient(90deg, rgba(124, 215, 209, 0.72) 0%, rgba(124, 215, 209, 1) 100%);
494
  }
495
 
496
  .task-card.task-complete h4 {
497
+ color: var(--muted);
498
  text-decoration: line-through;
499
  }
500
 
501
  .check-wrap {
502
  position: relative;
503
+ display: inline-flex;
504
  }
505
 
506
  .task-check {
 
510
  }
511
 
512
  .custom-check {
 
513
  width: 24px;
514
  height: 24px;
515
+ border-radius: 9px;
516
+ border: 1.5px solid rgba(255, 255, 255, 0.32);
517
+ background: rgba(255, 255, 255, 0.03);
518
  position: relative;
519
  flex-shrink: 0;
520
  }
521
 
522
  .task-check:checked + .custom-check {
523
+ background: linear-gradient(135deg, var(--accent) 0%, var(--accent-strong) 100%);
524
  border-color: transparent;
525
  }
526
 
 
531
  top: 3px;
532
  width: 6px;
533
  height: 12px;
534
+ border-right: 2px solid white;
535
+ border-bottom: 2px solid white;
536
  transform: rotate(45deg);
537
  }
538
 
 
 
 
 
 
 
 
 
 
 
539
  .task-delete {
540
  justify-self: flex-end;
541
  border: 0;
542
  background: transparent;
543
+ color: var(--muted);
544
  padding: 0;
545
  }
546
 
 
548
  min-height: 180px;
549
  display: grid;
550
  place-items: center;
 
551
  gap: 8px;
552
+ padding: 24px;
553
+ border-radius: var(--radius-panel);
554
+ background: rgba(255, 255, 255, 0.04);
555
  color: var(--muted);
556
+ text-align: center;
557
  }
558
 
559
  .modal-backdrop {
560
  position: fixed;
561
  inset: 0;
562
+ background: rgba(9, 11, 15, 0.34);
563
+ backdrop-filter: blur(12px);
564
  display: grid;
565
  place-items: center;
566
  padding: 24px;
567
  opacity: 0;
568
  pointer-events: none;
569
  transition: opacity 180ms ease;
570
+ z-index: 80;
571
  }
572
 
573
  .modal-backdrop.is-open {
 
576
  }
577
 
578
  .modal-card {
579
+ width: min(520px, 100%);
580
  padding: 28px;
581
+ box-shadow: var(--shadow-xl);
582
  }
583
 
584
  .modal-form {
 
600
  color: var(--muted-strong);
601
  }
602
 
603
+ .modal-form input,
604
+ .modal-form select,
605
+ .modal-form textarea {
606
  width: 100%;
607
+ min-height: 48px;
608
  padding: 0 16px;
609
+ border-radius: var(--radius-button);
610
+ border: 1px solid var(--line);
611
+ background: rgba(255, 255, 255, 0.06);
612
  color: var(--text);
613
  outline: none;
614
  }
615
 
616
+ .modal-form input:focus,
617
+ .modal-form select:focus,
618
+ .modal-form textarea:focus {
619
+ border-color: rgba(124, 215, 209, 0.7);
620
+ box-shadow: 0 0 0 3px rgba(124, 215, 209, 0.14);
621
  }
622
 
623
  .form-actions {
624
  justify-content: flex-end;
625
  gap: 10px;
626
+ padding-top: 4px;
627
  }
628
 
629
  .toast-stack {
630
  position: fixed;
631
+ top: 18px;
632
+ right: 18px;
633
  display: grid;
634
  gap: 10px;
635
+ z-index: 90;
636
  }
637
 
638
  .toast {
639
  min-width: 220px;
640
+ max-width: 340px;
641
  padding: 14px 16px;
642
  border-radius: 18px;
643
+ border: 1px solid var(--line-strong);
644
+ background: var(--surface-strong);
645
+ box-shadow: var(--shadow-lg);
 
646
  animation: riseIn 220ms ease both;
647
  }
648
 
649
+ .toast.success {
650
+ border-color: rgba(47, 125, 88, 0.22);
651
  }
652
 
653
+ .toast.error {
654
+ border-color: rgba(196, 91, 87, 0.26);
655
  }
656
 
657
  .admin-hero {
658
+ border-radius: var(--radius-shell);
659
+ padding: 30px;
660
  margin-bottom: 22px;
 
 
 
 
661
  }
662
 
663
  .admin-grid {
664
  display: grid;
665
+ gap: 20px;
666
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
667
  }
668
 
669
  .admin-card {
 
 
 
670
  display: flex;
671
  flex-direction: column;
672
  justify-content: space-between;
673
+ padding: 24px;
674
+ min-height: 240px;
675
  }
676
 
677
  .create-card {
 
682
  .create-icon {
683
  width: 56px;
684
  height: 56px;
685
+ border-radius: 20px;
686
  display: grid;
687
  place-items: center;
688
+ font-size: 1.8rem;
689
+ background: linear-gradient(135deg, rgba(124, 215, 209, 0.18) 0%, rgba(174, 111, 72, 0.12) 100%);
 
 
 
 
 
 
 
690
  }
691
 
692
  @keyframes floatGlow {
693
+ 0%,
694
+ 100% {
695
  transform: translate3d(0, 0, 0) scale(1);
696
  }
697
  50% {
698
+ transform: translate3d(2vw, 1.5vw, 0) scale(1.05);
699
  }
700
  }
701
 
 
710
  }
711
  }
712
 
713
+ @media (max-width: 1180px) {
714
+ .layout,
715
+ .admin-layout {
716
+ width: min(100% - 22px, 1520px);
717
+ }
718
+
719
+ .admin-hero,
720
  .section-header,
721
+ .hero-topbar {
722
  flex-direction: column;
723
  align-items: flex-start;
724
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
725
  }
726
 
727
+ @media (max-width: 760px) {
728
  .layout,
729
  .admin-layout {
730
+ width: min(100% - 18px, 1520px);
731
  padding-top: 18px;
732
+ padding-bottom: 28px;
733
  }
734
 
735
  .hero-card,
736
+ .card-surface,
 
737
  .admin-card,
738
+ .modal-card,
739
  .admin-hero {
 
740
  border-radius: 24px;
741
  }
742
 
 
 
 
 
743
  .form-actions {
744
  flex-direction: column-reverse;
745
  align-items: stretch;
static/v020.css CHANGED
@@ -1,68 +1,74 @@
1
- .layout.story-layout {
2
- width: min(1560px, calc(100% - 18px));
3
- height: calc(100vh - 28px);
4
- max-height: calc(100vh - 28px);
5
- min-height: calc(100vh - 28px);
6
- padding: 14px 0;
7
- }
8
-
9
- .story-layout {
10
  padding-top: 0;
11
  overflow: hidden;
12
  }
13
 
 
 
 
 
 
 
 
 
14
  .story-shell {
15
  display: grid;
16
- gap: 12px;
17
- min-width: 0;
18
  height: 100%;
19
  min-height: 0;
20
  grid-template-rows: auto minmax(0, 1fr);
21
  }
22
 
23
  .story-toolbar {
24
- border-radius: 24px;
25
- padding: 12px 16px;
26
  display: grid;
27
  grid-template-columns: auto 1fr auto;
28
- gap: 14px;
29
  align-items: center;
 
 
 
30
  }
31
 
32
  .story-nav {
33
- display: inline-flex;
34
  justify-self: center;
 
 
 
35
  padding: 6px;
36
  border-radius: 999px;
37
  background: rgba(255, 255, 255, 0.05);
38
- gap: 6px;
39
  }
40
 
41
  .story-tab {
42
- min-height: 42px;
43
- padding: 0 18px;
44
  border: 0;
45
- border-radius: 999px;
46
  background: transparent;
47
  color: var(--muted-strong);
 
 
48
  }
49
 
50
  .story-tab.is-active {
51
- background: linear-gradient(135deg, rgba(123, 231, 234, 0.2) 0%, rgba(97, 210, 159, 0.18) 100%);
52
  color: var(--text);
 
 
 
 
 
53
  }
54
 
55
  .page-viewport {
56
  position: relative;
57
  width: 100%;
58
- overflow: hidden;
59
- min-height: 0;
60
  height: 100%;
 
 
61
  }
62
 
63
  .page-track {
64
  display: flex;
65
- width: 100%;
66
  height: 100%;
67
  align-items: stretch;
68
  transition: transform 720ms cubic-bezier(0.22, 1, 0.36, 1);
@@ -72,12 +78,12 @@
72
  .page-slide {
73
  flex: 0 0 100%;
74
  width: 100%;
75
- max-width: 100%;
76
  min-width: 100%;
 
 
 
77
  overflow: hidden;
78
  pointer-events: none;
79
- min-height: 0;
80
- height: 100%;
81
  }
82
 
83
  .page-slide.is-active {
@@ -90,247 +96,193 @@ body.planner-interacting * {
90
  -webkit-user-select: none !important;
91
  }
92
 
93
- body.planner-interacting .page-home {
94
- pointer-events: none;
95
- }
96
-
97
- body.planner-interacting .page-planner {
98
- pointer-events: auto;
99
- }
100
-
101
  .page-home {
102
  display: grid;
103
- gap: 12px;
104
- grid-template-rows: minmax(216px, 27vh) minmax(0, 1fr);
105
- padding-right: 10px;
106
  min-height: 0;
107
  height: 100%;
108
- overflow: hidden;
109
  }
110
 
111
- .page-planner {
112
- padding-left: 10px;
113
- min-height: 0;
114
- height: 100%;
 
115
  overflow: hidden;
116
  }
117
 
118
- .inline-link {
119
- border: 0;
 
 
 
120
  }
121
 
122
- .page-home .hero-card {
123
- min-height: 0;
124
- padding: 22px 24px;
125
- display: flex;
126
- align-items: center;
127
- justify-content: center;
 
 
128
  }
129
 
130
- .clock-wrap {
131
- width: 100%;
132
- gap: 6px;
133
- padding: 6px 0 4px;
134
- display: grid;
135
- justify-items: center;
136
- align-content: center;
137
- text-align: center;
138
- margin: 0 auto;
139
  }
140
 
141
- .clock-display {
142
- font-size: clamp(2.7rem, 7vw, 4.9rem);
 
143
  }
144
 
145
- .clock-meta {
146
- gap: 8px 14px;
147
- font-size: 0.94rem;
148
  }
149
 
150
- .hero-copy {
151
- margin: 6px 0 0;
152
- color: var(--muted);
153
  }
154
 
155
  .board-section {
156
- display: grid;
157
- gap: 12px;
158
- grid-template-rows: auto minmax(0, 1fr);
159
  min-height: 0;
160
- height: 100%;
161
- overflow: hidden;
162
- }
163
-
164
- .page-home .board-section {
165
  grid-template-rows: minmax(0, 1fr);
 
166
  }
167
 
168
- .page-home .board-section > .section-header {
169
  display: none;
170
  }
171
 
172
- .board-section .section-header {
173
- margin-bottom: 0;
174
- }
175
-
176
- .board-section .section-header h2 {
177
- font-size: clamp(1.1rem, 1.7vw, 1.5rem);
178
- }
179
-
180
  .board-grid {
181
  display: grid;
182
- gap: 12px;
183
- grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
184
- grid-auto-rows: minmax(0, 1fr);
185
- align-items: stretch;
186
- align-content: start;
187
- min-height: 0;
188
  height: 100%;
189
- overflow: hidden;
 
190
  }
191
 
192
  .todo-column {
193
- padding: 16px;
194
- min-height: 0;
195
- height: 100%;
196
- max-height: 100%;
197
  position: relative;
198
- overflow: visible;
199
  display: grid;
200
  grid-template-rows: auto minmax(0, 1fr);
 
 
 
 
201
  }
202
 
203
- .page-home .column-header {
204
- position: relative;
205
- display: block;
206
- min-height: 58px;
207
- padding-right: 112px;
208
- z-index: 12;
209
  }
210
 
211
- .column-title {
212
- font-size: 1.2rem;
213
  }
214
 
215
- .page-home .column-actions {
216
- position: absolute;
217
- top: 0;
218
- right: 0;
219
- z-index: 24;
 
 
 
220
  }
221
 
222
- .page-home .menu-wrap {
223
- position: relative;
224
- z-index: 28;
 
 
 
 
 
 
225
  }
226
 
227
- .page-home .menu-panel {
228
- z-index: 60;
 
 
229
  }
230
 
231
  .task-list {
232
  display: flex;
233
  flex-direction: column;
234
- gap: 10px;
235
- margin-top: 0;
236
  min-height: 0;
237
- height: 100%;
238
  max-height: 100%;
239
  overflow-y: auto;
240
  overscroll-behavior: contain;
241
- padding-right: 4px;
242
  }
243
 
244
- .task-card {
245
- padding: 14px;
246
- border-radius: 18px;
247
- flex: none;
248
- }
249
-
250
- .task-copy h4 {
251
- margin: 0 0 8px;
252
- font-size: 0.98rem;
253
- }
254
-
255
- .meta-line {
256
- gap: 6px;
257
- }
258
-
259
- .meta-badge {
260
- padding: 6px 9px;
261
- font-size: 0.76rem;
262
- }
263
-
264
- .progress-shell {
265
- height: 8px;
266
  }
267
 
268
  .planner-shell {
269
- border-radius: 26px;
270
- padding: 16px;
271
- min-height: 0;
272
  height: 100%;
 
 
 
273
  overflow: hidden;
 
 
 
274
  display: grid;
275
- grid-template-rows: auto auto minmax(0, 1fr);
276
- gap: 8px;
 
277
  }
278
 
279
- .planner-head h2 {
280
  margin: 4px 0 0;
281
- font-size: clamp(1.34rem, 1.85vw, 1.72rem);
 
282
  }
283
 
284
- .planner-head .section-note {
285
- margin: 6px 0 0;
286
- font-size: 0.92rem;
287
  }
288
 
289
- .planner-head,
290
- .planner-controls,
291
- .planner-meta,
292
- .planner-sidebar-head,
293
- .planner-task-top,
294
- .planner-task-tags,
295
- .admin-card-actions,
296
- .split-fields {
297
  display: flex;
298
  align-items: center;
299
- }
300
-
301
- .planner-head,
302
- .planner-sidebar-head {
303
- justify-content: space-between;
304
- gap: 12px;
305
- }
306
-
307
- .planner-controls {
308
  gap: 8px;
309
  }
310
 
311
  .planner-date-picker {
312
  display: grid;
313
  gap: 6px;
314
- min-width: 172px;
315
  }
316
 
317
  .planner-date-picker span {
318
  color: var(--muted);
319
- font-size: 0.85rem;
320
- }
321
-
322
- .planner-date-picker input,
323
- .modal-form select {
324
- min-height: 42px;
325
- padding: 0 12px;
326
- border-radius: 14px;
327
- border: 1px solid rgba(255, 255, 255, 0.1);
328
- background: rgba(255, 255, 255, 0.04);
329
- color: var(--text);
330
- outline: none;
331
  }
332
 
333
  .planner-meta {
 
334
  flex-wrap: wrap;
335
  gap: 8px;
336
  }
@@ -340,56 +292,41 @@ body.planner-interacting .page-planner {
340
  .planner-task-category {
341
  display: inline-flex;
342
  align-items: center;
343
- padding: 6px 10px;
 
344
  border-radius: 999px;
345
  background: rgba(255, 255, 255, 0.06);
346
  color: var(--muted-strong);
347
- font-size: 0.76rem;
348
  }
349
 
350
  .planner-layout {
351
  display: grid;
352
- grid-template-columns: minmax(0, 8.2fr) minmax(220px, 1.8fr);
353
- gap: 12px;
354
  min-height: 0;
355
- overflow: hidden;
356
- }
357
-
358
- .page-planner .planner-head h2,
359
- .page-planner #plannerHeadlineNote,
360
- .page-planner .planner-sidebar-note,
361
- .page-planner .planner-sidebar-head .column-label {
362
- display: none;
363
- }
364
-
365
- .page-planner .planner-head {
366
- align-items: center;
367
- }
368
-
369
- .page-planner .planner-head .section-kicker {
370
- margin: 0;
371
  }
372
 
373
  .timeline-surface,
374
- .planner-sidebar {
375
- border-radius: 26px;
376
- border: 1px solid rgba(255, 255, 255, 0.08);
377
- background: rgba(255, 255, 255, 0.03);
 
 
378
  }
379
 
380
  .timeline-surface {
381
- padding: 10px;
382
  min-height: 0;
383
- height: 100%;
384
  }
385
 
386
  .timeline-scroll {
387
- overflow: hidden;
388
  height: 100%;
389
- max-height: none;
390
  min-height: 0;
391
- border-radius: 18px;
392
- background: rgba(3, 11, 20, 0.46);
 
393
  }
394
 
395
  .timeline-grid {
@@ -405,14 +342,6 @@ body.planner-interacting .page-planner {
405
  .timeline-now-line {
406
  position: absolute;
407
  top: 0;
408
- bottom: 0;
409
- }
410
-
411
- .timeline-axis-layer,
412
- .timeline-slot-layer,
413
- .timeline-canvas-layer,
414
- .timeline-drop-preview,
415
- .timeline-now-line {
416
  bottom: auto;
417
  }
418
 
@@ -438,42 +367,39 @@ body.planner-interacting .page-planner {
438
  top: 0;
439
  display: grid;
440
  grid-template-columns: repeat(7, minmax(0, 1fr));
441
- gap: 6px;
442
- z-index: 7;
443
  }
444
 
445
  .timeline-day-head {
446
- min-height: 46px;
 
447
  border: 1px solid rgba(255, 255, 255, 0.08);
448
- border-radius: 16px;
449
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0.03) 100%);
450
  color: var(--muted-strong);
451
  display: grid;
452
  place-items: center;
453
  gap: 2px;
454
- padding: 5px 4px;
455
  text-align: center;
456
- transition: transform 160ms ease, border-color 160ms ease, background 160ms ease;
457
  }
458
 
459
  .timeline-day-head strong {
460
- font-size: 0.82rem;
461
- line-height: 1;
462
  }
463
 
464
  .timeline-day-head span {
465
- font-size: 0.68rem;
466
  color: var(--muted);
467
- font-variant-numeric: tabular-nums;
468
  }
469
 
470
  .timeline-day-head.is-selected {
471
- border-color: rgba(123, 231, 234, 0.44);
472
- background: linear-gradient(180deg, rgba(123, 231, 234, 0.18) 0%, rgba(255, 255, 255, 0.05) 100%);
473
  }
474
 
475
  .timeline-day-head.is-today {
476
- box-shadow: inset 0 0 0 1px rgba(255, 200, 87, 0.22);
477
  }
478
 
479
  .timeline-day-column,
@@ -485,29 +411,25 @@ body.planner-interacting .page-planner {
485
  }
486
 
487
  .timeline-day-column {
488
- background: linear-gradient(180deg, rgba(255, 255, 255, 0.018) 0%, rgba(255, 255, 255, 0.008) 100%);
489
  }
490
 
491
  .timeline-day-column.is-selected {
492
- background: linear-gradient(180deg, rgba(92, 225, 230, 0.06) 0%, rgba(92, 225, 230, 0.015) 100%);
493
- }
494
-
495
- .timeline-day-column.is-today {
496
- box-shadow: inset 0 0 0 1px rgba(255, 200, 87, 0.12);
497
  }
498
 
499
  .timeline-day-divider {
500
  width: 1px;
501
- background: linear-gradient(180deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.02));
502
  }
503
 
504
  .timeline-axis-rail {
505
  position: absolute;
506
  top: 0;
507
  bottom: 0;
508
- right: 14px;
509
  width: 1px;
510
- background: linear-gradient(180deg, rgba(255, 255, 255, 0.06), rgba(123, 231, 234, 0.18), rgba(255, 255, 255, 0.06));
511
  }
512
 
513
  .timeline-axis-tick {
@@ -515,27 +437,23 @@ body.planner-interacting .page-planner {
515
  left: 0;
516
  right: 0;
517
  display: flex;
518
- justify-content: flex-end;
519
  align-items: center;
 
520
  gap: 10px;
521
  transform: translateY(-50%);
522
- padding-right: 20px;
523
- color: rgba(238, 244, 251, 0.76);
524
- font-size: 0.75rem;
525
  font-variant-numeric: tabular-nums;
526
- letter-spacing: 0.02em;
527
- line-height: 1;
528
- white-space: nowrap;
529
  }
530
 
531
  .timeline-axis-tick::after {
532
  content: "";
533
  width: 7px;
534
  height: 7px;
535
- border-radius: 999px;
536
- background: rgba(123, 231, 234, 0.78);
537
- box-shadow: 0 0 0 4px rgba(123, 231, 234, 0.12);
538
- flex: none;
539
  }
540
 
541
  .timeline-axis-tick.is-leading {
@@ -550,29 +468,21 @@ body.planner-interacting .page-planner {
550
  position: absolute;
551
  left: 6px;
552
  right: 8px;
553
- box-sizing: border-box;
554
- overflow: hidden;
555
- padding: 5px 8px;
556
- border-radius: 14px;
557
- background: linear-gradient(180deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.025));
558
- border: 1px solid rgba(255, 255, 255, 0.08);
559
- display: flex;
560
- flex-direction: column;
561
- justify-content: center;
562
  gap: 3px;
563
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03);
564
  }
565
 
566
  .timeline-slot-band strong {
567
  font-size: 0.74rem;
568
- line-height: 1.1;
569
  }
570
 
571
  .timeline-slot-band span {
572
  color: var(--muted);
573
- font-size: 0.64rem;
574
- line-height: 1.1;
575
- font-variant-numeric: tabular-nums;
576
  }
577
 
578
  .timeline-line {
@@ -583,43 +493,41 @@ body.planner-interacting .page-planner {
583
  }
584
 
585
  .timeline-line.is-slot {
586
- background: rgba(255, 255, 255, 0.08);
587
  }
588
 
589
  .timeline-major-block {
590
  position: absolute;
591
  left: 0;
592
  right: 0;
593
- box-sizing: border-box;
594
- border-radius: 16px;
595
- background: linear-gradient(180deg, rgba(255, 255, 255, 0.045) 0%, rgba(255, 255, 255, 0.015) 100%);
596
  pointer-events: none;
597
  }
598
 
599
  .timeline-major-block span {
600
  position: absolute;
601
  top: 10px;
602
- right: 12px;
603
- font-family: "Sora", "Noto Sans SC", sans-serif;
604
- font-size: clamp(1rem, 1.35vw, 1.45rem);
605
- color: rgba(238, 244, 251, 0.16);
 
606
  }
607
 
608
  .planner-event,
609
  .timeline-drop-preview {
610
  position: absolute;
611
- box-sizing: border-box;
612
- overflow: hidden;
613
- border-radius: 16px;
614
  padding: 10px 12px 12px;
615
- border: 1px solid rgba(255, 255, 255, 0.08);
616
- background: linear-gradient(180deg, rgba(13, 28, 44, 0.96) 0%, rgba(8, 20, 32, 0.92) 100%);
617
- box-shadow: 0 16px 30px rgba(0, 0, 0, 0.2);
 
618
  }
619
 
620
  .planner-event {
621
  touch-action: none;
622
- z-index: 5;
623
  }
624
 
625
  .planner-event::before,
@@ -628,8 +536,8 @@ body.planner-interacting .page-planner {
628
  position: absolute;
629
  inset: 0 auto 0 0;
630
  width: 4px;
631
- border-radius: 20px 0 0 20px;
632
- background: var(--event-accent, #7be7ea);
633
  }
634
 
635
  .planner-event-top,
@@ -653,60 +561,41 @@ body.planner-interacting .page-planner {
653
 
654
  .planner-course-stack {
655
  display: grid;
656
- gap: 2px;
657
  min-height: 100%;
658
  }
659
 
660
  .planner-course-title {
661
- display: block;
662
  margin: 0;
663
- font-size: 0.74rem;
664
  line-height: 1.12;
665
- letter-spacing: 0.01em;
666
- word-break: break-word;
667
- overflow: hidden;
668
  display: -webkit-box;
669
  -webkit-box-orient: vertical;
670
  -webkit-line-clamp: 2;
 
671
  }
672
 
673
  .planner-course-details {
674
  display: grid;
675
  gap: 1px;
676
- color: rgba(238, 244, 251, 0.82);
677
  font-size: 0.58rem;
678
- line-height: 1.12;
 
679
  }
680
 
681
  .planner-course-line {
682
- display: block;
683
- white-space: normal;
684
  overflow-wrap: anywhere;
685
- font-variant-numeric: tabular-nums;
686
  }
687
 
688
- .planner-lock-badge,
689
  .planner-event-clear,
690
  .planner-task-clear {
691
- display: inline-flex;
692
- align-items: center;
693
- justify-content: center;
694
- min-height: 30px;
695
  padding: 0 10px;
696
  border-radius: 999px;
697
  border: 0;
698
- }
699
-
700
- .planner-lock-badge {
701
- background: rgba(255, 255, 255, 0.08);
702
- color: var(--muted-strong);
703
- }
704
-
705
- .planner-event-clear,
706
- .planner-task-clear {
707
- background: rgba(255, 107, 92, 0.14);
708
- color: #ff9388;
709
- margin-top: 8px;
710
  }
711
 
712
  .planner-event-resize {
@@ -715,9 +604,7 @@ body.planner-interacting .page-planner {
715
  right: 8px;
716
  height: 8px;
717
  border-radius: 999px;
718
- background: linear-gradient(90deg, rgba(123, 231, 234, 0.9), rgba(97, 210, 159, 0.72));
719
- cursor: ns-resize;
720
- z-index: 2;
721
  }
722
 
723
  .planner-event-resize-top {
@@ -730,7 +617,7 @@ body.planner-interacting .page-planner {
730
 
731
  .planner-event.is-dragging,
732
  .planner-task-card.is-dragging {
733
- opacity: 0.8;
734
  }
735
 
736
  .planner-event.is-dragging {
@@ -739,31 +626,20 @@ body.planner-interacting .page-planner {
739
 
740
  .planner-event.is-conflict,
741
  .timeline-drop-preview.is-conflict {
742
- border-color: rgba(255, 107, 92, 0.72);
743
- box-shadow: 0 0 0 1px rgba(255, 107, 92, 0.22), 0 16px 28px rgba(0, 0, 0, 0.24);
744
  }
745
 
746
  .planner-event.is-conflict::before,
747
  .timeline-drop-preview.is-conflict::before {
748
- background: #ff6b5c;
749
  }
750
 
751
  .course-event {
752
- padding: 7px 8px 7px 10px;
753
  }
754
 
755
  .planner-event.is-compact {
756
- border-radius: 16px;
757
- padding: 7px 10px 8px;
758
- }
759
-
760
- .planner-event.is-compact::before {
761
- border-radius: 16px 0 0 16px;
762
- }
763
-
764
- .task-event.is-compact .planner-event-top {
765
- display: grid;
766
- gap: 4px;
767
  }
768
 
769
  .task-event.is-compact .planner-event-meta,
@@ -771,20 +647,7 @@ body.planner-interacting .page-planner {
771
  display: none;
772
  }
773
 
774
- .course-event.is-compact .planner-lock-badge {
775
- display: none;
776
- }
777
-
778
- .course-event.is-compact .planner-course-stack {
779
- gap: 2px;
780
- }
781
-
782
- .course-event.is-compact .planner-course-title {
783
- font-size: 0.68rem;
784
- }
785
-
786
  .course-event.is-compact .planner-course-details {
787
- gap: 1px;
788
  font-size: 0.54rem;
789
  }
790
 
@@ -794,7 +657,6 @@ body.planner-interacting .page-planner {
794
 
795
  .planner-event.is-tight .planner-event-meta,
796
  .planner-event.is-tight .planner-event-clear,
797
- .planner-event.is-tight .planner-lock-badge,
798
  .planner-event.is-tight .planner-event-time {
799
  display: none;
800
  }
@@ -804,40 +666,36 @@ body.planner-interacting .page-planner {
804
  }
805
 
806
  .course-event.is-tight .planner-course-title {
807
- font-size: 0.62rem;
808
- line-height: 1.06;
809
- }
810
-
811
- .planner-event.is-tight .planner-event-top {
812
- display: block;
813
  }
814
 
815
- .planner-event.is-tight .planner-event-top strong {
816
- max-width: 100%;
817
- font-size: 0.74rem;
 
 
 
818
  }
819
 
820
- .planner-event.is-tight .planner-event-resize {
821
- left: 8px;
822
- right: 8px;
823
- height: 5px;
 
824
  }
825
 
826
- .planner-sidebar {
827
- padding: 14px;
828
- display: grid;
829
- gap: 10px;
830
- align-content: start;
831
- min-height: 0;
832
- grid-template-rows: auto minmax(0, 1fr);
833
- overflow: hidden;
834
  }
835
 
836
  .planner-sidebar-note {
837
  display: grid;
838
  gap: 6px;
 
839
  color: var(--muted);
840
- font-size: 0.84rem;
841
  }
842
 
843
  .planner-task-pool {
@@ -845,20 +703,17 @@ body.planner-interacting .page-planner {
845
  flex-direction: column;
846
  gap: 12px;
847
  min-height: 0;
848
- height: 100%;
849
- max-height: 100%;
850
  overflow-y: auto;
851
- overscroll-behavior: contain;
852
- padding-right: 4px;
853
  }
854
 
855
  .planner-task-card {
856
- padding: 14px;
857
- border-radius: 20px;
858
- border: 1px solid rgba(255, 255, 255, 0.08);
859
- background: linear-gradient(180deg, rgba(255, 255, 255, 0.06) 0%, rgba(255, 255, 255, 0.03) 100%);
860
  display: grid;
861
  gap: 12px;
 
 
 
 
862
  }
863
 
864
  .planner-task-card h4 {
@@ -885,8 +740,11 @@ body.planner-interacting .page-planner {
885
  }
886
 
887
  .planner-task-tags span {
888
- padding: 6px 9px;
 
889
  border-radius: 999px;
 
 
890
  background: rgba(255, 255, 255, 0.05);
891
  color: var(--muted-strong);
892
  font-size: 0.76rem;
@@ -899,18 +757,8 @@ body.planner-interacting .page-planner {
899
  grid-column: 1 / -1;
900
  }
901
 
902
- .planner-task-category {
903
- white-space: nowrap;
904
- align-self: start;
905
- }
906
-
907
- .planner-empty,
908
- .empty-admin-card {
909
- min-height: 180px;
910
- display: grid;
911
- place-items: center;
912
- text-align: center;
913
- gap: 10px;
914
  }
915
 
916
  .timeline-drop-preview {
@@ -919,25 +767,13 @@ body.planner-interacting .page-planner {
919
  align-content: center;
920
  color: var(--muted-strong);
921
  border-style: dashed;
922
- background: rgba(123, 231, 234, 0.1);
923
- z-index: 4;
924
- }
925
-
926
- .timeline-drop-preview strong {
927
- font-size: 0.78rem;
928
- line-height: 1.1;
929
- }
930
-
931
- .timeline-drop-preview span {
932
- color: var(--muted);
933
- font-size: 0.72rem;
934
  }
935
 
936
  .timeline-now-line {
937
  position: absolute;
938
  height: 2px;
939
- background: linear-gradient(90deg, rgba(255, 107, 92, 0.95), rgba(255, 200, 87, 0.72));
940
- box-shadow: 0 0 18px rgba(255, 107, 92, 0.38);
941
  z-index: 6;
942
  pointer-events: none;
943
  }
@@ -949,40 +785,19 @@ body.planner-interacting .page-planner {
949
  top: -5px;
950
  width: 12px;
951
  height: 12px;
952
- border-radius: 999px;
953
- background: #ff6b5c;
954
- }
955
-
956
- .admin-section {
957
- margin-top: 24px;
958
- }
959
-
960
- .admin-grid-tight {
961
- grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
962
- }
963
-
964
- .admin-card-actions {
965
- gap: 10px;
966
- flex-wrap: wrap;
967
- }
968
-
969
- .split-fields {
970
- gap: 12px;
971
- }
972
-
973
- .split-fields label {
974
- flex: 1;
975
  }
976
 
977
  .admin-layout-v2 {
978
- width: min(1480px, calc(100% - 28px));
979
  }
980
 
981
  .admin-layout-v2 .admin-hero {
982
  display: grid;
983
  grid-template-columns: minmax(0, 1fr) auto;
984
  align-items: start;
985
- gap: 18px 24px;
986
  }
987
 
988
  .admin-layout-v2 .admin-hero > div:first-child {
@@ -991,7 +806,6 @@ body.planner-interacting .page-planner {
991
 
992
  .admin-layout-v2 .action-group {
993
  justify-self: end;
994
- align-self: start;
995
  }
996
 
997
  .admin-page-nav {
@@ -1004,20 +818,29 @@ body.planner-interacting .page-planner {
1004
  }
1005
 
1006
  .admin-page-tab {
1007
- min-height: 42px;
1008
  padding: 0 16px;
1009
- border-radius: 999px;
1010
  display: inline-flex;
1011
  align-items: center;
1012
  justify-content: center;
1013
  color: var(--muted-strong);
 
1014
  }
1015
 
1016
  .admin-page-tab.is-active {
1017
- background: linear-gradient(135deg, rgba(123, 231, 234, 0.2) 0%, rgba(97, 210, 159, 0.18) 100%);
1018
  color: var(--text);
1019
  }
1020
 
 
 
 
 
 
 
 
 
1021
  .admin-stack {
1022
  display: grid;
1023
  gap: 16px;
@@ -1027,26 +850,20 @@ body.planner-interacting .page-planner {
1027
  padding: 20px 22px;
1028
  }
1029
 
1030
- .course-list .course-card {
1031
- border-radius: 22px;
1032
- }
1033
-
1034
  .admin-lists-grid {
1035
- grid-template-columns: minmax(320px, 360px) minmax(0, 1fr);
1036
  align-items: start;
1037
  }
1038
 
1039
- .list-create-card {
 
 
1040
  position: sticky;
1041
- top: 28px;
1042
- }
1043
-
1044
- .list-management-stack {
1045
- gap: 14px;
1046
  }
1047
 
1048
  .list-row-card {
1049
- border-radius: 24px;
1050
  }
1051
 
1052
  .admin-row-main {
@@ -1063,15 +880,10 @@ body.planner-interacting .page-planner {
1063
  }
1064
 
1065
  .course-management-grid {
1066
- grid-template-columns: minmax(330px, 380px) minmax(0, 1fr);
1067
  align-items: start;
1068
  }
1069
 
1070
- .course-editor-card {
1071
- position: sticky;
1072
- top: 28px;
1073
- }
1074
-
1075
  .course-row-head {
1076
  align-items: start;
1077
  margin-bottom: 2px;
@@ -1095,13 +907,13 @@ body.planner-interacting .page-planner {
1095
  }
1096
 
1097
  .course-card h2 {
1098
- font-size: 1.12rem;
1099
  }
1100
 
1101
  .course-card .admin-card-copy {
1102
  margin: 1px 0 0;
1103
  font-size: 0.78rem;
1104
- line-height: 1.18;
1105
  }
1106
 
1107
  .course-row-actions .secondary-button,
@@ -1109,19 +921,14 @@ body.planner-interacting .page-planner {
1109
  .course-row-actions .task-count {
1110
  min-height: 34px;
1111
  padding: 0 10px;
1112
- font-size: 0.82rem;
1113
  }
1114
 
1115
  .admin-schedule-grid {
1116
- grid-template-columns: minmax(320px, 380px) minmax(0, 1fr);
1117
  align-items: start;
1118
  }
1119
 
1120
- .schedule-form-card {
1121
- position: sticky;
1122
- top: 28px;
1123
- }
1124
-
1125
  .schedule-editor-card {
1126
  padding: 22px;
1127
  }
@@ -1129,40 +936,39 @@ body.planner-interacting .page-planner {
1129
  .schedule-palette {
1130
  display: flex;
1131
  gap: 12px;
1132
- margin-top: 18px;
1133
  flex-wrap: wrap;
 
1134
  }
1135
 
1136
  .schedule-palette-card {
1137
- min-width: 200px;
1138
  padding: 16px 18px;
1139
  border-radius: 20px;
1140
  border: 1px solid rgba(255, 255, 255, 0.08);
1141
- background: linear-gradient(180deg, rgba(255, 255, 255, 0.06) 0%, rgba(255, 255, 255, 0.03) 100%);
1142
  display: grid;
1143
  gap: 6px;
1144
  cursor: grab;
1145
  }
1146
 
1147
  .schedule-palette-card.class {
1148
- box-shadow: inset 4px 0 0 rgba(123, 231, 234, 0.78);
1149
  }
1150
 
1151
  .schedule-palette-card.break {
1152
- box-shadow: inset 4px 0 0 rgba(255, 200, 87, 0.72);
1153
  }
1154
 
1155
  .schedule-editor-shell {
1156
  display: grid;
1157
- grid-template-columns: 92px minmax(0, 1fr);
1158
- gap: 14px;
1159
  margin-top: 18px;
1160
  }
1161
 
1162
  .schedule-editor-axis,
1163
  .schedule-editor-track {
1164
  position: relative;
1165
- min-height: 760px;
1166
  }
1167
 
1168
  .schedule-editor-axis {
@@ -1170,13 +976,10 @@ body.planner-interacting .page-planner {
1170
  }
1171
 
1172
  .schedule-editor-track {
1173
- border-radius: 24px;
1174
- background:
1175
- linear-gradient(180deg, rgba(255, 255, 255, 0.02) 0%, rgba(255, 255, 255, 0.01) 100%),
1176
- rgba(3, 11, 20, 0.42);
1177
  border: 1px solid rgba(255, 255, 255, 0.06);
1178
  overflow: hidden;
1179
- min-height: 980px;
1180
  }
1181
 
1182
  .schedule-editor-tick,
@@ -1190,8 +993,8 @@ body.planner-interacting .page-planner {
1190
  transform: translateY(-50%);
1191
  padding-right: 12px;
1192
  text-align: right;
1193
- color: rgba(238, 244, 251, 0.78);
1194
- font-size: 0.8rem;
1195
  font-variant-numeric: tabular-nums;
1196
  }
1197
 
@@ -1214,18 +1017,18 @@ body.planner-interacting .page-planner {
1214
  position: absolute;
1215
  left: 14px;
1216
  right: 14px;
1217
- border-radius: 18px;
1218
  border: 1px solid rgba(255, 255, 255, 0.08);
1219
- box-shadow: 0 16px 30px rgba(0, 0, 0, 0.2);
1220
  overflow: hidden;
1221
  }
1222
 
1223
  .schedule-editor-segment.class {
1224
- background: linear-gradient(180deg, rgba(123, 231, 234, 0.16) 0%, rgba(255, 255, 255, 0.05) 100%);
1225
  }
1226
 
1227
  .schedule-editor-segment.break {
1228
- background: linear-gradient(180deg, rgba(255, 200, 87, 0.14) 0%, rgba(255, 255, 255, 0.04) 100%);
1229
  }
1230
 
1231
  .schedule-editor-segment-copy {
@@ -1236,7 +1039,7 @@ body.planner-interacting .page-planner {
1236
 
1237
  .schedule-editor-segment-copy strong {
1238
  font-size: 0.94rem;
1239
- line-height: 1.15;
1240
  }
1241
 
1242
  .schedule-editor-segment-copy span,
@@ -1287,10 +1090,7 @@ body.planner-interacting .page-planner {
1287
  display: none;
1288
  }
1289
 
1290
- .schedule-editor-segment.break.is-tight .schedule-editor-segment-copy span {
1291
- display: none;
1292
- }
1293
-
1294
  .schedule-editor-segment.break.is-tight .schedule-editor-segment-copy strong {
1295
  display: none;
1296
  }
@@ -1303,8 +1103,8 @@ body.planner-interacting .page-planner {
1303
  padding: 0 10px;
1304
  border: 0;
1305
  border-radius: 999px;
1306
- background: rgba(255, 107, 92, 0.16);
1307
- color: #ff9388;
1308
  }
1309
 
1310
  .schedule-editor-resize {
@@ -1315,79 +1115,46 @@ body.planner-interacting .page-planner {
1315
  height: 8px;
1316
  border: 0;
1317
  border-radius: 999px;
1318
- background: linear-gradient(90deg, rgba(255, 255, 255, 0.85), rgba(123, 231, 234, 0.9));
1319
- cursor: ns-resize;
1320
  }
1321
 
1322
  .schedule-editor-dropzone {
1323
  position: absolute;
1324
  left: 14px;
1325
  right: 14px;
1326
- bottom: 14px;
1327
- min-height: 64px;
1328
- border-radius: 18px;
1329
- border: 1px dashed rgba(123, 231, 234, 0.35);
1330
  display: grid;
1331
  place-items: center;
1332
- color: var(--muted);
1333
- background: rgba(123, 231, 234, 0.05);
1334
  text-align: center;
1335
- padding: 12px;
 
1336
  pointer-events: none;
1337
  }
1338
 
1339
  .schedule-editor-dropzone.is-active {
1340
- border-color: rgba(123, 231, 234, 0.75);
1341
- background: rgba(123, 231, 234, 0.12);
1342
  color: var(--muted-strong);
1343
  }
1344
 
1345
- @media (max-width: 1180px) {
1346
- body {
1347
- overflow: auto;
1348
- }
1349
-
1350
  .layout.story-layout {
1351
- min-height: auto;
1352
- }
1353
-
1354
- .story-shell {
1355
- min-height: auto;
1356
- }
1357
-
1358
- .story-toolbar,
1359
- .planner-head,
1360
- .planner-layout {
1361
- grid-template-columns: 1fr;
1362
- flex-direction: column;
1363
- align-items: stretch;
1364
- }
1365
-
1366
- .story-nav {
1367
- justify-self: stretch;
1368
- justify-content: center;
1369
- }
1370
-
1371
- .admin-schedule-grid {
1372
- grid-template-columns: 1fr;
1373
  }
1374
 
 
 
 
1375
  .admin-lists-grid,
1376
  .course-management-grid {
1377
  grid-template-columns: 1fr;
1378
  }
1379
 
1380
- .schedule-form-card {
1381
- position: static;
1382
- }
1383
-
1384
- .list-create-card,
1385
- .course-editor-card {
1386
- position: static;
1387
- }
1388
-
1389
- .admin-page-nav {
1390
- flex-wrap: wrap;
1391
  }
1392
 
1393
  .admin-layout-v2 .admin-hero {
@@ -1398,28 +1165,37 @@ body.planner-interacting .page-planner {
1398
  .admin-page-nav {
1399
  justify-self: stretch;
1400
  }
 
1401
 
1402
- .page-viewport,
 
 
 
 
 
 
 
1403
  .page-track,
1404
  .page-slide,
 
 
1405
  .planner-shell {
1406
  height: auto;
 
1407
  }
1408
- }
1409
 
1410
- @media (max-width: 840px) {
1411
- .page-home,
1412
- .page-planner {
1413
- padding: 0;
1414
  }
1415
 
1416
- .planner-shell {
1417
- min-height: auto;
1418
- padding: 18px;
1419
  }
1420
 
1421
- .timeline-scroll {
1422
- height: auto;
1423
  }
1424
 
1425
  .schedule-editor-shell {
@@ -1435,33 +1211,12 @@ body.planner-interacting .page-planner {
1435
  justify-items: start;
1436
  justify-content: flex-start;
1437
  }
1438
- }
1439
 
1440
- @media (max-width: 560px) {
1441
- .story-toolbar {
1442
- padding: 14px;
1443
- border-radius: 22px;
1444
- }
1445
-
1446
- .story-nav {
1447
- flex-wrap: wrap;
1448
- }
1449
-
1450
- .story-tab {
1451
- width: 100%;
1452
- }
1453
-
1454
- .planner-shell,
1455
- .planner-sidebar,
1456
- .timeline-surface {
1457
- border-radius: 22px;
1458
- }
1459
-
1460
- .planner-controls {
1461
- flex-wrap: wrap;
1462
  }
1463
 
1464
- .planner-date-picker {
1465
- min-width: 100%;
1466
  }
1467
  }
 
1
+ .story-layout {
 
 
 
 
 
 
 
 
2
  padding-top: 0;
3
  overflow: hidden;
4
  }
5
 
6
+ .layout.story-layout {
7
+ width: min(1560px, calc(100% - 22px));
8
+ height: calc(100vh - 24px);
9
+ min-height: calc(100vh - 24px);
10
+ max-height: calc(100vh - 24px);
11
+ padding: 12px 0;
12
+ }
13
+
14
  .story-shell {
15
  display: grid;
16
+ gap: 14px;
 
17
  height: 100%;
18
  min-height: 0;
19
  grid-template-rows: auto minmax(0, 1fr);
20
  }
21
 
22
  .story-toolbar {
 
 
23
  display: grid;
24
  grid-template-columns: auto 1fr auto;
 
25
  align-items: center;
26
+ gap: 20px;
27
+ padding: 14px 18px;
28
+ border-radius: 28px;
29
  }
30
 
31
  .story-nav {
 
32
  justify-self: center;
33
+ display: inline-grid;
34
+ grid-auto-flow: column;
35
+ gap: 6px;
36
  padding: 6px;
37
  border-radius: 999px;
38
  background: rgba(255, 255, 255, 0.05);
 
39
  }
40
 
41
  .story-tab {
42
+ min-height: 40px;
43
+ padding: 0 16px;
44
  border: 0;
45
+ border-radius: 14px;
46
  background: transparent;
47
  color: var(--muted-strong);
48
+ font-weight: 700;
49
+ letter-spacing: -0.02em;
50
  }
51
 
52
  .story-tab.is-active {
53
+ background: linear-gradient(135deg, rgba(124, 215, 209, 0.18) 0%, rgba(124, 215, 209, 0.08) 100%);
54
  color: var(--text);
55
+ box-shadow: inset 0 0 0 1px rgba(124, 215, 209, 0.18);
56
+ }
57
+
58
+ .story-actions {
59
+ justify-self: end;
60
  }
61
 
62
  .page-viewport {
63
  position: relative;
64
  width: 100%;
 
 
65
  height: 100%;
66
+ min-height: 0;
67
+ overflow: hidden;
68
  }
69
 
70
  .page-track {
71
  display: flex;
 
72
  height: 100%;
73
  align-items: stretch;
74
  transition: transform 720ms cubic-bezier(0.22, 1, 0.36, 1);
 
78
  .page-slide {
79
  flex: 0 0 100%;
80
  width: 100%;
 
81
  min-width: 100%;
82
+ max-width: 100%;
83
+ height: 100%;
84
+ min-height: 0;
85
  overflow: hidden;
86
  pointer-events: none;
 
 
87
  }
88
 
89
  .page-slide.is-active {
 
96
  -webkit-user-select: none !important;
97
  }
98
 
 
 
 
 
 
 
 
 
99
  .page-home {
100
  display: grid;
101
+ gap: 14px;
102
+ grid-template-rows: minmax(244px, 31vh) minmax(0, 1fr);
 
103
  min-height: 0;
104
  height: 100%;
 
105
  }
106
 
107
+ .hero-clock-card {
108
+ position: relative;
109
+ display: grid;
110
+ place-items: center;
111
+ padding: 26px 28px;
112
  overflow: hidden;
113
  }
114
 
115
+ .hero-orbit {
116
+ position: absolute;
117
+ border-radius: 50%;
118
+ border: 1px solid rgba(255, 255, 255, 0.08);
119
+ pointer-events: none;
120
  }
121
 
122
+ .hero-orbit-a {
123
+ width: 46vw;
124
+ height: 46vw;
125
+ max-width: 540px;
126
+ max-height: 540px;
127
+ top: -58%;
128
+ left: -8%;
129
+ opacity: 0.26;
130
  }
131
 
132
+ .hero-orbit-b {
133
+ width: 34vw;
134
+ height: 34vw;
135
+ max-width: 420px;
136
+ max-height: 420px;
137
+ right: -8%;
138
+ bottom: -62%;
139
+ opacity: 0.22;
 
140
  }
141
 
142
+ .hero-clock-card .clock-wrap {
143
+ position: relative;
144
+ z-index: 1;
145
  }
146
 
147
+ .hero-clock-card .clock-display {
148
+ font-size: clamp(3.8rem, 8vw, 6.8rem);
 
149
  }
150
 
151
+ .hero-clock-card .clock-meta {
152
+ gap: 12px;
 
153
  }
154
 
155
  .board-section {
 
 
 
156
  min-height: 0;
157
+ display: grid;
 
 
 
 
158
  grid-template-rows: minmax(0, 1fr);
159
+ overflow: hidden;
160
  }
161
 
162
+ .board-section > .section-header {
163
  display: none;
164
  }
165
 
 
 
 
 
 
 
 
 
166
  .board-grid {
167
  display: grid;
168
+ grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.96fr) minmax(0, 1fr);
169
+ gap: 14px;
 
 
 
 
170
  height: 100%;
171
+ min-height: 0;
172
+ align-items: stretch;
173
  }
174
 
175
  .todo-column {
 
 
 
 
176
  position: relative;
 
177
  display: grid;
178
  grid-template-rows: auto minmax(0, 1fr);
179
+ min-height: 0;
180
+ padding: 18px;
181
+ overflow: visible;
182
+ border-radius: 28px;
183
  }
184
 
185
+ .todo-column:nth-child(2) {
186
+ transform: translateY(10px);
 
 
 
 
187
  }
188
 
189
+ .todo-column:nth-child(3) {
190
+ transform: translateY(24px);
191
  }
192
 
193
+ .column-header {
194
+ position: relative;
195
+ display: grid;
196
+ grid-template-columns: minmax(0, 1fr) auto;
197
+ align-items: start;
198
+ gap: 12px;
199
+ min-height: 60px;
200
+ z-index: 10;
201
  }
202
 
203
+ .column-header-copy {
204
+ min-width: 0;
205
+ }
206
+
207
+ .column-title {
208
+ margin: 8px 0 0;
209
+ font-size: 1.6rem;
210
+ letter-spacing: -0.05em;
211
+ line-height: 1.02;
212
  }
213
 
214
+ .column-actions {
215
+ gap: 8px;
216
+ justify-self: end;
217
+ z-index: 30;
218
  }
219
 
220
  .task-list {
221
  display: flex;
222
  flex-direction: column;
223
+ gap: 12px;
 
224
  min-height: 0;
 
225
  max-height: 100%;
226
  overflow-y: auto;
227
  overscroll-behavior: contain;
228
+ padding-right: 2px;
229
  }
230
 
231
+ .page-planner {
232
+ min-height: 0;
233
+ height: 100%;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
  }
235
 
236
  .planner-shell {
237
+ display: grid;
238
+ grid-template-rows: auto auto minmax(0, 1fr);
239
+ gap: 10px;
240
  height: 100%;
241
+ min-height: 0;
242
+ padding: 18px;
243
+ border-radius: 30px;
244
  overflow: hidden;
245
+ }
246
+
247
+ .planner-head {
248
  display: grid;
249
+ grid-template-columns: minmax(0, 1fr) auto;
250
+ gap: 16px;
251
+ align-items: end;
252
  }
253
 
254
+ .planner-head-copy h2 {
255
  margin: 4px 0 0;
256
+ font-size: clamp(1.65rem, 2vw, 2.2rem);
257
+ letter-spacing: -0.05em;
258
  }
259
 
260
+ .planner-head-copy .section-note {
261
+ margin-top: 6px;
262
+ max-width: 720px;
263
  }
264
 
265
+ .planner-controls {
 
 
 
 
 
 
 
266
  display: flex;
267
  align-items: center;
 
 
 
 
 
 
 
 
 
268
  gap: 8px;
269
  }
270
 
271
  .planner-date-picker {
272
  display: grid;
273
  gap: 6px;
274
+ min-width: 188px;
275
  }
276
 
277
  .planner-date-picker span {
278
  color: var(--muted);
279
+ font-size: 0.76rem;
280
+ letter-spacing: 0.08em;
281
+ text-transform: uppercase;
 
 
 
 
 
 
 
 
 
282
  }
283
 
284
  .planner-meta {
285
+ display: flex;
286
  flex-wrap: wrap;
287
  gap: 8px;
288
  }
 
292
  .planner-task-category {
293
  display: inline-flex;
294
  align-items: center;
295
+ min-height: 32px;
296
+ padding: 0 12px;
297
  border-radius: 999px;
298
  background: rgba(255, 255, 255, 0.06);
299
  color: var(--muted-strong);
300
+ font-size: 0.8rem;
301
  }
302
 
303
  .planner-layout {
304
  display: grid;
305
+ grid-template-columns: minmax(0, 8.7fr) minmax(260px, 1.75fr);
306
+ gap: 14px;
307
  min-height: 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
  }
309
 
310
  .timeline-surface,
311
+ .planner-sidebar,
312
+ .card-surface-soft {
313
+ border-radius: 28px;
314
+ border: 1px solid rgba(255, 255, 255, 0.06);
315
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.04) 0%, rgba(255, 255, 255, 0.02) 100%);
316
+ backdrop-filter: blur(18px) saturate(125%);
317
  }
318
 
319
  .timeline-surface {
320
+ padding: 12px;
321
  min-height: 0;
 
322
  }
323
 
324
  .timeline-scroll {
 
325
  height: 100%;
 
326
  min-height: 0;
327
+ overflow: hidden;
328
+ border-radius: 22px;
329
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.02) 0%, rgba(0, 0, 0, 0.08) 100%);
330
  }
331
 
332
  .timeline-grid {
 
342
  .timeline-now-line {
343
  position: absolute;
344
  top: 0;
 
 
 
 
 
 
 
 
345
  bottom: auto;
346
  }
347
 
 
367
  top: 0;
368
  display: grid;
369
  grid-template-columns: repeat(7, minmax(0, 1fr));
370
+ gap: 8px;
371
+ z-index: 8;
372
  }
373
 
374
  .timeline-day-head {
375
+ min-height: 54px;
376
+ border-radius: 18px;
377
  border: 1px solid rgba(255, 255, 255, 0.08);
 
378
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0.03) 100%);
379
  color: var(--muted-strong);
380
  display: grid;
381
  place-items: center;
382
  gap: 2px;
383
+ padding: 6px 4px;
384
  text-align: center;
 
385
  }
386
 
387
  .timeline-day-head strong {
388
+ font-size: 0.84rem;
 
389
  }
390
 
391
  .timeline-day-head span {
392
+ font-size: 0.7rem;
393
  color: var(--muted);
 
394
  }
395
 
396
  .timeline-day-head.is-selected {
397
+ border-color: rgba(124, 215, 209, 0.4);
398
+ background: linear-gradient(180deg, rgba(124, 215, 209, 0.18) 0%, rgba(124, 215, 209, 0.06) 100%);
399
  }
400
 
401
  .timeline-day-head.is-today {
402
+ box-shadow: inset 0 0 0 1px rgba(174, 111, 72, 0.18);
403
  }
404
 
405
  .timeline-day-column,
 
411
  }
412
 
413
  .timeline-day-column {
414
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.016) 0%, rgba(255, 255, 255, 0.004) 100%);
415
  }
416
 
417
  .timeline-day-column.is-selected {
418
+ background: linear-gradient(180deg, rgba(124, 215, 209, 0.06) 0%, rgba(124, 215, 209, 0.01) 100%);
 
 
 
 
419
  }
420
 
421
  .timeline-day-divider {
422
  width: 1px;
423
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0.09), rgba(255, 255, 255, 0.02));
424
  }
425
 
426
  .timeline-axis-rail {
427
  position: absolute;
428
  top: 0;
429
  bottom: 0;
430
+ right: 12px;
431
  width: 1px;
432
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(124, 215, 209, 0.18), rgba(255, 255, 255, 0.05));
433
  }
434
 
435
  .timeline-axis-tick {
 
437
  left: 0;
438
  right: 0;
439
  display: flex;
 
440
  align-items: center;
441
+ justify-content: flex-end;
442
  gap: 10px;
443
  transform: translateY(-50%);
444
+ padding-right: 18px;
445
+ color: var(--muted);
446
+ font-size: 0.74rem;
447
  font-variant-numeric: tabular-nums;
 
 
 
448
  }
449
 
450
  .timeline-axis-tick::after {
451
  content: "";
452
  width: 7px;
453
  height: 7px;
454
+ border-radius: 50%;
455
+ background: rgba(124, 215, 209, 0.78);
456
+ box-shadow: 0 0 0 5px rgba(124, 215, 209, 0.08);
 
457
  }
458
 
459
  .timeline-axis-tick.is-leading {
 
468
  position: absolute;
469
  left: 6px;
470
  right: 8px;
471
+ padding: 6px 9px;
472
+ border-radius: 16px;
473
+ border: 1px solid rgba(255, 255, 255, 0.06);
474
+ background: rgba(255, 255, 255, 0.04);
475
+ display: grid;
 
 
 
 
476
  gap: 3px;
 
477
  }
478
 
479
  .timeline-slot-band strong {
480
  font-size: 0.74rem;
 
481
  }
482
 
483
  .timeline-slot-band span {
484
  color: var(--muted);
485
+ font-size: 0.66rem;
 
 
486
  }
487
 
488
  .timeline-line {
 
493
  }
494
 
495
  .timeline-line.is-slot {
496
+ background: rgba(255, 255, 255, 0.06);
497
  }
498
 
499
  .timeline-major-block {
500
  position: absolute;
501
  left: 0;
502
  right: 0;
503
+ border-radius: 18px;
504
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.026) 0%, rgba(255, 255, 255, 0.008) 100%);
 
505
  pointer-events: none;
506
  }
507
 
508
  .timeline-major-block span {
509
  position: absolute;
510
  top: 10px;
511
+ right: 14px;
512
+ font-size: clamp(0.96rem, 1.2vw, 1.34rem);
513
+ color: rgba(255, 255, 255, 0.14);
514
+ font-weight: 800;
515
+ letter-spacing: -0.05em;
516
  }
517
 
518
  .planner-event,
519
  .timeline-drop-preview {
520
  position: absolute;
521
+ border-radius: 18px;
 
 
522
  padding: 10px 12px 12px;
523
+ border: 1px solid rgba(255, 255, 255, 0.07);
524
+ background: linear-gradient(180deg, rgba(15, 25, 34, 0.96) 0%, rgba(11, 19, 27, 0.92) 100%);
525
+ box-shadow: 0 16px 34px rgba(0, 0, 0, 0.24);
526
+ overflow: hidden;
527
  }
528
 
529
  .planner-event {
530
  touch-action: none;
 
531
  }
532
 
533
  .planner-event::before,
 
536
  position: absolute;
537
  inset: 0 auto 0 0;
538
  width: 4px;
539
+ border-radius: 18px 0 0 18px;
540
+ background: var(--event-accent, var(--accent));
541
  }
542
 
543
  .planner-event-top,
 
561
 
562
  .planner-course-stack {
563
  display: grid;
564
+ gap: 3px;
565
  min-height: 100%;
566
  }
567
 
568
  .planner-course-title {
 
569
  margin: 0;
570
+ font-size: 0.76rem;
571
  line-height: 1.12;
572
+ letter-spacing: -0.02em;
 
 
573
  display: -webkit-box;
574
  -webkit-box-orient: vertical;
575
  -webkit-line-clamp: 2;
576
+ overflow: hidden;
577
  }
578
 
579
  .planner-course-details {
580
  display: grid;
581
  gap: 1px;
 
582
  font-size: 0.58rem;
583
+ line-height: 1.14;
584
+ color: var(--muted-strong);
585
  }
586
 
587
  .planner-course-line {
 
 
588
  overflow-wrap: anywhere;
 
589
  }
590
 
 
591
  .planner-event-clear,
592
  .planner-task-clear {
593
+ min-height: 28px;
 
 
 
594
  padding: 0 10px;
595
  border-radius: 999px;
596
  border: 0;
597
+ background: rgba(196, 91, 87, 0.16);
598
+ color: var(--danger);
 
 
 
 
 
 
 
 
 
 
599
  }
600
 
601
  .planner-event-resize {
 
604
  right: 8px;
605
  height: 8px;
606
  border-radius: 999px;
607
+ background: linear-gradient(90deg, rgba(255, 255, 255, 0.88), rgba(124, 215, 209, 0.92));
 
 
608
  }
609
 
610
  .planner-event-resize-top {
 
617
 
618
  .planner-event.is-dragging,
619
  .planner-task-card.is-dragging {
620
+ opacity: 0.86;
621
  }
622
 
623
  .planner-event.is-dragging {
 
626
 
627
  .planner-event.is-conflict,
628
  .timeline-drop-preview.is-conflict {
629
+ border-color: rgba(196, 91, 87, 0.72);
 
630
  }
631
 
632
  .planner-event.is-conflict::before,
633
  .timeline-drop-preview.is-conflict::before {
634
+ background: var(--danger);
635
  }
636
 
637
  .course-event {
638
+ padding: 8px 9px 9px 11px;
639
  }
640
 
641
  .planner-event.is-compact {
642
+ padding: 7px 9px 8px;
 
 
 
 
 
 
 
 
 
 
643
  }
644
 
645
  .task-event.is-compact .planner-event-meta,
 
647
  display: none;
648
  }
649
 
 
 
 
 
 
 
 
 
 
 
 
 
650
  .course-event.is-compact .planner-course-details {
 
651
  font-size: 0.54rem;
652
  }
653
 
 
657
 
658
  .planner-event.is-tight .planner-event-meta,
659
  .planner-event.is-tight .planner-event-clear,
 
660
  .planner-event.is-tight .planner-event-time {
661
  display: none;
662
  }
 
666
  }
667
 
668
  .course-event.is-tight .planner-course-title {
669
+ font-size: 0.64rem;
 
 
 
 
 
670
  }
671
 
672
+ .planner-sidebar {
673
+ display: grid;
674
+ grid-template-rows: auto auto minmax(0, 1fr);
675
+ gap: 12px;
676
+ min-height: 0;
677
+ padding: 16px;
678
  }
679
 
680
+ .planner-sidebar-head {
681
+ display: flex;
682
+ align-items: start;
683
+ justify-content: space-between;
684
+ gap: 12px;
685
  }
686
 
687
+ .planner-sidebar-head h3 {
688
+ margin: 6px 0 0;
689
+ font-size: 1.4rem;
690
+ line-height: 1.02;
691
+ letter-spacing: -0.05em;
 
 
 
692
  }
693
 
694
  .planner-sidebar-note {
695
  display: grid;
696
  gap: 6px;
697
+ font-size: 0.82rem;
698
  color: var(--muted);
 
699
  }
700
 
701
  .planner-task-pool {
 
703
  flex-direction: column;
704
  gap: 12px;
705
  min-height: 0;
 
 
706
  overflow-y: auto;
707
+ padding-right: 2px;
 
708
  }
709
 
710
  .planner-task-card {
 
 
 
 
711
  display: grid;
712
  gap: 12px;
713
+ padding: 14px;
714
+ border-radius: 22px;
715
+ border: 1px solid rgba(255, 255, 255, 0.06);
716
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0.03) 100%);
717
  }
718
 
719
  .planner-task-card h4 {
 
740
  }
741
 
742
  .planner-task-tags span {
743
+ min-height: 32px;
744
+ padding: 0 10px;
745
  border-radius: 999px;
746
+ display: inline-flex;
747
+ align-items: center;
748
  background: rgba(255, 255, 255, 0.05);
749
  color: var(--muted-strong);
750
  font-size: 0.76rem;
 
757
  grid-column: 1 / -1;
758
  }
759
 
760
+ .card-surface-soft {
761
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.05) 0%, rgba(255, 255, 255, 0.02) 100%);
 
 
 
 
 
 
 
 
 
 
762
  }
763
 
764
  .timeline-drop-preview {
 
767
  align-content: center;
768
  color: var(--muted-strong);
769
  border-style: dashed;
770
+ background: rgba(124, 215, 209, 0.08);
 
 
 
 
 
 
 
 
 
 
 
771
  }
772
 
773
  .timeline-now-line {
774
  position: absolute;
775
  height: 2px;
776
+ background: linear-gradient(90deg, rgba(196, 91, 87, 0.95), rgba(211, 155, 112, 0.72));
 
777
  z-index: 6;
778
  pointer-events: none;
779
  }
 
785
  top: -5px;
786
  width: 12px;
787
  height: 12px;
788
+ border-radius: 50%;
789
+ background: var(--danger);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
790
  }
791
 
792
  .admin-layout-v2 {
793
+ width: min(1540px, calc(100% - 28px));
794
  }
795
 
796
  .admin-layout-v2 .admin-hero {
797
  display: grid;
798
  grid-template-columns: minmax(0, 1fr) auto;
799
  align-items: start;
800
+ gap: 20px 26px;
801
  }
802
 
803
  .admin-layout-v2 .admin-hero > div:first-child {
 
806
 
807
  .admin-layout-v2 .action-group {
808
  justify-self: end;
 
809
  }
810
 
811
  .admin-page-nav {
 
818
  }
819
 
820
  .admin-page-tab {
821
+ min-height: 40px;
822
  padding: 0 16px;
823
+ border-radius: 14px;
824
  display: inline-flex;
825
  align-items: center;
826
  justify-content: center;
827
  color: var(--muted-strong);
828
+ font-weight: 700;
829
  }
830
 
831
  .admin-page-tab.is-active {
832
+ background: linear-gradient(135deg, rgba(124, 215, 209, 0.18) 0%, rgba(124, 215, 209, 0.08) 100%);
833
  color: var(--text);
834
  }
835
 
836
+ .admin-section {
837
+ margin-top: 24px;
838
+ }
839
+
840
+ .admin-grid-tight {
841
+ gap: 18px;
842
+ }
843
+
844
  .admin-stack {
845
  display: grid;
846
  gap: 16px;
 
850
  padding: 20px 22px;
851
  }
852
 
 
 
 
 
853
  .admin-lists-grid {
854
+ grid-template-columns: minmax(320px, 380px) minmax(0, 1fr);
855
  align-items: start;
856
  }
857
 
858
+ .list-create-card,
859
+ .course-editor-card,
860
+ .schedule-form-card {
861
  position: sticky;
862
+ top: 24px;
 
 
 
 
863
  }
864
 
865
  .list-row-card {
866
+ border-radius: 28px;
867
  }
868
 
869
  .admin-row-main {
 
880
  }
881
 
882
  .course-management-grid {
883
+ grid-template-columns: minmax(340px, 390px) minmax(0, 1fr);
884
  align-items: start;
885
  }
886
 
 
 
 
 
 
887
  .course-row-head {
888
  align-items: start;
889
  margin-bottom: 2px;
 
907
  }
908
 
909
  .course-card h2 {
910
+ font-size: 1.1rem;
911
  }
912
 
913
  .course-card .admin-card-copy {
914
  margin: 1px 0 0;
915
  font-size: 0.78rem;
916
+ line-height: 1.22;
917
  }
918
 
919
  .course-row-actions .secondary-button,
 
921
  .course-row-actions .task-count {
922
  min-height: 34px;
923
  padding: 0 10px;
924
+ font-size: 0.8rem;
925
  }
926
 
927
  .admin-schedule-grid {
928
+ grid-template-columns: minmax(320px, 390px) minmax(0, 1fr);
929
  align-items: start;
930
  }
931
 
 
 
 
 
 
932
  .schedule-editor-card {
933
  padding: 22px;
934
  }
 
936
  .schedule-palette {
937
  display: flex;
938
  gap: 12px;
 
939
  flex-wrap: wrap;
940
+ margin-top: 16px;
941
  }
942
 
943
  .schedule-palette-card {
944
+ min-width: 220px;
945
  padding: 16px 18px;
946
  border-radius: 20px;
947
  border: 1px solid rgba(255, 255, 255, 0.08);
948
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0.03) 100%);
949
  display: grid;
950
  gap: 6px;
951
  cursor: grab;
952
  }
953
 
954
  .schedule-palette-card.class {
955
+ box-shadow: inset 4px 0 0 rgba(124, 215, 209, 0.78);
956
  }
957
 
958
  .schedule-palette-card.break {
959
+ box-shadow: inset 4px 0 0 rgba(211, 155, 112, 0.72);
960
  }
961
 
962
  .schedule-editor-shell {
963
  display: grid;
964
+ grid-template-columns: 96px minmax(0, 1fr);
965
+ gap: 16px;
966
  margin-top: 18px;
967
  }
968
 
969
  .schedule-editor-axis,
970
  .schedule-editor-track {
971
  position: relative;
 
972
  }
973
 
974
  .schedule-editor-axis {
 
976
  }
977
 
978
  .schedule-editor-track {
979
+ border-radius: 26px;
980
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.03) 0%, rgba(255, 255, 255, 0.01) 100%);
 
 
981
  border: 1px solid rgba(255, 255, 255, 0.06);
982
  overflow: hidden;
 
983
  }
984
 
985
  .schedule-editor-tick,
 
993
  transform: translateY(-50%);
994
  padding-right: 12px;
995
  text-align: right;
996
+ color: var(--muted-strong);
997
+ font-size: 0.86rem;
998
  font-variant-numeric: tabular-nums;
999
  }
1000
 
 
1017
  position: absolute;
1018
  left: 14px;
1019
  right: 14px;
1020
+ border-radius: 20px;
1021
  border: 1px solid rgba(255, 255, 255, 0.08);
1022
+ box-shadow: var(--shadow-sm);
1023
  overflow: hidden;
1024
  }
1025
 
1026
  .schedule-editor-segment.class {
1027
+ background: linear-gradient(180deg, rgba(124, 215, 209, 0.16) 0%, rgba(124, 215, 209, 0.06) 100%);
1028
  }
1029
 
1030
  .schedule-editor-segment.break {
1031
+ background: linear-gradient(180deg, rgba(211, 155, 112, 0.14) 0%, rgba(211, 155, 112, 0.06) 100%);
1032
  }
1033
 
1034
  .schedule-editor-segment-copy {
 
1039
 
1040
  .schedule-editor-segment-copy strong {
1041
  font-size: 0.94rem;
1042
+ line-height: 1.12;
1043
  }
1044
 
1045
  .schedule-editor-segment-copy span,
 
1090
  display: none;
1091
  }
1092
 
1093
+ .schedule-editor-segment.break.is-tight .schedule-editor-segment-copy span,
 
 
 
1094
  .schedule-editor-segment.break.is-tight .schedule-editor-segment-copy strong {
1095
  display: none;
1096
  }
 
1103
  padding: 0 10px;
1104
  border: 0;
1105
  border-radius: 999px;
1106
+ background: rgba(196, 91, 87, 0.16);
1107
+ color: var(--danger);
1108
  }
1109
 
1110
  .schedule-editor-resize {
 
1115
  height: 8px;
1116
  border: 0;
1117
  border-radius: 999px;
1118
+ background: linear-gradient(90deg, rgba(255, 255, 255, 0.9), rgba(124, 215, 209, 0.92));
 
1119
  }
1120
 
1121
  .schedule-editor-dropzone {
1122
  position: absolute;
1123
  left: 14px;
1124
  right: 14px;
1125
+ min-height: 72px;
1126
+ border-radius: 20px;
1127
+ border: 1px dashed rgba(124, 215, 209, 0.36);
 
1128
  display: grid;
1129
  place-items: center;
1130
+ padding: 14px;
 
1131
  text-align: center;
1132
+ color: var(--muted);
1133
+ background: rgba(124, 215, 209, 0.05);
1134
  pointer-events: none;
1135
  }
1136
 
1137
  .schedule-editor-dropzone.is-active {
1138
+ border-color: rgba(124, 215, 209, 0.72);
 
1139
  color: var(--muted-strong);
1140
  }
1141
 
1142
+ @media (max-width: 1280px) {
 
 
 
 
1143
  .layout.story-layout {
1144
+ width: min(100% - 20px, 1560px);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1145
  }
1146
 
1147
+ .board-grid,
1148
+ .planner-layout,
1149
+ .admin-schedule-grid,
1150
  .admin-lists-grid,
1151
  .course-management-grid {
1152
  grid-template-columns: 1fr;
1153
  }
1154
 
1155
+ .todo-column:nth-child(2),
1156
+ .todo-column:nth-child(3) {
1157
+ transform: none;
 
 
 
 
 
 
 
 
1158
  }
1159
 
1160
  .admin-layout-v2 .admin-hero {
 
1165
  .admin-page-nav {
1166
  justify-self: stretch;
1167
  }
1168
+ }
1169
 
1170
+ @media (max-width: 840px) {
1171
+ .layout.story-layout {
1172
+ height: auto;
1173
+ min-height: auto;
1174
+ max-height: none;
1175
+ }
1176
+
1177
+ .story-shell,
1178
  .page-track,
1179
  .page-slide,
1180
+ .page-home,
1181
+ .page-planner,
1182
  .planner-shell {
1183
  height: auto;
1184
+ min-height: auto;
1185
  }
 
1186
 
1187
+ .story-toolbar,
1188
+ .planner-head {
1189
+ grid-template-columns: 1fr;
 
1190
  }
1191
 
1192
+ .story-nav {
1193
+ justify-self: stretch;
1194
+ grid-auto-flow: row;
1195
  }
1196
 
1197
+ .planner-head {
1198
+ align-items: start;
1199
  }
1200
 
1201
  .schedule-editor-shell {
 
1211
  justify-items: start;
1212
  justify-content: flex-start;
1213
  }
 
1214
 
1215
+ .planner-task-tags {
1216
+ grid-template-columns: 1fr;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1217
  }
1218
 
1219
+ .planner-task-tags span:last-child {
1220
+ grid-column: auto;
1221
  }
1222
  }
templates/admin.html CHANGED
@@ -1,4 +1,4 @@
1
- {% extends "base.html" %}
2
  {% block title %}DRM | 后台管理{% endblock %}
3
  {% block head %}
4
  <link rel="stylesheet" href="{{ url_for('static', filename='v020.css') }}">
@@ -13,7 +13,7 @@
13
  <p class="admin-copy">通过拖拽上课块和课间块,重新安排整套节次时间。保存后首页与周课表会自动同步。</p>
14
  {% elif admin_page == "lists" %}
15
  <h1>清单管理</h1>
16
- <p class="admin-copy">统一维护首页的 todolist 分类,删除或新建会即时反映到主页。</p>
17
  {% else %}
18
  <h1>课程管理</h1>
19
  <p class="admin-copy">左侧新增或编辑课程,右侧用竖直列表快速检查全周课程配置。</p>
@@ -78,20 +78,20 @@
78
  <div class="schedule-palette" id="schedulePalette">
79
  <div class="schedule-palette-card class" draggable="true" data-palette-kind="class">
80
  <strong>上课块</strong>
81
- <span>拖时间轴追加一节课</span>
82
  </div>
83
  <div class="schedule-palette-card break" draggable="true" data-palette-kind="break">
84
  <strong>课间块</strong>
85
- <span>拖时间轴追加一段休息</span>
86
  </div>
87
  </div>
88
 
89
- <p class="admin-card-copy">规则:时间段不能重叠,上课后必须是课间,课间后必须是上课。可调整时长、删除节课,并拖入新块扩展节次。</p>
90
 
91
  <div class="schedule-editor-shell">
92
  <div class="schedule-editor-axis" id="scheduleEditorAxis"></div>
93
  <div class="schedule-editor-track" id="scheduleEditorTrack">
94
- <div class="schedule-editor-dropzone" id="scheduleEditorDropzone">将上课块或课间块拖到这里追加到时间表末尾</div>
95
  </div>
96
  </div>
97
  </article>
@@ -103,7 +103,7 @@
103
  <article class="admin-card create-card list-create-card">
104
  <div class="create-icon">+</div>
105
  <h2>新建一个清单</h2>
106
- <p class="admin-card-copy">清单会直接同步到首页第二页拖拽池。</p>
107
  <form id="createCategoryForm" class="modal-form compact">
108
  <label>
109
  <span>分类名称</span>
 
1
+ {% extends "base.html" %}
2
  {% block title %}DRM | 后台管理{% endblock %}
3
  {% block head %}
4
  <link rel="stylesheet" href="{{ url_for('static', filename='v020.css') }}">
 
13
  <p class="admin-copy">通过拖拽上课块和课间块,重新安排整套节次时间。保存后首页与周课表会自动同步。</p>
14
  {% elif admin_page == "lists" %}
15
  <h1>清单管理</h1>
16
+ <p class="admin-copy">统一维护首页的 todolist 分类,删除或新建会即时反映到主页与拖拽池。</p>
17
  {% else %}
18
  <h1>课程管理</h1>
19
  <p class="admin-copy">左侧新增或编辑课程,右侧用竖直列表快速检查全周课程配置。</p>
 
78
  <div class="schedule-palette" id="schedulePalette">
79
  <div class="schedule-palette-card class" draggable="true" data-palette-kind="class">
80
  <strong>上课块</strong>
81
+ <span>拖时间轴末尾追加一节课</span>
82
  </div>
83
  <div class="schedule-palette-card break" draggable="true" data-palette-kind="break">
84
  <strong>课间块</strong>
85
+ <span>拖时间轴末尾追加一段休息</span>
86
  </div>
87
  </div>
88
 
89
+ <p class="admin-card-copy">规则:时间段不能重叠,上课后必须是课间,课间后必须是上课。支持拖入新块、删除节次、调整时长。</p>
90
 
91
  <div class="schedule-editor-shell">
92
  <div class="schedule-editor-axis" id="scheduleEditorAxis"></div>
93
  <div class="schedule-editor-track" id="scheduleEditorTrack">
94
+ <div class="schedule-editor-dropzone" id="scheduleEditorDropzone">将上课块或课间块拖到这里追加到时间表末尾</div>
95
  </div>
96
  </div>
97
  </article>
 
103
  <article class="admin-card create-card list-create-card">
104
  <div class="create-icon">+</div>
105
  <h2>新建一个清单</h2>
106
+ <p class="admin-card-copy">清单会直接同步到首页第二页拖拽池。</p>
107
  <form id="createCategoryForm" class="modal-form compact">
108
  <label>
109
  <span>分类名称</span>
templates/base.html CHANGED
@@ -1,12 +1,13 @@
1
- <!doctype html>
2
  <html lang="zh-CN">
3
  <head>
4
  <meta charset="utf-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
 
6
  <title>{% block title %}Daily Reminder Master{% endblock %}</title>
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
- <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700;800&family=Sora:wght@400;600;700;800&display=swap" rel="stylesheet">
10
  <link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
11
  {% block head %}{% endblock %}
12
  </head>
@@ -14,6 +15,7 @@
14
  <div class="page-shell">
15
  <div class="ambient ambient-one"></div>
16
  <div class="ambient ambient-two"></div>
 
17
  {% block body %}{% endblock %}
18
  </div>
19
  {% block scripts %}{% endblock %}
 
1
+ <!doctype html>
2
  <html lang="zh-CN">
3
  <head>
4
  <meta charset="utf-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <meta name="color-scheme" content="light dark">
7
  <title>{% block title %}Daily Reminder Master{% endblock %}</title>
8
  <link rel="preconnect" href="https://fonts.googleapis.com">
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
+ <link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&family=Noto+Sans+SC:wght@400;500;700;800&family=IBM+Plex+Mono:wght@400;500;600&display=swap" rel="stylesheet">
11
  <link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
12
  {% block head %}{% endblock %}
13
  </head>
 
15
  <div class="page-shell">
16
  <div class="ambient ambient-one"></div>
17
  <div class="ambient ambient-two"></div>
18
+ <div class="ambient ambient-three"></div>
19
  {% block body %}{% endblock %}
20
  </div>
21
  {% block scripts %}{% endblock %}
templates/index.html CHANGED
@@ -1,4 +1,4 @@
1
- {% extends "base.html" %}
2
  {% block title %}DRM | 提醒主页{% endblock %}
3
  {% block head %}
4
  <link rel="stylesheet" href="{{ url_for('static', filename='v020.css') }}">
@@ -13,14 +13,14 @@
13
  </div>
14
 
15
  <nav class="story-nav" aria-label="页面导航">
16
- <button class="story-tab is-active" type="button" data-go-page="0">第一 · 提醒</button>
17
- <button class="story-tab" type="button" data-go-page="1">第二页 · 周课表</button>
18
  </nav>
19
 
20
- <div class="action-group">
21
- <a class="ghost-link" href="{{ url_for('admin') }}">后台管理</a>
22
  {% if authenticated %}
23
- <button class="pill-button" id="logoutButton" type="button">退出登录</button>
24
  {% else %}
25
  <button class="pill-button accent" id="openLoginButton" type="button">登录后编辑</button>
26
  {% endif %}
@@ -30,37 +30,26 @@
30
  <div class="page-viewport">
31
  <div class="page-track" id="pageTrack">
32
  <section class="page-slide page-home">
33
- <section class="hero-card">
 
 
34
  <div class="clock-wrap">
 
35
  <h1 class="clock-display" id="clockDisplay">00:00:00</h1>
36
  <div class="clock-meta">
37
  <span id="dateDisplay">0000 年 00 月 00 日</span>
38
- <span id="weekdayDisplay">{{ clock_meta.weekday }}</span>
39
  <span id="lunarDisplay">农历加载中</span>
40
  </div>
41
  </div>
42
  </section>
43
 
44
  <section class="board-section">
45
- <div class="section-header">
46
- <div>
47
- <p class="section-kicker">今日待办板</p>
48
- <h2>每个分类一列,压缩留白后在一屏内保持更高信息密度</h2>
49
- </div>
50
- <p class="section-note">
51
- {% if authenticated %}
52
- 已登录,可添加、勾选、重命名,并把任务拖进第二页的周课表。
53
- {% else %}
54
- 当前为只读模式,登录后可进行编辑与拖拽排程。
55
- {% endif %}
56
- </p>
57
- </div>
58
-
59
  <div class="board-grid" id="boardGrid">
60
  {% for category in categories %}
61
  <article class="todo-column card-surface" data-category-id="{{ category.id }}">
62
  <header class="column-header">
63
- <div>
64
  <p class="column-label">Todolist</p>
65
  <h3 class="column-title">{{ category.name }}</h3>
66
  </div>
@@ -116,10 +105,10 @@
116
  <section class="page-slide page-planner">
117
  <section class="planner-shell card-surface">
118
  <div class="planner-head">
119
- <div>
120
- <p class="section-kicker">第二页 · 周课表</p>
121
- <h2>查看课程与任务,把整周安排收进一屏</h2>
122
- <p class="section-note" id="plannerHeadlineNote">固定课程按学期周次自动出现,待办可拖入本周任意一天,并支持上下边缘拉伸;每项任务最短 15 分钟。</p>
123
  </div>
124
  <div class="planner-controls">
125
  <button class="icon-button planner-shift-button" id="plannerPrevDay" type="button" aria-label="上一周">←</button>
@@ -148,17 +137,17 @@
148
  </div>
149
  </section>
150
 
151
- <aside class="planner-sidebar">
152
  <div class="planner-sidebar-head">
153
  <div>
154
- <p class="column-label">Todolist Drag Zone</p>
155
- <h3>待办拖本周课表</h3>
156
  </div>
157
  <span class="planner-count" id="plannerTaskCount">0 项</span>
158
  </div>
159
  <div class="planner-sidebar-note">
160
  <span>课程是固定块,只能在后台修改。</span>
161
- <span>任务块可拖动、拉伸,也可移出排程。</span>
162
  </div>
163
  <div class="planner-task-pool" id="plannerTaskPool"></div>
164
  </aside>
@@ -176,7 +165,7 @@
176
  <div class="modal-card">
177
  <div class="modal-head">
178
  <p class="modal-kicker">安全登录</p>
179
- <h3>输入密码后即可编辑待办与时间表</h3>
180
  </div>
181
  <form class="modal-form" id="loginForm">
182
  <label>
@@ -216,7 +205,7 @@
216
  <div class="modal-card">
217
  <div class="modal-head">
218
  <p class="modal-kicker">清单设置</p>
219
- <h3>重命名当前 todolist</h3>
220
  </div>
221
  <form class="modal-form" id="renameForm">
222
  <input type="hidden" id="renameCategoryId" name="category_id">
 
1
+ {% extends "base.html" %}
2
  {% block title %}DRM | 提醒主页{% endblock %}
3
  {% block head %}
4
  <link rel="stylesheet" href="{{ url_for('static', filename='v020.css') }}">
 
13
  </div>
14
 
15
  <nav class="story-nav" aria-label="页面导航">
16
+ <button class="story-tab is-active" type="button" data-go-page="0">页提醒</button>
17
+ <button class="story-tab" type="button" data-go-page="1">周课表</button>
18
  </nav>
19
 
20
+ <div class="action-group story-actions">
21
+ <a class="ghost-link" href="{{ url_for('admin') }}">管理后台</a>
22
  {% if authenticated %}
23
+ <button class="pill-button accent-soft" id="logoutButton" type="button">退出登录</button>
24
  {% else %}
25
  <button class="pill-button accent" id="openLoginButton" type="button">登录后编辑</button>
26
  {% endif %}
 
30
  <div class="page-viewport">
31
  <div class="page-track" id="pageTrack">
32
  <section class="page-slide page-home">
33
+ <section class="hero-card hero-clock-card">
34
+ <div class="hero-orbit hero-orbit-a"></div>
35
+ <div class="hero-orbit hero-orbit-b"></div>
36
  <div class="clock-wrap">
37
+ <div class="clock-caption">北京时间</div>
38
  <h1 class="clock-display" id="clockDisplay">00:00:00</h1>
39
  <div class="clock-meta">
40
  <span id="dateDisplay">0000 年 00 月 00 日</span>
41
+ <span id="weekdayDisplay">星期一</span>
42
  <span id="lunarDisplay">农历加载中</span>
43
  </div>
44
  </div>
45
  </section>
46
 
47
  <section class="board-section">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  <div class="board-grid" id="boardGrid">
49
  {% for category in categories %}
50
  <article class="todo-column card-surface" data-category-id="{{ category.id }}">
51
  <header class="column-header">
52
+ <div class="column-header-copy">
53
  <p class="column-label">Todolist</p>
54
  <h3 class="column-title">{{ category.name }}</h3>
55
  </div>
 
105
  <section class="page-slide page-planner">
106
  <section class="planner-shell card-surface">
107
  <div class="planner-head">
108
+ <div class="planner-head-copy">
109
+ <p class="section-kicker">Weekly Planner</p>
110
+ <h2>周课程与待办总览</h2>
111
+ <p class="section-note" id="plannerHeadlineNote">课程自动按学期周次出现,待办可拖入本周任意一天,并支持上下边缘拉伸。</p>
112
  </div>
113
  <div class="planner-controls">
114
  <button class="icon-button planner-shift-button" id="plannerPrevDay" type="button" aria-label="上一周">←</button>
 
137
  </div>
138
  </section>
139
 
140
+ <aside class="planner-sidebar card-surface-soft">
141
  <div class="planner-sidebar-head">
142
  <div>
143
+ <p class="column-label">Task Queue</p>
144
+ <h3>待办拖本周课表</h3>
145
  </div>
146
  <span class="planner-count" id="plannerTaskCount">0 项</span>
147
  </div>
148
  <div class="planner-sidebar-note">
149
  <span>课程是固定块,只能在后台修改。</span>
150
+ <span>任务卡支持拖动、拉伸移出排程。</span>
151
  </div>
152
  <div class="planner-task-pool" id="plannerTaskPool"></div>
153
  </aside>
 
165
  <div class="modal-card">
166
  <div class="modal-head">
167
  <p class="modal-kicker">安全登录</p>
168
+ <h3>输入密码后即可编辑待办与表</h3>
169
  </div>
170
  <form class="modal-form" id="loginForm">
171
  <label>
 
205
  <div class="modal-card">
206
  <div class="modal-head">
207
  <p class="modal-kicker">清单设置</p>
208
+ <h3>重命名当前清单</h3>
209
  </div>
210
  <form class="modal-form" id="renameForm">
211
  <input type="hidden" id="renameCategoryId" name="category_id">