comparison mrjunejune/src/jrpg/jrpg.css @ 259:667156fcd3e3

Add dev-only cyberpunk JRPG page
author MrJuneJune <me@mrjunejune.com>
date Wed, 05 Aug 2026 09:19:41 -0700
parents
children 1f9877b637e9
comparison
equal deleted inserted replaced
258:60a876c4587a 259:667156fcd3e3
1 @font-face {
2 font-family: "Pixel Mplus";
3 src: url("/public/fonts/pixel-mplus-12-regular.ttf") format("truetype");
4 font-display: block;
5 }
6
7 :root {
8 --mjj-jrpg-art: url("/public/jrpg/bar-ink.webp");
9 --mjj-jrpg-canvas: var(--zenbu-sys-color-surface-page);
10 --mjj-jrpg-surface: var(--zenbu-sys-color-surface-default);
11 --mjj-jrpg-surface-raised: var(--zenbu-sys-color-surface-raised);
12 --mjj-jrpg-surface-sunken: var(--zenbu-sys-color-surface-sunken);
13 --mjj-jrpg-text: var(--zenbu-sys-color-text-primary);
14 --mjj-jrpg-text-muted: var(--zenbu-sys-color-text-secondary);
15 --mjj-jrpg-frame: var(--zenbu-sys-color-border-strong);
16 --mjj-jrpg-frame-soft: var(--zenbu-sys-color-border-subtle);
17 --mjj-jrpg-primary: var(--zenbu-sys-color-action-primary-background);
18 --mjj-jrpg-primary-hover:
19 var(--zenbu-sys-color-action-primary-background-hover);
20 --mjj-jrpg-primary-foreground:
21 var(--zenbu-sys-color-action-primary-foreground);
22 --mjj-jrpg-accent: var(--zenbu-sys-color-danger-foreground);
23 --mjj-jrpg-highlight: var(--zenbu-sys-color-warning-foreground);
24 --mjj-jrpg-info: var(--zenbu-sys-color-info-foreground);
25 --mjj-jrpg-success: var(--zenbu-sys-color-success-foreground);
26 --mjj-jrpg-focus: var(--zenbu-sys-color-focus-outer);
27 --mjj-jrpg-panel: color-mix(
28 in srgb,
29 var(--mjj-jrpg-surface) 92%,
30 transparent
31 );
32 --mjj-jrpg-panel-strong: color-mix(
33 in srgb,
34 var(--mjj-jrpg-surface-sunken) 92%,
35 transparent
36 );
37 }
38
39 .jrpg-page {
40 --zenbu-sys-font-family-ui: "Pixel Mplus";
41 --zenbu-sys-font-family-content: "Pixel Mplus";
42 --zenbu-sys-font-family-code: "Pixel Mplus";
43 min-width: 20rem;
44 min-height: 100dvh;
45 overflow: hidden;
46 overflow-anchor: none;
47 background: var(--mjj-jrpg-canvas);
48 color: var(--mjj-jrpg-text);
49 font-family: "Pixel Mplus";
50 font-size: var(--zenbu-sys-font-size-md);
51 line-height: var(--zenbu-sys-line-height-md);
52 }
53
54 .jrpg-page * {
55 font-family: inherit;
56 }
57
58 .jrpg-main {
59 box-sizing: border-box;
60 width: 100%;
61 max-width: none;
62 height: 100dvh;
63 min-height: 0;
64 padding: 0;
65 }
66
67 .jrpg-shell {
68 box-sizing: border-box;
69 display: block;
70 width: 100%;
71 max-width: none;
72 height: 100%;
73 margin: 0;
74 padding: var(--zenbu-sys-padding-sm);
75 border: var(--zenbu-sys-stroke-width-emphasis) solid var(--mjj-jrpg-frame);
76 background: var(--mjj-jrpg-canvas);
77 box-shadow:
78 inset 0 0 0 var(--zenbu-sys-stroke-width)
79 var(--mjj-jrpg-frame-soft);
80 }
81
82 .jrpg-workspace {
83 display: grid;
84 grid-template:
85 "scene utility" minmax(0, 1fr)
86 "composer menu" minmax(9rem, auto) /
87 minmax(0, 1.22fr) minmax(19rem, 0.95fr);
88 gap: var(--zenbu-sys-space-group);
89 height: 100%;
90 min-height: 0;
91 }
92
93 .jrpg-scene,
94 .jrpg-utility,
95 mjj-jrpg-composer,
96 mjj-jrpg-menu,
97 .jrpg-preview-panel {
98 box-sizing: border-box;
99 border: var(--zenbu-sys-stroke-width-emphasis) solid var(--mjj-jrpg-frame);
100 border-radius: 0;
101 }
102
103 .jrpg-scene {
104 grid-area: scene;
105 display: grid;
106 grid-template-columns: minmax(8rem, 0.38fr) minmax(15rem, 0.92fr);
107 align-items: end;
108 gap: var(--zenbu-sys-space-group);
109 min-height: 0;
110 padding: var(--zenbu-sys-padding-lg);
111 overflow: hidden;
112 background-image:
113 linear-gradient(
114 to top,
115 color-mix(
116 in srgb,
117 var(--mjj-jrpg-canvas) 56%,
118 transparent
119 ),
120 transparent 55%
121 ),
122 var(--mjj-jrpg-art);
123 background-position: center;
124 background-size: cover;
125 }
126
127 mjj-jrpg-character {
128 display: block;
129 align-self: end;
130 min-width: 0;
131 filter: drop-shadow(
132 var(--zenbu-sys-space-related)
133 var(--zenbu-sys-space-related)
134 0
135 color-mix(in srgb, var(--mjj-jrpg-frame) 35%, transparent)
136 );
137 }
138
139 mjj-jrpg-character img {
140 display: block;
141 width: 100%;
142 max-height: 25rem;
143 object-fit: contain;
144 object-position: center bottom;
145 border-radius: 0;
146 animation: mjj-jrpg-idle 2.4s steps(2, end) infinite;
147 }
148
149 mjj-jrpg-character[state="thinking"] img {
150 animation-duration: 0.8s;
151 }
152
153 @keyframes mjj-jrpg-idle {
154 50% { transform: translateY(calc(var(--zenbu-sys-space-related) * -1)); }
155 }
156
157 mjj-jrpg-chat {
158 position: relative;
159 display: grid;
160 grid-template-rows: auto minmax(0, 1fr) auto;
161 align-self: stretch;
162 min-height: 0;
163 padding: var(--zenbu-sys-padding-md);
164 border: var(--zenbu-sys-stroke-width-emphasis) solid var(--mjj-jrpg-frame);
165 background: var(--mjj-jrpg-panel-strong);
166 box-shadow:
167 inset 0 0 0 var(--zenbu-sys-stroke-width)
168 var(--mjj-jrpg-info);
169 }
170
171 .jrpg-panel-heading {
172 display: flex;
173 align-items: baseline;
174 justify-content: space-between;
175 gap: var(--zenbu-sys-space-group);
176 padding-bottom: var(--zenbu-sys-padding-sm);
177 border-bottom: var(--zenbu-sys-stroke-width) solid var(--mjj-jrpg-frame-soft);
178 }
179
180 .jrpg-panel-heading span,
181 .jrpg-preview-kicker,
182 .jrpg-menu-label,
183 .jrpg-brand > p,
184 .jrpg-dialog-heading p,
185 .jrpg-preview-stats dt {
186 color: var(--mjj-jrpg-text-muted);
187 font-size: var(--zenbu-sys-font-size-xs);
188 letter-spacing: 0.08em;
189 }
190
191 .jrpg-panel-heading h1 {
192 margin: 0;
193 color: var(--mjj-jrpg-text);
194 font-size: var(--zenbu-sys-font-size-lg);
195 }
196
197 zen-message-scroller,
198 .jrpg-message-viewport {
199 display: block;
200 min-height: 0;
201 height: 100%;
202 }
203
204 .jrpg-message-viewport {
205 overflow-y: auto;
206 overflow-anchor: none;
207 overscroll-behavior: contain;
208 scrollbar-color: var(--mjj-jrpg-frame) transparent;
209 }
210
211 .jrpg-messages {
212 display: grid;
213 gap: var(--zenbu-sys-space-group);
214 margin: 0;
215 padding: var(--zenbu-sys-padding-md) 0;
216 list-style: none;
217 }
218
219 .jrpg-message {
220 display: grid;
221 grid-template-columns: minmax(4rem, auto) 1fr;
222 gap: var(--zenbu-sys-space-control);
223 padding-left: var(--zenbu-sys-padding-sm);
224 border-left: var(--zenbu-sys-stroke-width-emphasis) solid var(--mjj-jrpg-accent);
225 }
226
227 .jrpg-message[data-speaker="June"] {
228 border-left-color: var(--mjj-jrpg-info);
229 }
230
231 .jrpg-message strong {
232 color: var(--mjj-jrpg-highlight);
233 font-weight: var(--zenbu-sys-font-weight-bold);
234 }
235
236 .jrpg-message p {
237 margin: 0;
238 color: var(--mjj-jrpg-text);
239 }
240
241 .jrpg-next {
242 display: flex;
243 align-items: center;
244 justify-content: end;
245 gap: var(--zenbu-sys-space-icon-label);
246 margin: 0;
247 color: var(--mjj-jrpg-primary);
248 font-size: var(--zenbu-sys-font-size-xs);
249 }
250
251 .jrpg-utility {
252 grid-area: utility;
253 display: grid;
254 grid-template-rows: auto minmax(0, 1fr);
255 gap: var(--zenbu-sys-space-group);
256 padding: var(--zenbu-sys-padding-md);
257 background: var(--mjj-jrpg-surface);
258 }
259
260 .jrpg-brand {
261 display: flex;
262 align-items: end;
263 justify-content: space-between;
264 gap: var(--zenbu-sys-space-control);
265 padding: 0 var(--zenbu-sys-padding-sm) var(--zenbu-sys-padding-sm);
266 border-bottom: var(--zenbu-sys-stroke-width-emphasis) solid var(--mjj-jrpg-frame);
267 }
268
269 body.jrpg-page .jrpg-brand header {
270 width: auto;
271 max-width: none;
272 margin: 0;
273 padding: 0;
274 text-align: left;
275 }
276
277 body.jrpg-page .jrpg-brand header h1 {
278 margin: 0;
279 color: var(--mjj-jrpg-primary);
280 font-size: var(--zenbu-sys-font-size-2xl);
281 letter-spacing: 0;
282 text-shadow:
283 var(--zenbu-sys-space-icon-label)
284 var(--zenbu-sys-space-icon-label)
285 0
286 var(--mjj-jrpg-accent);
287 }
288
289 .jrpg-brand > p {
290 margin: 0;
291 color: var(--mjj-jrpg-highlight);
292 text-align: right;
293 }
294
295 mjj-jrpg-preview {
296 display: block;
297 min-height: 0;
298 }
299
300 .jrpg-preview-panel {
301 display: grid;
302 grid-template-rows: auto auto minmax(0, 1fr) auto auto;
303 gap: var(--zenbu-sys-space-group);
304 height: 100%;
305 padding: var(--zenbu-sys-padding-lg);
306 background:
307 linear-gradient(
308 135deg,
309 var(--mjj-jrpg-surface-raised),
310 var(--mjj-jrpg-surface)
311 );
312 box-shadow:
313 inset 0 0 0 var(--zenbu-sys-stroke-width)
314 var(--mjj-jrpg-accent);
315 }
316
317 .jrpg-preview-panel h2,
318 .jrpg-preview-panel p {
319 margin: 0;
320 }
321
322 .jrpg-preview-panel h2 {
323 color: var(--mjj-jrpg-primary);
324 }
325
326 .jrpg-preview-panel > p:not(.jrpg-preview-kicker) {
327 color: var(--mjj-jrpg-text);
328 }
329
330 .jrpg-preview-stats {
331 display: grid;
332 grid-template-columns: repeat(2, 1fr);
333 gap: var(--zenbu-sys-space-control);
334 margin: 0;
335 }
336
337 .jrpg-preview-stats div {
338 padding: var(--zenbu-sys-padding-sm);
339 border: var(--zenbu-sys-stroke-width) solid var(--mjj-jrpg-frame-soft);
340 background: var(--mjj-jrpg-panel);
341 }
342
343 .jrpg-preview-stats dd {
344 color: var(--mjj-jrpg-success);
345 margin: var(--zenbu-sys-space-icon-label) 0 0;
346 }
347
348 .jrpg-preview-dialog > zen-button > button,
349 .jrpg-preview-dialog dialog zen-button > :where(button, a) {
350 width: 100%;
351 border: var(--zenbu-sys-stroke-width-emphasis) solid var(--mjj-jrpg-frame);
352 border-radius: 0;
353 background: var(--mjj-jrpg-primary);
354 color: var(--mjj-jrpg-primary-foreground);
355 cursor: pointer;
356 }
357
358 .jrpg-preview-dialog > zen-button > button:hover,
359 .jrpg-preview-dialog dialog zen-button > :where(button, a):hover {
360 border-color: var(--mjj-jrpg-primary-hover);
361 background: var(--mjj-jrpg-primary-hover);
362 }
363
364 .jrpg-preview-dialog dialog {
365 box-sizing: border-box;
366 width: min(82vw, 46rem);
367 max-width: calc(100% - var(--zenbu-sys-space-content));
368 padding: var(--zenbu-sys-padding-xl);
369 border: var(--zenbu-sys-stroke-width-emphasis) solid var(--mjj-jrpg-frame);
370 border-radius: 0;
371 background: var(--mjj-jrpg-surface-raised);
372 color: var(--mjj-jrpg-text);
373 box-shadow:
374 inset 0 0 0 var(--zenbu-sys-stroke-width)
375 var(--mjj-jrpg-accent),
376 var(--zenbu-sys-space-control)
377 var(--zenbu-sys-space-control)
378 0
379 var(--mjj-jrpg-accent);
380 }
381
382 .jrpg-preview-dialog dialog::backdrop {
383 background: color-mix(in srgb, var(--mjj-jrpg-canvas) 84%, transparent);
384 }
385
386 .jrpg-preview-dialog dialog[open] {
387 animation: mjj-jrpg-dialog-open var(--zenbu-sys-motion-duration-layout)
388 var(--zenbu-sys-motion-ease-enter);
389 }
390
391 @keyframes mjj-jrpg-dialog-open {
392 from {
393 clip-path: inset(48% 25%);
394 transform: scaleX(0.35);
395 }
396 to {
397 clip-path: inset(0);
398 transform: scaleX(1);
399 }
400 }
401
402 .jrpg-dialog-heading {
403 display: flex;
404 align-items: center;
405 justify-content: space-between;
406 gap: var(--zenbu-sys-space-group);
407 padding-bottom: var(--zenbu-sys-padding-md);
408 border-bottom: var(--zenbu-sys-stroke-width) solid var(--mjj-jrpg-frame-soft);
409 }
410
411 .jrpg-dialog-heading p,
412 .jrpg-preview-dialog dialog > p {
413 margin: 0;
414 }
415
416 .jrpg-dialog-heading zen-button {
417 width: auto;
418 }
419
420 .jrpg-dialog-heading zen-button > button {
421 width: var(--zenbu-control-height);
422 min-width: var(--zenbu-control-height);
423 padding: 0;
424 border-color: var(--mjj-jrpg-accent);
425 background: var(--mjj-jrpg-surface);
426 color: var(--mjj-jrpg-text);
427 }
428
429 .jrpg-preview-dialog dialog h2 {
430 margin-top: var(--zenbu-sys-space-content);
431 }
432
433 .jrpg-preview-dialog dialog > p {
434 margin-bottom: var(--zenbu-sys-space-content);
435 }
436
437 mjj-jrpg-composer {
438 grid-area: composer;
439 display: block;
440 padding: var(--zenbu-sys-padding-md);
441 background: var(--mjj-jrpg-surface);
442 }
443
444 .jrpg-composer {
445 display: grid;
446 grid-template-columns: minmax(0, 1fr) auto;
447 gap: var(--zenbu-sys-space-control);
448 }
449
450 .jrpg-composer zen-field {
451 display: grid;
452 gap: var(--zenbu-sys-space-icon-label);
453 }
454
455 .jrpg-composer label,
456 .jrpg-composer-hint {
457 grid-column: 1 / -1;
458 color: var(--mjj-jrpg-text-muted);
459 font-size: var(--zenbu-sys-font-size-xs);
460 }
461
462 .jrpg-composer textarea {
463 box-sizing: border-box;
464 width: 100%;
465 min-height: calc(var(--zenbu-control-height) * 2);
466 resize: vertical;
467 padding:
468 var(--zenbu-control-padding-block)
469 var(--zenbu-control-padding-inline);
470 border: var(--zenbu-sys-stroke-width-emphasis) solid var(--mjj-jrpg-frame);
471 border-radius: 0;
472 background: var(--mjj-jrpg-surface-sunken);
473 color: var(--mjj-jrpg-text);
474 font: inherit;
475 }
476
477 .jrpg-composer textarea::placeholder {
478 color: var(--mjj-jrpg-text-muted);
479 }
480
481 .jrpg-page :where(a, button, textarea):focus-visible {
482 outline: var(--zenbu-sys-focus-width) solid var(--mjj-jrpg-focus);
483 outline-offset: var(--zenbu-sys-focus-offset);
484 }
485
486 .jrpg-composer zen-button {
487 align-self: end;
488 }
489
490 .jrpg-composer zen-button > button {
491 border: var(--zenbu-sys-stroke-width-emphasis) solid var(--mjj-jrpg-frame);
492 border-radius: 0;
493 background: var(--mjj-jrpg-primary);
494 color: var(--mjj-jrpg-primary-foreground);
495 cursor: pointer;
496 }
497
498 .jrpg-composer zen-button > button:hover {
499 border-color: var(--mjj-jrpg-primary-hover);
500 background: var(--mjj-jrpg-primary-hover);
501 }
502
503 .jrpg-composer button:disabled {
504 opacity: var(--zenbu-sys-opacity-disabled);
505 cursor: not-allowed;
506 }
507
508 .jrpg-composer-hint {
509 margin: 0;
510 }
511
512 mjj-jrpg-menu {
513 grid-area: menu;
514 display: block;
515 padding: var(--zenbu-sys-padding-md);
516 background: var(--mjj-jrpg-surface-sunken);
517 }
518
519 mjj-jrpg-menu nav {
520 display: grid;
521 grid-template-columns: auto 1fr;
522 align-items: center;
523 gap: var(--zenbu-sys-space-group);
524 height: 100%;
525 }
526
527 .jrpg-menu-label {
528 margin: 0;
529 writing-mode: vertical-rl;
530 }
531
532 mjj-jrpg-menu ul {
533 display: grid;
534 grid-template-columns: repeat(2, minmax(0, 1fr));
535 gap: var(--zenbu-sys-space-control);
536 margin: 0;
537 padding: 0;
538 list-style: none;
539 }
540
541 mjj-jrpg-menu zen-button,
542 mjj-jrpg-menu button {
543 width: 100%;
544 }
545
546 mjj-jrpg-menu button {
547 justify-content: start;
548 border: var(--zenbu-sys-stroke-width) solid transparent;
549 border-radius: 0;
550 background: transparent;
551 color: var(--mjj-jrpg-text);
552 cursor: pointer;
553 }
554
555 mjj-jrpg-menu button:hover {
556 border-color: var(--mjj-jrpg-accent);
557 color: var(--mjj-jrpg-primary-hover);
558 }
559
560 mjj-jrpg-menu button[aria-pressed="true"] {
561 border-color: var(--mjj-jrpg-frame);
562 background: var(--mjj-jrpg-surface-raised);
563 color: var(--mjj-jrpg-primary);
564 }
565
566 mjj-jrpg-menu button zen-icon {
567 opacity: 0;
568 }
569
570 mjj-jrpg-menu button[aria-pressed="true"] zen-icon {
571 opacity: 1;
572 }
573
574 @media (max-width: 52rem) {
575 .jrpg-page {
576 overflow-y: auto;
577 }
578
579 .jrpg-main {
580 height: auto;
581 min-height: 100dvh;
582 padding: 0;
583 }
584
585 .jrpg-shell {
586 height: auto;
587 min-height: 100dvh;
588 }
589
590 .jrpg-workspace {
591 grid-template:
592 "scene" auto
593 "utility" auto
594 "menu" auto
595 "composer" auto /
596 minmax(0, 1fr);
597 height: auto;
598 min-height: 0;
599 }
600
601 .jrpg-scene {
602 min-height: 34rem;
603 }
604
605 .jrpg-utility {
606 min-height: 27rem;
607 }
608
609 mjj-jrpg-menu nav {
610 grid-template-columns: 1fr;
611 }
612
613 .jrpg-menu-label {
614 writing-mode: initial;
615 }
616
617 mjj-jrpg-menu ul {
618 grid-template-columns: repeat(3, minmax(0, 1fr));
619 }
620 }
621
622 @media (max-width: 34rem) {
623 .jrpg-main {
624 padding: 0;
625 }
626
627 .jrpg-scene {
628 grid-template-columns: 1fr;
629 grid-template-rows: minmax(12rem, 0.6fr) minmax(20rem, 1fr);
630 min-height: 42rem;
631 padding: var(--zenbu-sys-padding-md);
632 }
633
634 mjj-jrpg-character {
635 justify-self: center;
636 width: min(15rem, 65%);
637 }
638
639 mjj-jrpg-character img {
640 max-height: 15rem;
641 }
642
643 .jrpg-brand {
644 align-items: center;
645 }
646
647 .jrpg-brand > p {
648 max-width: 9rem;
649 }
650
651 .jrpg-composer {
652 grid-template-columns: 1fr;
653 }
654
655 .jrpg-composer zen-button {
656 width: 100%;
657 }
658
659 .jrpg-composer zen-button > button {
660 width: 100%;
661 }
662
663 mjj-jrpg-menu ul {
664 grid-template-columns: 1fr;
665 }
666
667 .jrpg-preview-dialog dialog {
668 width: calc(100% - var(--zenbu-sys-space-group));
669 max-width: none;
670 padding: var(--zenbu-sys-padding-lg);
671 }
672 }
673
674 @media (prefers-reduced-motion: reduce) {
675 mjj-jrpg-character img,
676 .jrpg-preview-dialog dialog[open] {
677 animation: none;
678 }
679 }
680
681 @media (forced-colors: active) {
682 .jrpg-scene {
683 background-image: none;
684 }
685 }