Archie0099 commited on
Commit
ef3708d
·
verified ·
1 Parent(s): b9d34d8

Redesign UI with light and dark themes

Browse files
Files changed (2) hide show
  1. static/index.html +34 -0
  2. static/styles.css +342 -174
static/index.html CHANGED
@@ -4,6 +4,29 @@
4
  <meta charset="UTF-8" />
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
  <title>Local PDF Extractor</title>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  <link rel="stylesheet" href="/static/styles.css" />
8
  </head>
9
  <body>
@@ -23,6 +46,17 @@
23
  <p class="tagline">Extract text from typed, scanned &amp; handwritten PDFs</p>
24
  </div>
25
  </div>
 
 
 
 
 
 
 
 
 
 
 
26
  </header>
27
 
28
  <main class="layout">
 
4
  <meta charset="UTF-8" />
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
  <title>Local PDF Extractor</title>
7
+ <script>
8
+ /* Set the theme before first paint (no flash), then wire the header toggle.
9
+ Self-contained so app.js is untouched. */
10
+ (function () {
11
+ var root = document.documentElement;
12
+ try {
13
+ var t = localStorage.getItem("theme");
14
+ if (t !== "light" && t !== "dark") t = "dark";
15
+ root.setAttribute("data-theme", t);
16
+ } catch (e) {
17
+ root.setAttribute("data-theme", "dark");
18
+ }
19
+ document.addEventListener("DOMContentLoaded", function () {
20
+ var btn = document.getElementById("themeToggle");
21
+ if (!btn) return;
22
+ btn.addEventListener("click", function () {
23
+ var next = root.getAttribute("data-theme") === "light" ? "dark" : "light";
24
+ root.setAttribute("data-theme", next);
25
+ try { localStorage.setItem("theme", next); } catch (e) {}
26
+ });
27
+ });
28
+ })();
29
+ </script>
30
  <link rel="stylesheet" href="/static/styles.css" />
31
  </head>
32
  <body>
 
46
  <p class="tagline">Extract text from typed, scanned &amp; handwritten PDFs</p>
47
  </div>
48
  </div>
49
+ <div class="header-actions">
50
+ <button type="button" class="theme-toggle" id="themeToggle" aria-label="Switch light / dark theme" title="Switch light / dark theme">
51
+ <svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
52
+ <circle cx="12" cy="12" r="4"></circle>
53
+ <path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"></path>
54
+ </svg>
55
+ <svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
56
+ <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
57
+ </svg>
58
+ </button>
59
+ </div>
60
  </header>
61
 
62
  <main class="layout">
static/styles.css CHANGED
@@ -1,26 +1,108 @@
 
 
 
 
 
 
 
1
  :root {
2
- --bg: #0f1115;
3
- --bg-soft: #161a22;
4
- --panel: #1b212c;
5
- --panel-2: #212835;
6
- --border: #2a3342;
7
- --border-soft: #232b38;
8
- --text: #e7ecf3;
9
- --text-dim: #9aa6b8;
10
- --text-faint: #6b7686;
11
- --accent: #6c8cff;
12
- --accent-2: #5a78f0;
13
- --green: #2ecc8f;
14
- --green-soft: rgba(46, 204, 143, 0.15);
15
- --amber: #f5a623;
16
- --amber-soft: rgba(245, 166, 35, 0.15);
17
- --red: #ff5d6c;
18
- --red-soft: rgba(255, 93, 108, 0.13);
19
- --radius: 12px;
20
- --radius-sm: 8px;
21
- --shadow: 0 6px 24px rgba(0, 0, 0, 0.35);
22
  --mono: "SFMono-Regular", "Consolas", "Liberation Mono", Menlo, monospace;
23
- --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  }
25
 
26
  * { box-sizing: border-box; }
@@ -34,6 +116,7 @@ html, body {
34
  font-size: 15px;
35
  line-height: 1.5;
36
  -webkit-font-smoothing: antialiased;
 
37
  }
38
 
39
  body {
@@ -41,75 +124,128 @@ body {
41
  display: flex;
42
  flex-direction: column;
43
  background:
44
- radial-gradient(1200px 600px at 90% -10%, rgba(108, 140, 255, 0.08), transparent 60%),
45
- radial-gradient(900px 500px at -10% 110%, rgba(46, 204, 143, 0.06), transparent 55%),
46
  var(--bg);
 
 
47
  }
48
 
49
- h1, h2, h3 { margin: 0; font-weight: 650; letter-spacing: -0.01em; }
50
 
51
- /* ---------- Header ---------- */
 
 
52
  .app-header {
53
  display: flex;
54
  align-items: center;
55
  justify-content: space-between;
56
- padding: 16px 24px;
 
57
  border-bottom: 1px solid var(--border-soft);
58
- background: rgba(15, 17, 21, 0.7);
59
- backdrop-filter: blur(8px);
 
60
  position: sticky;
61
  top: 0;
62
  z-index: 20;
63
  }
64
  .brand { display: flex; align-items: center; gap: 14px; }
65
- .brand-mark { color: var(--accent); display: flex; }
66
- .brand-text h1 { font-size: 19px; }
67
- .tagline { margin: 2px 0 0; font-size: 12.5px; color: var(--text-dim); }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  .offline-pill {
69
  font-size: 12px;
70
  font-weight: 600;
71
  color: var(--green);
72
  background: var(--green-soft);
73
- border: 1px solid rgba(46, 204, 143, 0.3);
74
  padding: 5px 12px;
75
  border-radius: 999px;
76
  }
77
 
78
- /* ---------- Layout ---------- */
79
  .layout {
80
  display: grid;
81
- grid-template-columns: 320px 1fr;
82
- gap: 24px;
83
- padding: 24px;
84
  flex: 1;
85
- max-width: 1400px;
86
  width: 100%;
87
  margin: 0 auto;
88
  }
89
 
90
- /* ---------- Sidebar ---------- */
91
  .sidebar { display: flex; flex-direction: column; gap: 18px; }
92
  .panel {
93
- background: var(--panel);
94
  border: 1px solid var(--border);
95
- border-radius: var(--radius);
96
- padding: 18px;
 
 
 
 
 
 
 
 
 
97
  }
98
- .panel-title { font-size: 14px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); margin-bottom: 14px; }
99
 
100
  .setting { margin-bottom: 18px; }
