forked from
me.webbeef.org/browser.html
Rewild Your Web
1/* SPDX-License-Identifier: AGPL-3.0-or-later */
2
3/*
4 * Beaver Remote Control — a warm, tactile phone interface
5 * for controlling The Hearth media center.
6 * Feels like holding a handcrafted wooden remote.
7 */
8
9* {
10 margin: 0;
11 padding: 0;
12 box-sizing: border-box;
13}
14
15html, body {
16 width: 100%;
17 height: 100%;
18 font-family: var(--font-family-base);
19 background: var(--bg-main);
20 color: var(--color-text-menu);
21 overflow: hidden;
22 user-select: none;
23 -webkit-user-select: none;
24 -webkit-tap-highlight-color: transparent;
25}
26
27.screen {
28 width: 100%;
29 height: 100%;
30 display: flex;
31 flex-direction: column;
32}
33
34.hidden {
35 display: none !important;
36}
37
38/* ===== Device Selector ===== */
39
40.selector-header {
41 padding: 3.5em 2em 1.5em;
42 text-align: center;
43}
44
45.app-title {
46 font-family: Pacifico, cursive;
47 font-size: 2.4em;
48 color: var(--color-text);
49 line-height: 1.1;
50}
51
52.app-subtitle {
53 font-size: 0.85em;
54 color: var(--color-text-tertiary);
55 margin-top: 0.4em;
56 letter-spacing: 0.04em;
57 text-transform: uppercase;
58}
59
60.device-list {
61 flex: 1;
62 padding: 1.5em;
63 overflow-y: auto;
64}
65
66.loading {
67 display: flex;
68 flex-direction: column;
69 align-items: center;
70 gap: 1.2em;
71 padding: 4em 2em;
72 color: var(--color-text-tertiary);
73 font-size: 0.9em;
74}
75
76.spinner {
77 font-size: 2em;
78 color: var(--color-primary);
79 animation: spin 1.5s linear infinite;
80}
81
82@keyframes spin {
83 to { transform: rotate(360deg); }
84}
85
86.device-item {
87 display: flex;
88 align-items: center;
89 gap: 1em;
90 padding: 1.2em 1.4em;
91 background: var(--bg-surface);
92 border-radius: var(--radius-md);
93 margin-bottom: 0.5em;
94 cursor: pointer;
95 transition:
96 background 0.18s cubic-bezier(0.16, 1, 0.3, 1),
97 transform 0.12s cubic-bezier(0.16, 1, 0.3, 1);
98 border: 1px solid var(--color-border);
99}
100
101.device-item:active {
102 background: var(--bg-hover);
103 transform: scale(0.97);
104}
105
106.device-item lucide-icon {
107 font-size: 1.4em;
108 color: var(--color-primary);
109}
110
111.device-item-info {
112 flex: 1;
113}
114
115.device-item-name {
116 font-weight: var(--font-weight-bold);
117 font-size: 1em;
118}
119
120.device-item-status {
121 font-size: var(--font-size-sm);
122 color: var(--color-text-secondary);
123 margin-top: 0.1em;
124}
125
126.no-devices {
127 text-align: center;
128 padding: 4em 2em;
129 color: var(--color-text-tertiary);
130 line-height: 1.6;
131 font-size: 0.9em;
132}
133
134/* ===== Guest Connect ===== */
135
136.device-item-guest {
137 display: flex;
138 align-items: center;
139 gap: 1em;
140 padding: 1.2em 1.4em;
141 background: none;
142 border-radius: var(--radius-md);
143 margin-bottom: 0.5em;
144 cursor: pointer;
145 transition:
146 background 0.18s cubic-bezier(0.16, 1, 0.3, 1),
147 transform 0.12s cubic-bezier(0.16, 1, 0.3, 1);
148 border: 1px dashed var(--color-border);
149}
150
151.device-item-guest:active {
152 background: var(--bg-hover);
153 transform: scale(0.97);
154}
155
156.device-item-guest lucide-icon {
157 font-size: 1.4em;
158 color: var(--color-text-secondary);
159}
160
161/* ===== PIN Entry ===== */
162
163.pin-form {
164 display: flex;
165 flex-direction: column;
166 align-items: center;
167 padding: 2em;
168 gap: 1.5em;
169}
170
171.pin-input {
172 width: 10em;
173 font-size: 2em;
174 text-align: center;
175 letter-spacing: 0.3em;
176 padding: 0.5em 0.6em;
177 background: var(--bg-surface);
178 border: 2px solid var(--color-border);
179 border-radius: var(--radius-md);
180 color: var(--color-text);
181 font-family: var(--font-family-base);
182 font-weight: var(--font-weight-bold);
183 caret-color: var(--color-primary);
184 transition: border-color 0.18s cubic-bezier(0.16, 1, 0.3, 1);
185}
186
187.pin-input:focus {
188 outline: none;
189 border-color: var(--color-primary);
190 box-shadow: 0 0 0 3px var(--color-focus-ring);
191}
192
193.pin-error {
194 color: var(--color-danger);
195 font-size: var(--font-size-sm);
196}
197
198.pin-actions {
199 display: flex;
200 gap: 1em;
201 margin-top: 0.5em;
202}
203
204.pin-btn {
205 padding: 0.8em 2em;
206 border-radius: var(--radius-md);
207 border: 1px solid var(--color-border);
208 background: var(--bg-surface);
209 color: var(--color-text);
210 font-family: var(--font-family-base);
211 font-size: 1em;
212 cursor: pointer;
213 transition:
214 background 0.18s cubic-bezier(0.16, 1, 0.3, 1),
215 transform 0.1s cubic-bezier(0.16, 1, 0.3, 1);
216}
217
218.pin-btn:active {
219 transform: scale(0.95);
220}
221
222.pin-btn:disabled {
223 opacity: 0.5;
224 cursor: not-allowed;
225}
226
227.pin-btn-submit {
228 background: var(--color-primary);
229 border-color: var(--color-primary);
230 color: var(--color-text-on-header);
231 font-weight: var(--font-weight-bold);
232}
233
234.pin-btn-cancel {
235 background: none;
236}
237
238/* ===== Connection Bar ===== */
239
240.connection-bar {
241 display: flex;
242 align-items: center;
243 gap: 0.6em;
244 padding: 0.7em 1.2em;
245 background: var(--bg-header);
246 border-bottom: 1px solid var(--color-border);
247}
248
249.connected-icon {
250 color: var(--color-primary);
251 font-size: 0.9em;
252}
253
254#connected-name {
255 flex: 1;
256 font-size: var(--font-size-sm);
257 font-weight: var(--font-weight-bold);
258 color: var(--color-text-secondary);
259}
260
261.disconnect-btn {
262 background: none;
263 border: none;
264 color: var(--color-text-tertiary);
265 padding: 0.5em;
266 cursor: pointer;
267 border-radius: 50%;
268 transition: background 0.18s cubic-bezier(0.16, 1, 0.3, 1);
269}
270
271.disconnect-btn:active {
272 background: var(--bg-hover);
273}
274
275/* ===== Now Playing ===== */
276
277.now-playing {
278 padding: 1em 1.4em;
279 background: var(--bg-menu);
280 border-bottom: 1px solid var(--color-border);
281}
282
283.now-playing-info {
284 text-align: center;
285 margin-bottom: 0.8em;
286}
287
288.np-title {
289 font-weight: var(--font-weight-bold);
290 font-size: 1em;
291 white-space: nowrap;
292 overflow: hidden;
293 text-overflow: ellipsis;
294}
295
296.np-artist {
297 font-size: var(--font-size-sm);
298 color: var(--color-text-secondary);
299 margin-top: 0.1em;
300}
301
302.transport-controls {
303 display: flex;
304 align-items: center;
305 justify-content: center;
306 gap: 0.8em;
307}
308
309.transport-btn {
310 display: flex;
311 align-items: center;
312 justify-content: center;
313 width: 3em;
314 height: 3em;
315 border-radius: 50%;
316 background: none;
317 border: none;
318 color: var(--color-text);
319 cursor: pointer;
320 transition:
321 background 0.05s cubic-bezier(0.16, 1, 0.3, 1),
322 transform 0.05s cubic-bezier(0.16, 1, 0.3, 1);
323}
324
325.transport-btn:active {
326 background: var(--bg-hover);
327 transform: translateY(1px);
328}
329
330.transport-btn.play-btn {
331 width: 3.5em;
332 height: 3.5em;
333 background: var(--bg-surface);
334 border: 1px solid var(--color-border);
335 box-shadow:
336 0 2px 0 var(--color-border),
337 0 2px 4px var(--color-shadow);
338}
339
340.transport-btn.play-btn:active {
341 box-shadow: none;
342 transform: translateY(2px);
343}
344
345.transport-btn lucide-icon {
346 font-size: 1.2em;
347}
348
349.transport-btn.play-btn lucide-icon {
350 font-size: 1.4em;
351}
352
353/* ===== D-Pad ===== */
354
355.dpad-area {
356 flex: 1;
357 display: flex;
358 align-items: center;
359 justify-content: center;
360 padding: 1.5em;
361}
362
363.dpad {
364 display: grid;
365 grid-template-columns: 1fr 1fr 1fr;
366 grid-template-rows: 1fr 1fr 1fr;
367 gap: 6px;
368 width: min(280px, 72vw);
369 aspect-ratio: 1;
370}
371
372.dpad-btn {
373 display: flex;
374 align-items: center;
375 justify-content: center;
376 background: var(--bg-surface);
377 border: 1px solid var(--color-border);
378 color: var(--color-text);
379 cursor: pointer;
380 font-family: var(--font-family-base);
381 font-size: 1em;
382 box-shadow:
383 0 2px 0 var(--color-border),
384 0 2px 4px var(--color-shadow);
385 transition:
386 background 0.05s cubic-bezier(0.16, 1, 0.3, 1),
387 box-shadow 0.05s cubic-bezier(0.16, 1, 0.3, 1),
388 transform 0.05s cubic-bezier(0.16, 1, 0.3, 1);
389}
390
391.dpad-btn:active {
392 background: var(--color-menu-item-hover);
393 box-shadow: none;
394 transform: translateY(2px);
395}
396
397.dpad-btn lucide-icon {
398 font-size: 1.8em;
399}
400
401.dpad-btn.up {
402 grid-column: 2;
403 grid-row: 1;
404 border-radius: var(--radius-md) var(--radius-md) 4px 4px;
405}
406
407.dpad-btn.down {
408 grid-column: 2;
409 grid-row: 3;
410 border-radius: 4px 4px var(--radius-md) var(--radius-md);
411}
412
413.dpad-btn.left {
414 grid-column: 1;
415 grid-row: 2;
416 border-radius: var(--radius-md) 4px 4px var(--radius-md);
417}
418
419.dpad-btn.right {
420 grid-column: 3;
421 grid-row: 2;
422 border-radius: 4px var(--radius-md) var(--radius-md) 4px;
423}
424
425.dpad-btn.ok {
426 grid-column: 2;
427 grid-row: 2;
428 background: var(--color-primary);
429 border-color: var(--color-primary);
430 color: var(--color-text-on-header);
431 font-weight: var(--font-weight-bold);
432 font-size: 1.1em;
433 border-radius: 50%;
434 letter-spacing: 0.05em;
435 box-shadow:
436 0 2px 0 oklch(35% 0.08 155),
437 0 2px 6px var(--color-shadow);
438}
439
440.dpad-btn.ok:active {
441 box-shadow: none;
442 transform: translateY(2px);
443 opacity: 0.9;
444}
445
446/* ===== Utility Bar ===== */
447
448.utility-bar {
449 display: flex;
450 justify-content: center;
451 gap: 0.8em;
452 padding: 0.8em 1.5em 2em;
453}
454
455.utility-btn {
456 display: flex;
457 align-items: center;
458 justify-content: center;
459 width: 3.2em;
460 height: 3.2em;
461 background: var(--bg-surface);
462 border: 1px solid var(--color-border);
463 color: var(--color-text-secondary);
464 cursor: pointer;
465 border-radius: var(--radius-md);
466 font-family: var(--font-family-base);
467 box-shadow:
468 0 2px 0 var(--color-border),
469 0 2px 4px var(--color-shadow);
470 transition:
471 background 0.05s cubic-bezier(0.16, 1, 0.3, 1),
472 box-shadow 0.05s cubic-bezier(0.16, 1, 0.3, 1),
473 transform 0.05s cubic-bezier(0.16, 1, 0.3, 1);
474}
475
476.utility-btn:active {
477 background: var(--color-menu-item-hover);
478 box-shadow: none;
479 transform: translateY(2px);
480}
481
482.utility-btn lucide-icon {
483 font-size: 1.3em;
484}