101
  .setting:last-child { margin-bottom: 0; }
102
- .setting-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
103
- .setting-label { display: block; font-size: 13px; font-weight: 600; margin-bottom: 8px; color: var(--text); }
104
- .hint { margin: 6px 0 0; font-size: 12px; color: var(--text-faint); line-height: 1.45; }
 
 
105
 
106
  .segmented {
107
  display: flex;
108
- background: var(--bg-soft);
109
  border: 1px solid var(--border);
110
- border-radius: var(--radius-sm);
111
- padding: 3px;
112
- gap: 3px;
113
  }
114
  .seg {
115
  flex: 1;
@@ -118,74 +254,92 @@ h1, h2, h3 { margin: 0; font-weight: 650; letter-spacing: -0.01em; }
118
  color: var(--text-dim);
119
  font: inherit;
120
  font-size: 13px;
121
- font-weight: 600;
122
- padding: 7px 8px;
123
- border-radius: 6px;
124
  cursor: pointer;
125
- transition: background 0.15s, color 0.15s;
126
  }
127
  .seg:hover { color: var(--text); }
128
- .seg.active { background: var(--accent); color: #fff; box-shadow: 0 2px 8px rgba(108, 140, 255, 0.35); }
 
 
 
 
129
 
130
  .select {
131
  width: 100%;
132
- background: var(--bg-soft);
133
  border: 1px solid var(--border);
134
  color: var(--text);
135
  font: inherit;
136
  font-size: 14px;
137
- padding: 9px 11px;
138
  border-radius: var(--radius-sm);
139
  cursor: pointer;
 
140
  }
141
- .select:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
 
142
 
143
  /* switch */
144
- .switch { position: relative; display: inline-block; width: 44px; height: 24px; flex: none; }
145
  .switch input { opacity: 0; width: 0; height: 0; }
146
  .slider {
147
  position: absolute; inset: 0; cursor: pointer;
148
- background: var(--border); border-radius: 999px; transition: background 0.18s;
 
 
149
  }
150
  .slider::before {
151
- content: ""; position: absolute; height: 18px; width: 18px; left: 3px; top: 3px;
152
- background: #fff; border-radius: 50%; transition: transform 0.18s;
 
 
 
 
 
 
153
  }
154
- .switch input:checked + .slider { background: var(--accent); }
155
  .switch input:checked + .slider::before { transform: translateX(20px); }
156
- .switch input:focus + .slider { box-shadow: 0 0 0 2px var(--accent); }
157
 
158
  /* dropzone */
159
  .dropzone {
160
- border: 2px dashed var(--border);
161
- border-radius: var(--radius);
162
- padding: 28px 18px;
163
  text-align: center;
164
  cursor: pointer;
165
- transition: border-color 0.18s, background 0.18s, transform 0.05s;
166
  color: var(--text-dim);
167
- background: var(--panel);
 
 
 
168
  }
169
- .dropzone:hover { border-color: var(--accent); background: var(--panel-2); }
170
  .dropzone:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
171
- .dropzone.dragover { border-color: var(--accent); background: rgba(108, 140, 255, 0.08); transform: scale(1.01); }
172
- .dz-icon { color: var(--accent); margin-bottom: 8px; }
173
- .dz-primary { margin: 0; font-weight: 600; color: var(--text); font-size: 15px; }
174
- .dz-secondary { margin: 6px 0 0; font-size: 13px; }
175
- .dz-link { color: var(--accent); text-decoration: underline; }
176
 
177
  /* notes */
178
  .notes {
179
- background: var(--panel);
180
  border: 1px solid var(--border);
181
- border-radius: var(--radius);
182
- padding: 16px 18px;
 
183
  }
184
- .notes-title { font-size: 13px; color: var(--text-dim); margin-bottom: 10px; }
185
  .notes ul { margin: 0; padding-left: 18px; }
186
- .notes li { font-size: 12.5px; color: var(--text-faint); margin-bottom: 6px; line-height: 1.5; }
 
187
 
188
- /* ---------- Work area ---------- */
189
  .work { min-width: 0; display: flex; flex-direction: column; gap: 18px; }
190
 
191
  .toolbar {
@@ -193,186 +347,195 @@ h1, h2, h3 { margin: 0; font-weight: 650; letter-spacing: -0.01em; }
193
  align-items: center;
194
  gap: 14px;
195
  flex-wrap: wrap;
196
- background: var(--panel);
 
 
197
  border: 1px solid var(--border);
198
  border-radius: var(--radius);
199
  padding: 12px 14px;
200
  position: sticky;
201
- top: 78px;
202
  z-index: 10;
 
203
  }
204
  .search-wrap { position: relative; flex: 1; min-width: 220px; display: flex; align-items: center; }
205
- .search-icon { position: absolute; left: 11px; color: var(--text-faint); pointer-events: none; }
206
  .search-input {
207
  width: 100%;
208
- background: var(--bg-soft);
209
  border: 1px solid var(--border);
210
  color: var(--text);
211
  font: inherit;
212
  font-size: 14px;
213
- padding: 9px 12px 9px 34px;
214
  border-radius: var(--radius-sm);
 
215
  }
216
- .search-input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
217
- .search-count { position: absolute; right: 12px; font-size: 12px; color: var(--text-faint); }
 
218
  .toolbar-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
219
- .export-group { display: flex; gap: 4px; background: var(--bg-soft); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 3px; }
220
 
221
  /* buttons */
222
  .btn {
223
  border: 1px solid var(--border);
224
- background: var(--panel-2);
225
  color: var(--text);
226
  font: inherit;
227
  font-size: 13px;
228
- font-weight: 600;
229
- padding: 8px 13px;
230
  border-radius: var(--radius-sm);
231
  cursor: pointer;
232
- transition: background 0.15s, border-color 0.15s, color 0.15s, opacity 0.15s;
233
- }
234
- .btn:hover { background: var(--border); }
235
- .btn:active { transform: translateY(1px); }
236
- .btn:disabled { opacity: 0.45; cursor: not-allowed; }
237
- .btn-sm { padding: 5px 10px; font-size: 12px; }
238
- .btn-ghost { background: transparent; border-color: transparent; color: var(--text-dim); }
239
- .btn-ghost:hover { background: var(--border-soft); color: var(--text); }
 
240
  .export-group .btn-ghost { border: none; }
241
- .btn-danger { color: var(--red); border-color: rgba(255, 93, 108, 0.4); background: transparent; }
242
- .btn-danger:hover { background: var(--red-soft); }
243
 
244
- /* empty state */
245
- /* The HTML `hidden` attribute must always win — otherwise an explicit
246
- `display:` rule (e.g. .empty-state below) keeps a "hidden" element visible. */
247
  [hidden] { display: none !important; }
248
 
 
249
  .empty-state {
250
  display: flex;
251
  flex-direction: column;
252
  align-items: center;
253
  text-align: center;
254
- padding: 80px 24px;
255
  color: var(--text-faint);
256
- border: 1px dashed var(--border);
257
- border-radius: var(--radius);
 
 
258
  }
259
- .empty-state svg { color: var(--border); margin-bottom: 16px; }
260
  .empty-state h2 { font-size: 18px; color: var(--text-dim); margin-bottom: 6px; }
261
  .empty-state p { margin: 0; max-width: 360px; font-size: 14px; }
262
 
263
  /* files */
264
  .files-container { display: flex; flex-direction: column; gap: 18px; }
265
  .file-card {
266
- background: var(--panel);
267
  border: 1px solid var(--border);
268
- border-radius: var(--radius);
269
  overflow: hidden;
 
270
  }
271
  .file-head {
272
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
273
- padding: 14px 16px; border-bottom: 1px solid var(--border-soft);
274
  }
275
- .file-meta { display: flex; align-items: center; gap: 10px; min-width: 0; }
276
- .file-name { font-size: 15px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
277
  .file-head-right { display: flex; align-items: center; gap: 12px; flex: none; }
278
- .status-text { font-size: 12.5px; color: var(--text-dim); }
279
  .status-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--text-faint); flex: none; }
280
- .status-dot.processing { background: var(--accent); animation: pulse 1.2s infinite; }
281
- .status-dot.done { background: var(--green); }
282
- .status-dot.error { background: var(--red); }
283
- .status-dot.cancelled { background: var(--amber); }
284
- @keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.35; } }
285
-
286
- .progress-row { display: flex; align-items: center; gap: 12px; padding: 12px 16px; }
287
- .progress-track { flex: 1; height: 7px; background: var(--bg-soft); border-radius: 999px; overflow: hidden; }
288
- .progress-fill { height: 100%; width: 0%; background: linear-gradient(90deg, var(--accent-2), var(--accent)); border-radius: 999px; transition: width 0.3s ease; }
289
  .progress-label { font-size: 12px; color: var(--text-dim); font-variant-numeric: tabular-nums; flex: none; }
290
 
291
  .file-error {
292
- margin: 0 16px 14px;
293
- padding: 10px 12px;
294
  background: var(--red-soft);
295
- border: 1px solid rgba(255, 93, 108, 0.35);
296
  border-radius: var(--radius-sm);
297
  color: var(--red);
298
  font-size: 13px;
299
  }
300
 
301
- .pages { display: flex; flex-direction: column; gap: 12px; padding: 4px 16px 16px; }
302
 
303
  /* page card */
304
  .page-card {
305
  border: 1px solid var(--border-soft);
306
- border-radius: var(--radius-sm);
307
- background: var(--bg-soft);
308
  overflow: hidden;
309
  }
310
- .page-head { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-bottom: 1px solid var(--border-soft); }
311
  .page-num { font-size: 13px; font-weight: 700; color: var(--text-dim); }
312
  .page-spacer { flex: 1; }
313
- .badge { font-size: 11px; font-weight: 700; padding: 3px 9px; border-radius: 999px; text-transform: uppercase; letter-spacing: 0.03em; }
314
- .badge.text { color: var(--green); background: var(--green-soft); border: 1px solid rgba(46, 204, 143, 0.35); }
315
- .badge.ocr { color: var(--amber); background: var(--amber-soft); border: 1px solid rgba(245, 166, 35, 0.35); }
316
- .badge.ocr.lowconf { color: var(--red); background: var(--red-soft); border-color: rgba(255, 93, 108, 0.35); }
317
- .badge.handwriting { color: #b98cff; background: rgba(160, 120, 255, 0.15); border: 1px solid rgba(160, 120, 255, 0.4); }
318
- .badge.online { color: #4fc3f7; background: rgba(79, 195, 247, 0.14); border: 1px solid rgba(79, 195, 247, 0.4); }
319
- .beta-tag { font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--accent); background: rgba(108,140,255,0.16); padding: 1px 5px; border-radius: 999px; vertical-align: middle; }
320
- .badge.error { color: var(--red); background: var(--red-soft); border: 1px solid rgba(255, 93, 108, 0.35); }
321
- .badge.pending { color: var(--text-faint); background: var(--border-soft); border: 1px solid var(--border); }
322
 
323
  .page-text {
324
  margin: 0;
325
- padding: 14px 16px;
326
  white-space: pre-wrap;
327
  word-break: break-word;
328
  font-family: var(--mono);
329
  font-size: 13px;
330
- line-height: 1.6;
331
  color: var(--text);
332
  max-height: 460px;
333
  overflow: auto;
334
  }
335
  .page-text:empty::before { content: "(no text on this page)"; color: var(--text-faint); font-style: italic; }
336
- .page-text mark { background: var(--amber); color: #1a1a1a; border-radius: 2px; padding: 0 1px; }
337
- .page-text mark.active { background: #ffd86b; outline: 1px solid var(--amber); }
338
 
339
  /* Low-confidence line highlight ("which lines to check") */
340
- .lc-line { background: rgba(245, 166, 35, 0.16); border-bottom: 1px dashed rgba(245, 166, 35, 0.7); border-radius: 2px; }
341
 
342
  /* "N to check" chip in the page header */
343
- .to-check { font-size: 11px; font-weight: 600; color: var(--amber); background: var(--amber-soft); border: 1px solid rgba(245, 166, 35, 0.35); border-radius: 999px; padding: 2px 8px; white-space: nowrap; }
344
 
345
- /* Inline edit box matches the read-only text view */
346
  .page-edit {
347
  width: 100%; box-sizing: border-box; margin: 0;
348
- padding: 14px 16px; min-height: 180px; max-height: 460px; resize: vertical;
349
  white-space: pre-wrap; word-break: break-word;
350
- font-family: var(--mono); font-size: 13px; line-height: 1.6;
351
- color: var(--text); background: var(--bg-soft);
352
- border: 1px solid var(--accent); border-radius: 0 0 var(--radius-sm) var(--radius-sm);
353
  outline: none;
 
354
  }
355
 
356
- .page-image-wrap { padding: 12px 16px; border-top: 1px solid var(--border-soft); background: var(--panel); }
357
- .page-image-wrap img { max-width: 100%; border-radius: 6px; border: 1px solid var(--border); display: block; }
358
  .page-image-wrap .img-loading { color: var(--text-faint); font-size: 13px; }
359
 
360
  /* toast */
361
  .toast {
362
  position: fixed;
363
- bottom: 24px;
364
  left: 50%;
365
- transform: translateX(-50%) translateY(10px);
366
- background: var(--panel-2);
367
  border: 1px solid var(--border);
368
  color: var(--text);
369
- padding: 11px 18px;
370
  border-radius: 999px;
371
  font-size: 13.5px;
372
  font-weight: 600;
373
  box-shadow: var(--shadow);
374
  opacity: 0;
375
- transition: opacity 0.2s, transform 0.2s;
376
  z-index: 50;
377
  pointer-events: none;
378
  }
@@ -392,36 +555,41 @@ h1, h2, h3 { margin: 0; font-weight: 650; letter-spacing: -0.01em; }
392
  }
393
 
394
  /* scrollbars */
395
- .page-text::-webkit-scrollbar { width: 10px; height: 10px; }
396
- .page-text::-webkit-scrollbar-thumb { background: var(--border); border-radius: 999px; border: 2px solid var(--bg-soft); }
 
397
  .page-text::-webkit-scrollbar-track { background: transparent; }
398
 
399
- /* Large-handwriting sub-setting: indented under the handwriting toggle */
400
- .setting-sub { margin-left: 14px; padding-left: 10px; border-left: 2px solid var(--border-soft); }
401
 
402
  /* "Suggest best settings" recommendation panel */
403
- .btn-primary { background: var(--accent); color: #fff; border-color: var(--accent); }
404
- .btn-primary:hover { background: var(--accent-2); }
405
- .suggest-card { margin-top: 6px; padding: 10px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-soft); }
406
- .suggest-rationale { font-size: 12px; line-height: 1.45; margin: 0 0 8px; color: var(--text-dim); }
407
- .suggest-evidence { font-size: 11px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; margin-bottom: 8px; }
408
- .ev-row { display: grid; grid-template-columns: 1.5fr 1fr 0.9fr 0.9fr; gap: 6px; padding: 2px 0; opacity: 0.75; }
409
- .ev-row.best { opacity: 1; font-weight: 600; color: var(--text); }
410
 
411
  /* Online (Gemini) settings */
412
- .online-input { width: 100%; margin-bottom: 6px; font-family: ui-monospace, monospace; font-size: 12px; }
413
  .online-key-actions { display: flex; align-items: center; gap: 8px; }
414
  .online-status { font-size: 11px; }
415
  .online-status.good { color: var(--green); }
416
  .online-status.bad { color: var(--red); }
417
 
418
- /* Remove (×) button on a file card */
419
- .btn-remove { color: var(--text-dim); font-size: 18px; line-height: 1; padding: 3px 9px; font-weight: 700; }
420
- .btn-remove:hover { color: var(--red); background: var(--red-soft); }
421
 
422
  /* Settings group sub-headings */
423
  .setting-group-label {
424
- font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em;
425
- color: var(--text-faint); margin: 18px 0 4px; padding-top: 14px;
426
  border-top: 1px solid var(--border-soft);
427
  }
 
 
 
 
 
1
+ /* ============================================================
2
+ PDF Extractor - UI styles
3
+ Two themes (dark default, light) driven by html[data-theme].
4
+ Component class names are unchanged so the app behaviour and
5
+ all JS hooks keep working; only the styling is new.
6
+ ============================================================ */
7
+
8
  :root {
9
+ /* shape + type (shared across themes) */
10
+ --radius-lg: 18px;
11
+ --radius: 13px;
12
+ --radius-sm: 9px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  --mono: "SFMono-Regular", "Consolas", "Liberation Mono", Menlo, monospace;
14
+ --sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
15
+ --t-fast: 0.14s ease;
16
+ --t: 0.22s cubic-bezier(0.2, 0.6, 0.2, 1);
17
+
18
+ /* accent contrast text is white in both themes */
19
+ --accent-contrast: #ffffff;
20
+ }
21
+
22
+ /* ---------------- DARK (default) ---------------- */
23
+ html[data-theme="dark"] {
24
+ --bg: #0a0d14;
25
+ --bg-glow-1: rgba(118, 131, 255, 0.13);
26
+ --bg-glow-2: rgba(38, 199, 154, 0.07);
27
+
28
+ --surface: #141a26;
29
+ --surface-2: #1c2433;
30
+ --surface-3: #0f1521;
31
+ --surface-raise: #1f2838;
32
+
33
+ --border: #28313f;
34
+ --border-soft: #1d2532;
35
+ --border-strong: #36425380;
36
+
37
+ --text: #e9eef6;
38
+ --text-dim: #9eabbf;
39
+ --text-faint: #66718390;
40
+
41
+ --accent: #7e8cff;
42
+ --accent-strong: #6b78f7;
43
+ --accent-soft: rgba(126, 140, 255, 0.16);
44
+ --accent-ring: rgba(126, 140, 255, 0.45);
45
+
46
+ --green: #34d39e;
47
+ --green-soft: rgba(52, 211, 158, 0.15);
48
+ --green-line: rgba(52, 211, 158, 0.38);
49
+ --amber: #f5b13d;
50
+ --amber-soft: rgba(245, 177, 61, 0.15);
51
+ --amber-line: rgba(245, 177, 61, 0.4);
52
+ --red: #ff6171;
53
+ --red-soft: rgba(255, 97, 113, 0.14);
54
+ --red-line: rgba(255, 97, 113, 0.4);
55
+ --violet: #b98cff;
56
+ --cyan: #54c8f7;
57
+
58
+ --shadow: 0 18px 40px -18px rgba(0, 0, 0, 0.7);
59
+ --shadow-sm: 0 2px 10px rgba(0, 0, 0, 0.35);
60
+ --mark: #f5b13d;
61
+ --mark-active: #ffd86b;
62
+ --mark-text: #1a1205;
63
+ }
64
+
65
+ /* ---------------- LIGHT ---------------- */
66
+ html[data-theme="light"] {
67
+ --bg: #f4f6fb;
68
+ --bg-glow-1: rgba(91, 102, 235, 0.08);
69
+ --bg-glow-2: rgba(20, 175, 128, 0.06);
70
+
71
+ --surface: #ffffff;
72
+ --surface-2: #ffffff;
73
+ --surface-3: #f1f4f9;
74
+ --surface-raise: #ffffff;
75
+
76
+ --border: #e3e8f0;
77
+ --border-soft: #edf0f6;
78
+ --border-strong: #d3dae6;
79
+
80
+ --text: #18202e;
81
+ --text-dim: #586377;
82
+ --text-faint: #8a95a8;
83
+
84
+ --accent: #5b63e6;
85
+ --accent-strong: #4a52da;
86
+ --accent-soft: rgba(91, 99, 230, 0.1);
87
+ --accent-ring: rgba(91, 99, 230, 0.35);
88
+
89
+ --green: #12a877;
90
+ --green-soft: rgba(18, 168, 119, 0.12);
91
+ --green-line: rgba(18, 168, 119, 0.32);
92
+ --amber: #c77d18;
93
+ --amber-soft: rgba(199, 125, 24, 0.12);
94
+ --amber-line: rgba(199, 125, 24, 0.32);
95
+ --red: #e0455c;
96
+ --red-soft: rgba(224, 69, 92, 0.1);
97
+ --red-line: rgba(224, 69, 92, 0.32);
98
+ --violet: #8b5cf6;
99
+ --cyan: #0ea5d9;
100
+
101
+ --shadow: 0 16px 40px -20px rgba(28, 40, 66, 0.28);
102
+ --shadow-sm: 0 1px 2px rgba(28, 40, 66, 0.06), 0 2px 6px rgba(28, 40, 66, 0.05);
103
+ --mark: #ffd84d;
104
+ --mark-active: #ffc21f;
105
+ --mark-text: #3a2c00;
106
  }
107
 
108
  * { box-sizing: border-box; }
 
116
  font-size: 15px;
117
  line-height: 1.5;
118
  -webkit-font-smoothing: antialiased;
119
+ text-rendering: optimizeLegibility;
120
  }
121
 
122
  body {
 
124
  display: flex;
125
  flex-direction: column;
126
  background:
127
+ radial-gradient(1100px 560px at 88% -12%, var(--bg-glow-1), transparent 60%),
128
+ radial-gradient(820px 480px at -8% 112%, var(--bg-glow-2), transparent 55%),
129
  var(--bg);
130
+ background-attachment: fixed;
131
+ transition: background-color var(--t), color var(--t);
132
  }
133
 
134
+ h1, h2, h3 { margin: 0; font-weight: 680; letter-spacing: -0.015em; }
135
 
136
+ ::selection { background: var(--accent-soft); }
137
+
138
+ /* ---------------- Header ---------------- */
139
  .app-header {
140
  display: flex;
141
  align-items: center;
142
  justify-content: space-between;
143
+ gap: 16px;
144
+ padding: 15px 26px;
145
  border-bottom: 1px solid var(--border-soft);
146
+ background: color-mix(in srgb, var(--bg) 78%, transparent);
147
+ backdrop-filter: blur(14px) saturate(1.3);
148
+ -webkit-backdrop-filter: blur(14px) saturate(1.3);
149
  position: sticky;
150
  top: 0;
151
  z-index: 20;
152
  }
153
  .brand { display: flex; align-items: center; gap: 14px; }
154
+ .brand-mark {
155
+ color: var(--accent-contrast);
156
+ display: flex;
157
+ align-items: center;
158
+ justify-content: center;
159
+ width: 42px;
160
+ height: 42px;
161
+ border-radius: 12px;
162
+ background: linear-gradient(145deg, var(--accent), var(--accent-strong));
163
+ box-shadow: 0 6px 18px -6px var(--accent-ring), inset 0 1px 0 rgba(255, 255, 255, 0.25);
164
+ }
165
+ .brand-mark svg { width: 24px; height: 24px; }
166
+ .brand-text h1 { font-size: 19px; line-height: 1.1; }
167
+ .tagline { margin: 3px 0 0; font-size: 12.5px; color: var(--text-dim); }
168
+
169
+ .header-actions { display: flex; align-items: center; gap: 10px; }
170
+
171
+ /* theme toggle */
172
+ .theme-toggle {
173
+ display: inline-flex;
174
+ align-items: center;
175
+ justify-content: center;
176
+ width: 40px;
177
+ height: 40px;
178
+ border-radius: 11px;
179
+ border: 1px solid var(--border);
180
+ background: var(--surface-2);
181
+ color: var(--text-dim);
182
+ cursor: pointer;
183
+ transition: color var(--t-fast), background var(--t-fast), border-color var(--t-fast), transform var(--t-fast);
184
+ box-shadow: var(--shadow-sm);
185
+ }
186
+ .theme-toggle:hover { color: var(--accent); border-color: var(--accent); transform: translateY(-1px); }
187
+ .theme-toggle:active { transform: translateY(0); }
188
+ .theme-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
189
+ .theme-toggle svg { width: 19px; height: 19px; }
190
+ .theme-toggle .icon-sun, .theme-toggle .icon-moon { display: none; }
191
+ html[data-theme="dark"] .theme-toggle .icon-sun { display: block; }
192
+ html[data-theme="light"] .theme-toggle .icon-moon { display: block; }
193
+
194
  .offline-pill {
195
  font-size: 12px;
196
  font-weight: 600;
197
  color: var(--green);
198
  background: var(--green-soft);
199
+ border: 1px solid var(--green-line);
200
  padding: 5px 12px;
201
  border-radius: 999px;
202
  }
203
 
204
+ /* ---------------- Layout ---------------- */
205
  .layout {
206
  display: grid;
207
+ grid-template-columns: 330px 1fr;
208
+ gap: 26px;
209
+ padding: 26px;
210
  flex: 1;
211
+ max-width: 1440px;
212
  width: 100%;
213
  margin: 0 auto;
214
  }
215
 
216
+ /* ---------------- Sidebar ---------------- */
217
  .sidebar { display: flex; flex-direction: column; gap: 18px; }
218
  .panel {
219
+ background: var(--surface);
220
  border: 1px solid var(--border);
221
+ border-radius: var(--radius-lg);
222
+ padding: 20px;
223
+ box-shadow: var(--shadow);
224
+ }
225
+ .panel-title {
226
+ font-size: 12px;
227
+ font-weight: 700;
228
+ text-transform: uppercase;
229
+ letter-spacing: 0.08em;
230
+ color: var(--text-dim);
231
+ margin-bottom: 16px;
232
  }
 
233
 
234
  .setting { margin-bottom: 18px; }
235
  .setting:last-child { margin-bottom: 0; }
236
+ .setting-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; }
237
+ .setting-row > div { min-width: 0; }
238
+ .setting-label { display: block; font-size: 13.5px; font-weight: 650; margin-bottom: 8px; color: var(--text); }
239
+ .setting-row .setting-label { margin-bottom: 3px; }
240
+ .hint { margin: 5px 0 0; font-size: 11.5px; color: var(--text-faint); line-height: 1.5; }
241
 
242
  .segmented {
243
  display: flex;
244
+ background: var(--surface-3);
245
  border: 1px solid var(--border);
246
+ border-radius: 11px;
247
+ padding: 4px;
248
+ gap: 4px;
249
  }
250
  .seg {
251
  flex: 1;
 
254
  color: var(--text-dim);
255
  font: inherit;
256
  font-size: 13px;
257
+ font-weight: 650;
258
+ padding: 8px 8px;
259
+ border-radius: 8px;
260
  cursor: pointer;
261
+ transition: background var(--t-fast), color var(--t-fast), box-shadow var(--t-fast);
262
  }
263
  .seg:hover { color: var(--text); }
264
+ .seg.active {
265
+ background: linear-gradient(145deg, var(--accent), var(--accent-strong));
266
+ color: var(--accent-contrast);
267
+ box-shadow: 0 4px 12px -3px var(--accent-ring);
268
+ }
269
 
270
  .select {
271
  width: 100%;
272
+ background: var(--surface-3);
273
  border: 1px solid var(--border);
274
  color: var(--text);
275
  font: inherit;
276
  font-size: 14px;
277
+ padding: 10px 12px;
278
  border-radius: var(--radius-sm);
279
  cursor: pointer;
280
+ transition: border-color var(--t-fast), box-shadow var(--t-fast);
281
  }
282
+ .select:hover { border-color: var(--border-strong); }
283
+ .select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
284
 
285
  /* switch */
286
+ .switch { position: relative; display: inline-block; width: 46px; height: 26px; flex: none; }
287
  .switch input { opacity: 0; width: 0; height: 0; }
288
  .slider {
289
  position: absolute; inset: 0; cursor: pointer;
290
+ background: var(--border); border-radius: 999px;
291
+ transition: background var(--t);
292
+ border: 1px solid var(--border-strong);
293
  }
294
  .slider::before {
295
+ content: ""; position: absolute; height: 20px; width: 20px; left: 2px; top: 2px;
296
+ background: #fff; border-radius: 50%;
297
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
298
+ transition: transform var(--t);
299
+ }
300
+ .switch input:checked + .slider {
301
+ background: linear-gradient(145deg, var(--accent), var(--accent-strong));
302
+ border-color: transparent;
303
  }
 
304
  .switch input:checked + .slider::before { transform: translateX(20px); }
305
+ .switch input:focus-visible + .slider { box-shadow: 0 0 0 3px var(--accent-ring); }
306
 
307
  /* dropzone */
308
  .dropzone {
309
+ border: 1.5px dashed var(--border-strong);
310
+ border-radius: var(--radius-lg);
311
+ padding: 32px 18px;
312
  text-align: center;
313
  cursor: pointer;
314
+ transition: border-color var(--t), background var(--t), transform var(--t-fast);
315
  color: var(--text-dim);
316
+ background:
317
+ radial-gradient(120% 120% at 50% 0%, var(--accent-soft), transparent 70%),
318
+ var(--surface);
319
+ box-shadow: var(--shadow);
320
  }
321
+ .dropzone:hover { border-color: var(--accent); }
322
  .dropzone:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
323
+ .dropzone.dragover { border-color: var(--accent); background: var(--accent-soft); transform: scale(1.012); }
324
+ .dz-icon { color: var(--accent); margin-bottom: 10px; }
325
+ .dz-primary { margin: 0; font-weight: 650; color: var(--text); font-size: 15px; }
326
+ .dz-secondary { margin: 6px 0 0; font-size: 13px; color: var(--text-dim); }
327
+ .dz-link { color: var(--accent); font-weight: 600; }
328
 
329
  /* notes */
330
  .notes {
331
+ background: var(--surface);
332
  border: 1px solid var(--border);
333
+ border-radius: var(--radius-lg);
334
+ padding: 18px 20px;
335
+ box-shadow: var(--shadow);
336
  }
337
+ .notes-title { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.07em; color: var(--text-dim); margin-bottom: 12px; }
338
  .notes ul { margin: 0; padding-left: 18px; }
339
+ .notes li { font-size: 12px; color: var(--text-faint); margin-bottom: 7px; line-height: 1.55; }
340
+ .notes li::marker { color: var(--accent); }
341
 
342
+ /* ---------------- Work area ---------------- */
343
  .work { min-width: 0; display: flex; flex-direction: column; gap: 18px; }
344
 
345
  .toolbar {
 
347
  align-items: center;
348
  gap: 14px;
349
  flex-wrap: wrap;
350
+ background: color-mix(in srgb, var(--surface) 88%, transparent);
351
+ backdrop-filter: blur(12px);
352
+ -webkit-backdrop-filter: blur(12px);
353
  border: 1px solid var(--border);
354
  border-radius: var(--radius);
355
  padding: 12px 14px;
356
  position: sticky;
357
+ top: 86px;
358
  z-index: 10;
359
+ box-shadow: var(--shadow);
360
  }
361
  .search-wrap { position: relative; flex: 1; min-width: 220px; display: flex; align-items: center; }
362
+ .search-icon { position: absolute; left: 12px; color: var(--text-faint); pointer-events: none; }
363
  .search-input {
364
  width: 100%;
365
+ background: var(--surface-3);
366
  border: 1px solid var(--border);
367
  color: var(--text);
368
  font: inherit;
369
  font-size: 14px;
370
+ padding: 10px 12px 10px 36px;
371
  border-radius: var(--radius-sm);
372
+ transition: border-color var(--t-fast), box-shadow var(--t-fast);
373
  }
374
+ .search-input::placeholder { color: var(--text-faint); }
375
+ .search-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
376
+ .search-count { position: absolute; right: 12px; font-size: 12px; color: var(--text-faint); font-variant-numeric: tabular-nums; }
377
  .toolbar-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
378
+ .export-group { display: flex; gap: 3px; background: var(--surface-3); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 3px; }
379
 
380
  /* buttons */
381
  .btn {
382
  border: 1px solid var(--border);
383
+ background: var(--surface-2);
384
  color: var(--text);
385
  font: inherit;
386
  font-size: 13px;
387
+ font-weight: 650;
388
+ padding: 9px 14px;
389
  border-radius: var(--radius-sm);
390
  cursor: pointer;
391
+ transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast), opacity var(--t-fast), transform var(--t-fast), box-shadow var(--t-fast);
392
+ box-shadow: var(--shadow-sm);
393
+ }
394
+ .btn:hover { border-color: var(--border-strong); transform: translateY(-1px); }
395
+ .btn:active { transform: translateY(0); }
396
+ .btn:disabled { opacity: 0.45; cursor: not-allowed; transform: none; box-shadow: none; }
397
+ .btn-sm { padding: 6px 11px; font-size: 12px; }
398
+ .btn-ghost { background: transparent; border-color: transparent; color: var(--text-dim); box-shadow: none; }
399
+ .btn-ghost:hover { background: var(--accent-soft); color: var(--accent); border-color: transparent; transform: none; }
400
  .export-group .btn-ghost { border: none; }
401
+ .btn-danger { color: var(--red); border-color: var(--red-line); background: transparent; box-shadow: none; }
402
+ .btn-danger:hover { background: var(--red-soft); border-color: var(--red); transform: none; }
403
 
404
+ /* The HTML `hidden` attribute must always win over display rules below. */
 
 
405
  [hidden] { display: none !important; }
406
 
407
+ /* empty state */
408
  .empty-state {
409
  display: flex;
410
  flex-direction: column;
411
  align-items: center;
412
  text-align: center;
413
+ padding: 84px 24px;
414
  color: var(--text-faint);
415
+ border: 1.5px dashed var(--border-strong);
416
+ border-radius: var(--radius-lg);
417
+ background: var(--surface);
418
+ box-shadow: var(--shadow);
419
  }
420
+ .empty-state svg { color: var(--accent); opacity: 0.55; margin-bottom: 18px; }
421
  .empty-state h2 { font-size: 18px; color: var(--text-dim); margin-bottom: 6px; }
422
  .empty-state p { margin: 0; max-width: 360px; font-size: 14px; }
423
 
424
  /* files */
425
  .files-container { display: flex; flex-direction: column; gap: 18px; }
426
  .file-card {
427
+ background: var(--surface);
428
  border: 1px solid var(--border);
429
+ border-radius: var(--radius-lg);
430
  overflow: hidden;
431
+ box-shadow: var(--shadow);
432
  }
433
  .file-head {
434
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
435
+ padding: 15px 18px; border-bottom: 1px solid var(--border-soft);
436
  }
437
+ .file-meta { display: flex; align-items: center; gap: 11px; min-width: 0; }
438
+ .file-name { font-size: 15px; font-weight: 650; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
439
  .file-head-right { display: flex; align-items: center; gap: 12px; flex: none; }
440
+ .status-text { font-size: 12.5px; color: var(--text-dim); font-weight: 550; }
441
  .status-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--text-faint); flex: none; }
442
+ .status-dot.processing { background: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft); animation: pulse 1.2s infinite; }
443
+ .status-dot.done { background: var(--green); box-shadow: 0 0 0 4px var(--green-soft); }
444
+ .status-dot.error { background: var(--red); box-shadow: 0 0 0 4px var(--red-soft); }
445
+ .status-dot.cancelled { background: var(--amber); box-shadow: 0 0 0 4px var(--amber-soft); }
446
+ @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
447
+
448
+ .progress-row { display: flex; align-items: center; gap: 13px; padding: 13px 18px; }
449
+ .progress-track { flex: 1; height: 8px; background: var(--surface-3); border-radius: 999px; overflow: hidden; box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.12); }
450
+ .progress-fill { height: 100%; width: 0%; background: linear-gradient(90deg, var(--accent-strong), var(--accent)); border-radius: 999px; transition: width 0.3s ease; }
451
  .progress-label { font-size: 12px; color: var(--text-dim); font-variant-numeric: tabular-nums; flex: none; }
452
 
453
  .file-error {
454
+ margin: 0 18px 15px;
455
+ padding: 11px 13px;
456
  background: var(--red-soft);
457
+ border: 1px solid var(--red-line);
458
  border-radius: var(--radius-sm);
459
  color: var(--red);
460
  font-size: 13px;
461
  }
462
 
463
+ .pages { display: flex; flex-direction: column; gap: 13px; padding: 5px 18px 18px; }
464
 
465
  /* page card */
466
  .page-card {
467
  border: 1px solid var(--border-soft);
468
+ border-radius: var(--radius);
469
+ background: var(--surface-3);
470
  overflow: hidden;
471
  }
472
+ .page-head { display: flex; align-items: center; gap: 10px; padding: 10px 13px; border-bottom: 1px solid var(--border-soft); }
473
  .page-num { font-size: 13px; font-weight: 700; color: var(--text-dim); }
474
  .page-spacer { flex: 1; }
475
+ .badge { font-size: 10.5px; font-weight: 700; padding: 3px 9px; border-radius: 999px; text-transform: uppercase; letter-spacing: 0.04em; }
476
+ .badge.text { color: var(--green); background: var(--green-soft); border: 1px solid var(--green-line); }
477
+ .badge.ocr { color: var(--amber); background: var(--amber-soft); border: 1px solid var(--amber-line); }
478
+ .badge.ocr.lowconf { color: var(--red); background: var(--red-soft); border-color: var(--red-line); }
479
+ .badge.handwriting { color: var(--violet); background: color-mix(in srgb, var(--violet) 16%, transparent); border: 1px solid color-mix(in srgb, var(--violet) 40%, transparent); }
480
+ .badge.online { color: var(--cyan); background: color-mix(in srgb, var(--cyan) 15%, transparent); border: 1px solid color-mix(in srgb, var(--cyan) 40%, transparent); }
481
+ .beta-tag { font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--accent); background: var(--accent-soft); padding: 1px 5px; border-radius: 999px; vertical-align: middle; }
482
+ .badge.error { color: var(--red); background: var(--red-soft); border: 1px solid var(--red-line); }
483
+ .badge.pending { color: var(--text-faint); background: var(--surface-2); border: 1px solid var(--border); }
484
 
485
  .page-text {
486
  margin: 0;
487
+ padding: 15px 17px;
488
  white-space: pre-wrap;
489
  word-break: break-word;
490
  font-family: var(--mono);
491
  font-size: 13px;
492
+ line-height: 1.65;
493
  color: var(--text);
494
  max-height: 460px;
495
  overflow: auto;
496
  }
497
  .page-text:empty::before { content: "(no text on this page)"; color: var(--text-faint); font-style: italic; }
498
+ .page-text mark { background: var(--mark); color: var(--mark-text); border-radius: 3px; padding: 0 2px; }
499
+ .page-text mark.active { background: var(--mark-active); outline: 1.5px solid var(--amber); }
500
 
501
  /* Low-confidence line highlight ("which lines to check") */
502
+ .lc-line { background: var(--amber-soft); border-bottom: 1px dashed var(--amber-line); border-radius: 3px; }
503
 
504
  /* "N to check" chip in the page header */
505
+ .to-check { font-size: 11px; font-weight: 600; color: var(--amber); background: var(--amber-soft); border: 1px solid var(--amber-line); border-radius: 999px; padding: 2px 9px; white-space: nowrap; }
506
 
507
+ /* Inline edit box - matches the read-only text view */
508
  .page-edit {
509
  width: 100%; box-sizing: border-box; margin: 0;
510
+ padding: 15px 17px; min-height: 180px; max-height: 460px; resize: vertical;
511
  white-space: pre-wrap; word-break: break-word;
512
+ font-family: var(--mono); font-size: 13px; line-height: 1.65;
513
+ color: var(--text); background: var(--surface-3);
514
+ border: 1px solid var(--accent); border-radius: 0 0 var(--radius) var(--radius);
515
  outline: none;
516
+ box-shadow: inset 0 0 0 3px var(--accent-soft);
517
  }
518
 
519
+ .page-image-wrap { padding: 13px 17px; border-top: 1px solid var(--border-soft); background: var(--surface); }
520
+ .page-image-wrap img { max-width: 100%; border-radius: 8px; border: 1px solid var(--border); display: block; }
521
  .page-image-wrap .img-loading { color: var(--text-faint); font-size: 13px; }
522
 
523
  /* toast */
524
  .toast {
525
  position: fixed;
526
+ bottom: 26px;
527
  left: 50%;
528
+ transform: translateX(-50%) translateY(12px);
529
+ background: var(--surface-raise);
530
  border: 1px solid var(--border);
531
  color: var(--text);
532
+ padding: 12px 20px;
533
  border-radius: 999px;
534
  font-size: 13.5px;
535
  font-weight: 600;
536
  box-shadow: var(--shadow);
537
  opacity: 0;
538
+ transition: opacity var(--t), transform var(--t);
539
  z-index: 50;
540
  pointer-events: none;
541
  }
 
555
  }
556
 
557
  /* scrollbars */
558
+ .page-text::-webkit-scrollbar { width: 11px; height: 11px; }
559
+ .page-text::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 999px; border: 3px solid var(--surface-3); }
560
+ .page-text::-webkit-scrollbar-thumb:hover { background: var(--text-faint); }
561
  .page-text::-webkit-scrollbar-track { background: transparent; }
562
 
563
+ /* Large-handwriting / online sub-setting: indented under its toggle */
564
+ .setting-sub { margin-left: 4px; padding-left: 13px; border-left: 2px solid var(--accent-soft); }
565
 
566
  /* "Suggest best settings" recommendation panel */
567
+ .btn-primary { background: linear-gradient(145deg, var(--accent), var(--accent-strong)); color: var(--accent-contrast); border-color: transparent; box-shadow: 0 6px 16px -6px var(--accent-ring); }
568
+ .btn-primary:hover { filter: brightness(1.06); border-color: transparent; }
569
+ .suggest-card { margin-top: 6px; padding: 12px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface-3); }
570
+ .suggest-rationale { font-size: 12px; line-height: 1.5; margin: 0 0 8px; color: var(--text-dim); }
571
+ .suggest-evidence { font-size: 11px; font-family: var(--mono); margin-bottom: 8px; }
572
+ .ev-row { display: grid; grid-template-columns: 1.5fr 1fr 0.9fr 0.9fr; gap: 6px; padding: 2px 0; opacity: 0.72; }
573
+ .ev-row.best { opacity: 1; font-weight: 650; color: var(--text); }
574
 
575
  /* Online (Gemini) settings */
576
+ .online-input { width: 100%; margin-bottom: 6px; font-family: var(--mono); font-size: 12px; }
577
  .online-key-actions { display: flex; align-items: center; gap: 8px; }
578
  .online-status { font-size: 11px; }
579
  .online-status.good { color: var(--green); }
580
  .online-status.bad { color: var(--red); }
581
 
582
+ /* Remove (x) button on a file card */
583
+ .btn-remove { color: var(--text-dim); font-size: 18px; line-height: 1; padding: 3px 9px; font-weight: 700; box-shadow: none; border-color: transparent; background: transparent; }
584
+ .btn-remove:hover { color: var(--red); background: var(--red-soft); transform: none; }
585
 
586
  /* Settings group sub-headings */
587
  .setting-group-label {
588
+ font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.09em;
589
+ color: var(--text-faint); margin: 20px 0 6px; padding-top: 16px;
590
  border-top: 1px solid var(--border-soft);
591
  }
592
+
593
+ @media (prefers-reduced-motion: reduce) {
594
+ * { transition: none !important; animation: none !important; }
595
+ }