@moood/render 0.0.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -29
- package/cli.js +34 -34
- package/engine/actions.js +69 -69
- package/engine/captions.js +20 -20
- package/engine/directions.js +44 -44
- package/engine/engine.js +1456 -1456
- package/engine/engine.json +1 -1
- package/engine/gl.js +1027 -1027
- package/engine/kit.js +142 -142
- package/engine/live.js +23 -23
- package/engine/mic.js +76 -76
- package/engine/music.css +28 -28
- package/engine/music.js +279 -279
- package/engine/nav.css +66 -66
- package/engine/render.html +50 -50
- package/engine/scene.css +124 -124
- package/engine/scenestate.js +220 -220
- package/engine/select.js +301 -301
- package/engine/speech.js +150 -150
- package/engine/volume.js +56 -56
- package/engine/widgets.js +88 -88
- package/index.js +70 -70
- package/package.json +27 -13
- package/scene.js +43 -43
package/engine/nav.css
CHANGED
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
/* Finding one's way, the same on every page: the crumbs — where I am: moood / a world / a game / … —
|
|
2
|
-
(templates/_crumbs.html), and the viewer — a scene looked at without leaving the page (viewer.js). */
|
|
3
|
-
|
|
4
|
-
.crumbs { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 7px; min-width: 0; font-family: Georgia, "Times New Roman", serif; }
|
|
5
|
-
.crumbs a { color: inherit; text-decoration: none; }
|
|
6
|
-
.crumbs a:hover { text-decoration: underline; }
|
|
7
|
-
.crumbs .brand { font-style: italic; }
|
|
8
|
-
.crumbs .brand .moon { color: #e8c98a; }
|
|
9
|
-
/* a small moon over the m, as in the sign (drawn, not a letter: what is copied is still "moood.me") */
|
|
10
|
-
.crumbs .brand .m { position: relative; }
|
|
11
|
-
.crumbs .brand .m::after { content: ""; position: absolute; left: 0.46em; top: 0.15em; width: 0.15em; height: 0.15em; border-radius: 50%; background: #e8c98a; pointer-events: none; }
|
|
12
|
-
.crumbs .brand .tld { opacity: 0.55; }
|
|
13
|
-
.crumbs .sep { opacity: 0.35; }
|
|
14
|
-
.crumbs .kind { margin-right: -3px; font-size: 0.78em; font-style: italic; opacity: 0.55; }
|
|
15
|
-
.crumbs form { display: inline; }
|
|
16
|
-
.crumbs button { border: 0; background: none; color: inherit; font: inherit; padding: 0; cursor: pointer; opacity: 0.7; }
|
|
17
|
-
.crumbs button:hover { opacity: 1; text-decoration: underline; }
|
|
18
|
-
.crumbs .volume { margin-left: 4px; font-size: 0.85em; }
|
|
19
|
-
.crumbs .volume:hover { text-decoration: none; }
|
|
20
|
-
/* how loud: the music and the voices (volume.js) */
|
|
21
|
-
#volume { position: fixed; z-index: 50; width: 220px; box-sizing: border-box; padding: 10px 12px; display: grid; gap: 8px;
|
|
22
|
-
border-radius: 10px; background: rgba(14, 17, 22, 0.94); border: 1px solid rgba(255, 255, 255, 0.12); backdrop-filter: blur(6px);
|
|
23
|
-
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45); color: rgba(236, 232, 224, 0.92); font: 14px/1.3 Georgia, "Times New Roman", serif; }
|
|
24
|
-
#volume[hidden] { display: none; }
|
|
25
|
-
#volume label { display: grid; grid-template-columns: 64px 1fr; align-items: center; gap: 8px; }
|
|
26
|
-
#volume input { width: 100%; accent-color: #e8c98a; }
|
|
27
|
-
/* over a scene full-screen: top-left */
|
|
28
|
-
#crumbs { position: fixed; left: 12px; top: 10px; z-index: 6; max-width: min(720px, calc(100vw - 24px)); padding: 4px 12px;
|
|
29
|
-
border-radius: 999px; background: rgba(10, 12, 18, 0.55); backdrop-filter: blur(6px); font-size: 14px; line-height: 1.4;
|
|
30
|
-
color: rgba(236, 232, 224, 0.92); }
|
|
31
|
-
|
|
32
|
-
/* a full-screen page whose thing is not there (shell.js lost) */
|
|
33
|
-
.lost { min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
|
|
34
|
-
padding: 16px; box-sizing: border-box; background: #0e1116; color: #d6dae1; font: 16px/1.5 Georgia, "Times New Roman", serif; }
|
|
35
|
-
.lost a { color: #e8c98a; }
|
|
36
|
-
.lost .crumbs { margin-bottom: 18px; font-size: 18px; }
|
|
37
|
-
|
|
38
|
-
/* the viewer */
|
|
39
|
-
.viewer-veil { position: fixed; inset: 0; z-index: 40; background: rgba(4, 6, 10, 0.6); opacity: 0; pointer-events: none; transition: opacity 0.32s ease; }
|
|
40
|
-
.viewer-veil.open { opacity: 1; pointer-events: auto; }
|
|
41
|
-
.viewer { position: fixed; z-index: 41; display: none; flex-direction: column; overflow: hidden; border-radius: 12px; background: #07080c;
|
|
42
|
-
box-shadow: 0 30px 80px rgba(0, 0, 0, 0.6); border: 1px solid rgba(255, 255, 255, 0.12); }
|
|
43
|
-
.viewer.open { display: flex; }
|
|
44
|
-
.viewer { transform-origin: 0 0; }
|
|
45
|
-
.viewer.moving { transition: transform 0.32s ease, clip-path 0.32s ease; }
|
|
46
|
-
/* the scene's picture, standing in its place until the scene has drawn itself (then fading out),
|
|
47
|
-
and coming back over it as the view shrinks back into it */
|
|
48
|
-
.viewer-still { position: absolute; object-fit: cover; pointer-events: none; }
|
|
49
|
-
.viewer-still.gone { opacity: 0; transition: opacity 0.3s ease; }
|
|
50
|
-
/* waiting for the scene, over its picture: a slow ring in the middle */
|
|
51
|
-
.viewer-wait { position: absolute; width: 34px; height: 34px; margin: -17px 0 0 -17px; border-radius: 50%;
|
|
52
|
-
border: 2px solid rgba(255, 255, 255, 0.18); border-top-color: rgba(255, 236, 200, 0.85); opacity: 0; pointer-events: none;
|
|
53
|
-
transition: opacity 0.3s ease; animation: viewer-wait 1s linear infinite; }
|
|
54
|
-
.viewer.waiting .viewer-wait { opacity: 1; }
|
|
55
|
-
@keyframes viewer-wait { to { transform: rotate(1turn); } }
|
|
56
|
-
.viewer.closing .viewer-still { opacity: 1; transition: opacity 0.25s ease; }
|
|
57
|
-
.viewer-bar { display: flex; align-items: center; gap: 8px; padding: 6px 10px; font: 14px/1.3 Georgia, "Times New Roman", serif;
|
|
58
|
-
color: rgba(236, 232, 224, 0.92); background: rgba(255, 255, 255, 0.04); border-bottom: 1px solid rgba(255, 255, 255, 0.08); }
|
|
59
|
-
.viewer-bar button { border: 1px solid rgba(255, 255, 255, 0.18); background: none; color: inherit; font: inherit; border-radius: 999px;
|
|
60
|
-
padding: 1px 10px; cursor: pointer; }
|
|
61
|
-
.viewer-bar button:hover:not(:disabled) { background: rgba(255, 255, 255, 0.1); }
|
|
62
|
-
.viewer-bar button:disabled { opacity: 0.3; cursor: default; }
|
|
63
|
-
.viewer-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-style: italic; }
|
|
64
|
-
.viewer-page { color: inherit; opacity: 0.75; font-size: 13px; text-decoration: none; }
|
|
65
|
-
.viewer-page:hover { opacity: 1; text-decoration: underline; }
|
|
66
|
-
.viewer-frame { flex: 1; border: 0; width: 100%; background: #07080c; }
|
|
1
|
+
/* Finding one's way, the same on every page: the crumbs — where I am: moood / a world / a game / … —
|
|
2
|
+
(templates/_crumbs.html), and the viewer — a scene looked at without leaving the page (viewer.js). */
|
|
3
|
+
|
|
4
|
+
.crumbs { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 7px; min-width: 0; font-family: Georgia, "Times New Roman", serif; }
|
|
5
|
+
.crumbs a { color: inherit; text-decoration: none; }
|
|
6
|
+
.crumbs a:hover { text-decoration: underline; }
|
|
7
|
+
.crumbs .brand { font-style: italic; }
|
|
8
|
+
.crumbs .brand .moon { color: #e8c98a; }
|
|
9
|
+
/* a small moon over the m, as in the sign (drawn, not a letter: what is copied is still "moood.me") */
|
|
10
|
+
.crumbs .brand .m { position: relative; }
|
|
11
|
+
.crumbs .brand .m::after { content: ""; position: absolute; left: 0.46em; top: 0.15em; width: 0.15em; height: 0.15em; border-radius: 50%; background: #e8c98a; pointer-events: none; }
|
|
12
|
+
.crumbs .brand .tld { opacity: 0.55; }
|
|
13
|
+
.crumbs .sep { opacity: 0.35; }
|
|
14
|
+
.crumbs .kind { margin-right: -3px; font-size: 0.78em; font-style: italic; opacity: 0.55; }
|
|
15
|
+
.crumbs form { display: inline; }
|
|
16
|
+
.crumbs button { border: 0; background: none; color: inherit; font: inherit; padding: 0; cursor: pointer; opacity: 0.7; }
|
|
17
|
+
.crumbs button:hover { opacity: 1; text-decoration: underline; }
|
|
18
|
+
.crumbs .volume { margin-left: 4px; font-size: 0.85em; }
|
|
19
|
+
.crumbs .volume:hover { text-decoration: none; }
|
|
20
|
+
/* how loud: the music and the voices (volume.js) */
|
|
21
|
+
#volume { position: fixed; z-index: 50; width: 220px; box-sizing: border-box; padding: 10px 12px; display: grid; gap: 8px;
|
|
22
|
+
border-radius: 10px; background: rgba(14, 17, 22, 0.94); border: 1px solid rgba(255, 255, 255, 0.12); backdrop-filter: blur(6px);
|
|
23
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45); color: rgba(236, 232, 224, 0.92); font: 14px/1.3 Georgia, "Times New Roman", serif; }
|
|
24
|
+
#volume[hidden] { display: none; }
|
|
25
|
+
#volume label { display: grid; grid-template-columns: 64px 1fr; align-items: center; gap: 8px; }
|
|
26
|
+
#volume input { width: 100%; accent-color: #e8c98a; }
|
|
27
|
+
/* over a scene full-screen: top-left */
|
|
28
|
+
#crumbs { position: fixed; left: 12px; top: 10px; z-index: 6; max-width: min(720px, calc(100vw - 24px)); padding: 4px 12px;
|
|
29
|
+
border-radius: 999px; background: rgba(10, 12, 18, 0.55); backdrop-filter: blur(6px); font-size: 14px; line-height: 1.4;
|
|
30
|
+
color: rgba(236, 232, 224, 0.92); }
|
|
31
|
+
|
|
32
|
+
/* a full-screen page whose thing is not there (shell.js lost) */
|
|
33
|
+
.lost { min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
|
|
34
|
+
padding: 16px; box-sizing: border-box; background: #0e1116; color: #d6dae1; font: 16px/1.5 Georgia, "Times New Roman", serif; }
|
|
35
|
+
.lost a { color: #e8c98a; }
|
|
36
|
+
.lost .crumbs { margin-bottom: 18px; font-size: 18px; }
|
|
37
|
+
|
|
38
|
+
/* the viewer */
|
|
39
|
+
.viewer-veil { position: fixed; inset: 0; z-index: 40; background: rgba(4, 6, 10, 0.6); opacity: 0; pointer-events: none; transition: opacity 0.32s ease; }
|
|
40
|
+
.viewer-veil.open { opacity: 1; pointer-events: auto; }
|
|
41
|
+
.viewer { position: fixed; z-index: 41; display: none; flex-direction: column; overflow: hidden; border-radius: 12px; background: #07080c;
|
|
42
|
+
box-shadow: 0 30px 80px rgba(0, 0, 0, 0.6); border: 1px solid rgba(255, 255, 255, 0.12); }
|
|
43
|
+
.viewer.open { display: flex; }
|
|
44
|
+
.viewer { transform-origin: 0 0; }
|
|
45
|
+
.viewer.moving { transition: transform 0.32s ease, clip-path 0.32s ease; }
|
|
46
|
+
/* the scene's picture, standing in its place until the scene has drawn itself (then fading out),
|
|
47
|
+
and coming back over it as the view shrinks back into it */
|
|
48
|
+
.viewer-still { position: absolute; object-fit: cover; pointer-events: none; }
|
|
49
|
+
.viewer-still.gone { opacity: 0; transition: opacity 0.3s ease; }
|
|
50
|
+
/* waiting for the scene, over its picture: a slow ring in the middle */
|
|
51
|
+
.viewer-wait { position: absolute; width: 34px; height: 34px; margin: -17px 0 0 -17px; border-radius: 50%;
|
|
52
|
+
border: 2px solid rgba(255, 255, 255, 0.18); border-top-color: rgba(255, 236, 200, 0.85); opacity: 0; pointer-events: none;
|
|
53
|
+
transition: opacity 0.3s ease; animation: viewer-wait 1s linear infinite; }
|
|
54
|
+
.viewer.waiting .viewer-wait { opacity: 1; }
|
|
55
|
+
@keyframes viewer-wait { to { transform: rotate(1turn); } }
|
|
56
|
+
.viewer.closing .viewer-still { opacity: 1; transition: opacity 0.25s ease; }
|
|
57
|
+
.viewer-bar { display: flex; align-items: center; gap: 8px; padding: 6px 10px; font: 14px/1.3 Georgia, "Times New Roman", serif;
|
|
58
|
+
color: rgba(236, 232, 224, 0.92); background: rgba(255, 255, 255, 0.04); border-bottom: 1px solid rgba(255, 255, 255, 0.08); }
|
|
59
|
+
.viewer-bar button { border: 1px solid rgba(255, 255, 255, 0.18); background: none; color: inherit; font: inherit; border-radius: 999px;
|
|
60
|
+
padding: 1px 10px; cursor: pointer; }
|
|
61
|
+
.viewer-bar button:hover:not(:disabled) { background: rgba(255, 255, 255, 0.1); }
|
|
62
|
+
.viewer-bar button:disabled { opacity: 0.3; cursor: default; }
|
|
63
|
+
.viewer-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-style: italic; }
|
|
64
|
+
.viewer-page { color: inherit; opacity: 0.75; font-size: 13px; text-decoration: none; }
|
|
65
|
+
.viewer-page:hover { opacity: 1; text-decoration: underline; }
|
|
66
|
+
.viewer-frame { flex: 1; border: 0; width: 100%; background: #07080c; }
|
package/engine/render.html
CHANGED
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="ru">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8">
|
|
5
|
-
<title>moood · render</title>
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
7
|
-
<link rel="stylesheet" href="scene.css">
|
|
8
|
-
<style>html, body { margin: 0; height: 100%; overflow: hidden; background: #000; } #scene { position: fixed; inset: 0; width: 100%; height: 100%; } .titles { right: 0; }</style>
|
|
9
|
-
</head>
|
|
10
|
-
<body>
|
|
11
|
-
<!-- A scene from its starting viewpoint, no UI — what the render service (services/render)
|
|
12
|
-
screenshots for the artist's look at its own work, the pictures of scenes and assistants (MCP).
|
|
13
|
-
The service hands the
|
|
14
|
-
spec in as window.__mooodSpec; errors the scene's code threw end up in
|
|
15
|
-
window.__mooodRenderErrors; the title turns "ready" when it is time to take the picture. -->
|
|
16
|
-
<canvas id="scene"></canvas>
|
|
17
|
-
<header class="titles"><h1 id="title"></h1><p id="caption"></p></header>
|
|
18
|
-
<script src="kit.js"></script>
|
|
19
|
-
<script src="engine.js"></script>
|
|
20
|
-
<script src="gl.js"></script>
|
|
21
|
-
<script src="captions.js"></script>
|
|
22
|
-
<script src="widgets.js"></script>
|
|
23
|
-
<script src="scenestate.js"></script>
|
|
24
|
-
<script>
|
|
25
|
-
(async () => {
|
|
26
|
-
const errors = [];
|
|
27
|
-
addEventListener('error', e => errors.push(String(e.message)));
|
|
28
|
-
try {
|
|
29
|
-
const spec = window.__mooodSpec;
|
|
30
|
-
const bare = new URLSearchParams(location.search).has('bare'); // a picture for the list: no text
|
|
31
|
-
if (!bare) {
|
|
32
|
-
document.getElementById('title').textContent = spec.title || '';
|
|
33
|
-
document.getElementById('caption').textContent = spec.caption || '';
|
|
34
|
-
}
|
|
35
|
-
const modules = { texts: window.__mooodModules || {} }; // the modules the scene lists, given (kit.js)
|
|
36
|
-
const canvas = document.getElementById('scene'), stage = Moood.mount(canvas);
|
|
37
|
-
stage.show(spec, modules);
|
|
38
|
-
MooodState.start(spec, {}, { stage, modules }); // the starting state, scripts running (their errors are reported)
|
|
39
|
-
if (!bare) MooodWidgets.create({ canvas, stage }).show({ ...spec, widgets: (spec.widgets || []).map(w => ({ ...w, at: 0, for: 0 })) });
|
|
40
|
-
// show every caption at once, so the reviewer reads them all
|
|
41
|
-
if (!bare) MooodCaptions.show((spec.captions || []).map(c => ({ ...c, at: 0, for: 0 })));
|
|
42
|
-
} catch (e) { errors.push(String(e.message || e)); }
|
|
43
|
-
await new Promise(r => setTimeout(r, 1500));
|
|
44
|
-
errors.push(...(window.__mooodErrors || []));
|
|
45
|
-
window.__mooodRenderErrors = errors;
|
|
46
|
-
document.title = 'ready';
|
|
47
|
-
})();
|
|
48
|
-
</script>
|
|
49
|
-
</body>
|
|
50
|
-
</html>
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="ru">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<title>moood · render</title>
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
7
|
+
<link rel="stylesheet" href="scene.css">
|
|
8
|
+
<style>html, body { margin: 0; height: 100%; overflow: hidden; background: #000; } #scene { position: fixed; inset: 0; width: 100%; height: 100%; } .titles { right: 0; }</style>
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<!-- A scene from its starting viewpoint, no UI — what the render service (services/render)
|
|
12
|
+
screenshots for the artist's look at its own work, the pictures of scenes and assistants (MCP).
|
|
13
|
+
The service hands the
|
|
14
|
+
spec in as window.__mooodSpec; errors the scene's code threw end up in
|
|
15
|
+
window.__mooodRenderErrors; the title turns "ready" when it is time to take the picture. -->
|
|
16
|
+
<canvas id="scene"></canvas>
|
|
17
|
+
<header class="titles"><h1 id="title"></h1><p id="caption"></p></header>
|
|
18
|
+
<script src="kit.js"></script>
|
|
19
|
+
<script src="engine.js"></script>
|
|
20
|
+
<script src="gl.js"></script>
|
|
21
|
+
<script src="captions.js"></script>
|
|
22
|
+
<script src="widgets.js"></script>
|
|
23
|
+
<script src="scenestate.js"></script>
|
|
24
|
+
<script>
|
|
25
|
+
(async () => {
|
|
26
|
+
const errors = [];
|
|
27
|
+
addEventListener('error', e => errors.push(String(e.message)));
|
|
28
|
+
try {
|
|
29
|
+
const spec = window.__mooodSpec;
|
|
30
|
+
const bare = new URLSearchParams(location.search).has('bare'); // a picture for the list: no text
|
|
31
|
+
if (!bare) {
|
|
32
|
+
document.getElementById('title').textContent = spec.title || '';
|
|
33
|
+
document.getElementById('caption').textContent = spec.caption || '';
|
|
34
|
+
}
|
|
35
|
+
const modules = { texts: window.__mooodModules || {} }; // the modules the scene lists, given (kit.js)
|
|
36
|
+
const canvas = document.getElementById('scene'), stage = Moood.mount(canvas);
|
|
37
|
+
stage.show(spec, modules);
|
|
38
|
+
MooodState.start(spec, {}, { stage, modules }); // the starting state, scripts running (their errors are reported)
|
|
39
|
+
if (!bare) MooodWidgets.create({ canvas, stage }).show({ ...spec, widgets: (spec.widgets || []).map(w => ({ ...w, at: 0, for: 0 })) });
|
|
40
|
+
// show every caption at once, so the reviewer reads them all
|
|
41
|
+
if (!bare) MooodCaptions.show((spec.captions || []).map(c => ({ ...c, at: 0, for: 0 })));
|
|
42
|
+
} catch (e) { errors.push(String(e.message || e)); }
|
|
43
|
+
await new Promise(r => setTimeout(r, 1500));
|
|
44
|
+
errors.push(...(window.__mooodErrors || []));
|
|
45
|
+
window.__mooodRenderErrors = errors;
|
|
46
|
+
document.title = 'ready';
|
|
47
|
+
})();
|
|
48
|
+
</script>
|
|
49
|
+
</body>
|
|
50
|
+
</html>
|
package/engine/scene.css
CHANGED
|
@@ -1,124 +1,124 @@
|
|
|
1
|
-
/* Any page with a scene (web/scene, shared by every game): the living scene full-screen, its title,
|
|
2
|
-
timed captions, widgets, the lines said over whoever says them, the selection's glow, what can be
|
|
3
|
-
done with a thing picked, a strip of
|
|
4
|
-
the theme's scenes. Each page adds its own (its panels, the microphone). */
|
|
5
|
-
html, body { margin: 0; height: 100%; overflow: hidden; background: #07080c; color: #e6e8ee; font-family: Georgia, "Times New Roman", serif;
|
|
6
|
-
-webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
|
|
7
|
-
#scene { position: fixed; inset: 0; width: 100%; height: 100%; display: block; transition: opacity 1.4s ease; }
|
|
8
|
-
#scene.away { opacity: 0; }
|
|
9
|
-
a { color: inherit; }
|
|
10
|
-
|
|
11
|
-
.titles { position: fixed; top: 5vh; left: 0; right: 0; padding: 0 16px; text-align: center; pointer-events: none; text-shadow: 0 2px 20px rgba(0, 0, 0, 0.8);
|
|
12
|
-
transition: opacity 3s ease; }
|
|
13
|
-
.titles.gone { opacity: 0; }
|
|
14
|
-
/* in the Android app the app's own bar is over the top (--app-top) */
|
|
15
|
-
body.app .titles { top: calc(var(--app-top, 0px) + 2vh); }
|
|
16
|
-
.titles h1 { margin: 0; font-weight: normal; font-style: italic; font-size: clamp(1.6rem, 4vw, 2.8rem); letter-spacing: 0.04em; }
|
|
17
|
-
.titles p { margin: 0.6em 0 0; font-style: italic; opacity: 0.75; font-size: clamp(0.95rem, 1.6vw, 1.15rem); }
|
|
18
|
-
|
|
19
|
-
/* the selection's glow (select.js) */
|
|
20
|
-
#select-overlay { position: fixed; inset: 0; width: 100%; height: 100%; pointer-events: none; }
|
|
21
|
-
|
|
22
|
-
/* what can be done with the thing picked (actions.js): beside it */
|
|
23
|
-
#actions { position: fixed; left: 0; top: 0; z-index: 4; display: flex; flex-direction: column; gap: 3px; min-width: 150px; max-width: 280px;
|
|
24
|
-
padding: 8px; border-radius: 12px; background: rgba(10, 12, 18, 0.86); font: 15px/1.35 Georgia, 'Times New Roman', serif; color: #eee7da;
|
|
25
|
-
box-shadow: 0 6px 28px rgba(0, 0, 0, 0.45); }
|
|
26
|
-
#actions[hidden] { display: none; }
|
|
27
|
-
#actions b { padding: 2px 8px 4px; font-weight: normal; font-style: italic; font-size: 13px; opacity: 0.6; }
|
|
28
|
-
#actions button { border: 0; border-radius: 8px; padding: 6px 10px; background: none; color: inherit; font: inherit; text-align: left; cursor: pointer; }
|
|
29
|
-
#actions button:hover, #actions button:focus-visible { background: rgba(255, 228, 170, 0.14); outline: none; }
|
|
30
|
-
|
|
31
|
-
/* timed captions (spec.captions) */
|
|
32
|
-
#captions { position: fixed; left: 0; right: 0; bottom: 14vh; z-index: 2; pointer-events: none; text-align: center; }
|
|
33
|
-
#captions p { margin: 0.4em auto; max-width: 42em; padding: 0 16px; font: italic 400 clamp(17px, 2.1vw, 26px)/1.4 Georgia, 'Times New Roman', serif;
|
|
34
|
-
color: rgba(240, 236, 228, 0.92); text-shadow: 0 1px 14px rgba(0, 0, 0, 0.55); opacity: 0; transition: opacity 2.4s ease; }
|
|
35
|
-
#captions p:not(.on) { position: absolute; left: 0; right: 0; }
|
|
36
|
-
#captions p.on { opacity: 1; }
|
|
37
|
-
|
|
38
|
-
/* widgets (spec.widgets) */
|
|
39
|
-
#widgets { position: fixed; inset: 0; z-index: 1; pointer-events: none; overflow: hidden; }
|
|
40
|
-
#widgets .widget { position: absolute; left: 0; top: 0; transform-origin: 0 0; opacity: 0; transition: opacity 1.2s ease; }
|
|
41
|
-
#widgets .widget.on { opacity: 1; }
|
|
42
|
-
|
|
43
|
-
/* lines said (speech.js): over the one who says it, glimmering while heard; the narrator's low in
|
|
44
|
-
the middle */
|
|
45
|
-
#speech { position: fixed; inset: 0; z-index: 2; pointer-events: none; overflow: hidden; }
|
|
46
|
-
#speech .bubble { position: absolute; left: 0; top: 0; max-width: min(340px, 40vw); display: flex; gap: 6px; align-items: flex-start;
|
|
47
|
-
padding: 8px 12px; border-radius: 14px; background: rgba(12, 14, 22, 0.78); border: 1px solid rgba(255, 255, 255, 0.14);
|
|
48
|
-
color: rgba(244, 240, 232, 0.95); font: 15px/1.4 Georgia, 'Times New Roman', serif; transition: opacity 1.2s ease, box-shadow 0.3s; }
|
|
49
|
-
#speech .bubble.narrator { max-width: min(640px, 80vw); background: rgba(12, 14, 22, 0.55); border-color: transparent; font-style: italic; font-size: 17px; }
|
|
50
|
-
#speech .bubble p { margin: 0; }
|
|
51
|
-
#speech .bubble button { pointer-events: auto; flex: none; border: 0; background: none; color: inherit; opacity: 0.6; cursor: pointer; font-size: 12px; padding: 2px; }
|
|
52
|
-
#speech .bubble button:hover { opacity: 1; }
|
|
53
|
-
#speech .bubble.speaking { animation: speaking 1.4s ease-in-out infinite; }
|
|
54
|
-
#speech .bubble.fading { opacity: 0; }
|
|
55
|
-
#speech .bubble.pending { padding: 4px 12px; letter-spacing: 0.2em; animation: working 1.2s ease-in-out infinite; }
|
|
56
|
-
@keyframes speaking { 50% { box-shadow: 0 0 18px rgba(255, 220, 160, 0.45); border-color: rgba(255, 220, 160, 0.6); } }
|
|
57
|
-
@keyframes working { 50% { opacity: 0.55; } }
|
|
58
|
-
|
|
59
|
-
/* the microphone over what the player pressed on: hold to speak */
|
|
60
|
-
#mic { position: fixed; left: 0; top: 0; z-index: 3; width: 64px; height: 64px; margin: -32px 0 0 -32px; border-radius: 50%;
|
|
61
|
-
border: 1px solid rgba(255, 228, 160, 0.6); background: rgba(12, 14, 22, 0.72); color: rgba(255, 236, 200, 0.95);
|
|
62
|
-
display: grid; place-items: center; cursor: pointer; touch-action: none; transition: transform 0.2s, background 0.2s, opacity 0.3s; }
|
|
63
|
-
#mic svg { width: 26px; height: 26px; }
|
|
64
|
-
#mic[hidden] { display: none; }
|
|
65
|
-
#mic.on { transform: scale(1.18); background: rgba(150, 40, 30, 0.75); border-color: rgba(255, 170, 140, 0.9); animation: listening 1.1s ease-in-out infinite; }
|
|
66
|
-
#mic.busy { opacity: 0.5; }
|
|
67
|
-
@keyframes listening { 50% { box-shadow: 0 0 0 12px rgba(255, 140, 110, 0.15); } }
|
|
68
|
-
|
|
69
|
-
/* what the player said, as it is heard */
|
|
70
|
-
#heard { position: fixed; left: 50%; bottom: 6vh; z-index: 3; transform: translateX(-50%); max-width: min(640px, 86vw); padding: 8px 16px;
|
|
71
|
-
border-radius: 14px; background: rgba(255, 255, 255, 0.1); color: rgba(255, 255, 255, 0.92); font: 16px/1.4 Georgia, serif;
|
|
72
|
-
pointer-events: none; opacity: 0; transition: opacity 0.4s; }
|
|
73
|
-
#heard.on { opacity: 1; }
|
|
74
|
-
#heard.partial { color: rgba(255, 255, 255, 0.6); font-style: italic; }
|
|
75
|
-
|
|
76
|
-
/* the theme's scenes and what is being drawn (strip.js), low on the right */
|
|
77
|
-
#strip { position: fixed; right: 12px; bottom: 12px; z-index: 3; display: flex; gap: 6px; max-width: 46vw; overflow-x: auto; padding: 4px; }
|
|
78
|
-
#strip[hidden] { display: none; }
|
|
79
|
-
#strip a { flex: none; display: block; width: 80px; aspect-ratio: 16 / 9; border-radius: 6px; overflow: hidden; border: 1px solid rgba(255, 255, 255, 0.18);
|
|
80
|
-
background: rgba(12, 14, 22, 0.6); opacity: 0.75; transition: opacity 0.2s, border-color 0.2s; }
|
|
81
|
-
#strip a:hover { opacity: 1; }
|
|
82
|
-
#strip a.here { opacity: 1; border-color: rgba(255, 228, 170, 0.85); }
|
|
83
|
-
#strip img { display: block; width: 100%; height: 100%; object-fit: cover; }
|
|
84
|
-
#strip img[hidden] { display: none; }
|
|
85
|
-
/* a scene being drawn: its sketch as it is now, marked; waiting ones dashed */
|
|
86
|
-
#strip a.sketch { position: relative; opacity: 1; border-color: rgba(255, 196, 120, 0.85); animation: drawing 1.6s ease-in-out infinite; }
|
|
87
|
-
#strip a.sketch.waiting { border-style: dashed; animation: none; opacity: 0.75; }
|
|
88
|
-
#strip .badge { position: absolute; left: 0; right: 0; bottom: 0; padding: 1px 4px; font: italic 10px/1.3 Georgia, serif; color: #ffe3c0;
|
|
89
|
-
background: linear-gradient(transparent, rgba(0, 0, 0, 0.75)); }
|
|
90
|
-
@keyframes drawing { 50% { box-shadow: 0 0 0 2px rgba(255, 176, 100, 0.35); } }
|
|
91
|
-
|
|
92
|
-
/* around a scene on a page (the crumbs top-left: nav.css): the game stumbling, what a scene was
|
|
93
|
-
asked for, a drawing's work */
|
|
94
|
-
|
|
95
|
-
/* the master stumbled (an error in its turn) */
|
|
96
|
-
#trouble { position: fixed; left: 14px; bottom: 12px; z-index: 3; max-width: 60vw; font: italic 13px/1.4 Georgia, serif; color: rgba(255, 170, 150, 0.85);
|
|
97
|
-
pointer-events: none; opacity: 0; transition: opacity 0.6s; }
|
|
98
|
-
#trouble.on { opacity: 1; }
|
|
99
|
-
|
|
100
|
-
#about { position: fixed; left: 14px; top: 12px; z-index: 4; max-width: min(520px, 80vw); max-height: 70vh; overflow: auto; padding: 8px 12px;
|
|
101
|
-
border-radius: 12px; background: rgba(12, 14, 22, 0.78); font: 13px/1.45 Georgia, serif; color: rgba(240, 236, 228, 0.9); }
|
|
102
|
-
#about summary { cursor: pointer; font-style: italic; opacity: 0.8; }
|
|
103
|
-
#about .note { white-space: pre-wrap; opacity: 0.75; font-size: 12px; }
|
|
104
|
-
#crumbs ~ #about, #crumbs ~ #work { top: 48px; }
|
|
105
|
-
|
|
106
|
-
/* a scene being drawn (drawing.html): what was asked, its state, what the artist says as it works */
|
|
107
|
-
#work { position: fixed; left: 14px; top: 12px; z-index: 4; width: min(420px, 80vw); max-height: 60vh; display: flex; flex-direction: column; gap: 6px;
|
|
108
|
-
padding: 10px 14px; border-radius: 12px; background: rgba(12, 14, 22, 0.8); font: 13px/1.45 Georgia, serif; color: rgba(240, 236, 228, 0.92); }
|
|
109
|
-
#work .state { margin: 0; font-style: italic; color: #ffcf9a; }
|
|
110
|
-
#work.drawing .state::before { content: '● '; animation: working 1.2s ease-in-out infinite; }
|
|
111
|
-
#work .asked { margin: 0; opacity: 0.8; max-height: 9em; overflow: auto; }
|
|
112
|
-
#work ol { margin: 0; padding: 0; list-style: none; overflow: auto; display: flex; flex-direction: column; gap: 3px; font-size: 12px; }
|
|
113
|
-
#work li { opacity: 0.85; }
|
|
114
|
-
#work li.tool { opacity: 0.45; font-family: ui-monospace, Consolas, monospace; font-size: 11px; }
|
|
115
|
-
|
|
116
|
-
/* the ways the scene can change (directions.js): a panel to try them */
|
|
117
|
-
#directions { position: fixed; left: 16px; bottom: 16px; z-index: 3; display: flex; flex-direction: column; gap: 6px; padding: 10px 12px;
|
|
118
|
-
border-radius: 12px; background: rgba(8, 10, 16, 0.78); font-size: 13px; -webkit-user-select: none; user-select: none; }
|
|
119
|
-
#directions[hidden] { display: none; }
|
|
120
|
-
#directions .direction { white-space: nowrap; display: grid; grid-template-columns: 15em auto 10em auto; align-items: center; gap: 6px; }
|
|
121
|
-
#directions .direction.blocked { opacity: 0.4; }
|
|
122
|
-
#directions button { border: 0; background: none; color: inherit; cursor: pointer; font-size: 12px; opacity: 0.75; }
|
|
123
|
-
#directions button:hover:not(:disabled) { opacity: 1; }
|
|
124
|
-
#directions input { width: 100%; accent-color: #e8b86a; }
|
|
1
|
+
/* Any page with a scene (web/scene, shared by every game): the living scene full-screen, its title,
|
|
2
|
+
timed captions, widgets, the lines said over whoever says them, the selection's glow, what can be
|
|
3
|
+
done with a thing picked, a strip of
|
|
4
|
+
the theme's scenes. Each page adds its own (its panels, the microphone). */
|
|
5
|
+
html, body { margin: 0; height: 100%; overflow: hidden; background: #07080c; color: #e6e8ee; font-family: Georgia, "Times New Roman", serif;
|
|
6
|
+
-webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
|
|
7
|
+
#scene { position: fixed; inset: 0; width: 100%; height: 100%; display: block; transition: opacity 1.4s ease; }
|
|
8
|
+
#scene.away { opacity: 0; }
|
|
9
|
+
a { color: inherit; }
|
|
10
|
+
|
|
11
|
+
.titles { position: fixed; top: 5vh; left: 0; right: 0; padding: 0 16px; text-align: center; pointer-events: none; text-shadow: 0 2px 20px rgba(0, 0, 0, 0.8);
|
|
12
|
+
transition: opacity 3s ease; }
|
|
13
|
+
.titles.gone { opacity: 0; }
|
|
14
|
+
/* in the Android app the app's own bar is over the top (--app-top) */
|
|
15
|
+
body.app .titles { top: calc(var(--app-top, 0px) + 2vh); }
|
|
16
|
+
.titles h1 { margin: 0; font-weight: normal; font-style: italic; font-size: clamp(1.6rem, 4vw, 2.8rem); letter-spacing: 0.04em; }
|
|
17
|
+
.titles p { margin: 0.6em 0 0; font-style: italic; opacity: 0.75; font-size: clamp(0.95rem, 1.6vw, 1.15rem); }
|
|
18
|
+
|
|
19
|
+
/* the selection's glow (select.js) */
|
|
20
|
+
#select-overlay { position: fixed; inset: 0; width: 100%; height: 100%; pointer-events: none; }
|
|
21
|
+
|
|
22
|
+
/* what can be done with the thing picked (actions.js): beside it */
|
|
23
|
+
#actions { position: fixed; left: 0; top: 0; z-index: 4; display: flex; flex-direction: column; gap: 3px; min-width: 150px; max-width: 280px;
|
|
24
|
+
padding: 8px; border-radius: 12px; background: rgba(10, 12, 18, 0.86); font: 15px/1.35 Georgia, 'Times New Roman', serif; color: #eee7da;
|
|
25
|
+
box-shadow: 0 6px 28px rgba(0, 0, 0, 0.45); }
|
|
26
|
+
#actions[hidden] { display: none; }
|
|
27
|
+
#actions b { padding: 2px 8px 4px; font-weight: normal; font-style: italic; font-size: 13px; opacity: 0.6; }
|
|
28
|
+
#actions button { border: 0; border-radius: 8px; padding: 6px 10px; background: none; color: inherit; font: inherit; text-align: left; cursor: pointer; }
|
|
29
|
+
#actions button:hover, #actions button:focus-visible { background: rgba(255, 228, 170, 0.14); outline: none; }
|
|
30
|
+
|
|
31
|
+
/* timed captions (spec.captions) */
|
|
32
|
+
#captions { position: fixed; left: 0; right: 0; bottom: 14vh; z-index: 2; pointer-events: none; text-align: center; }
|
|
33
|
+
#captions p { margin: 0.4em auto; max-width: 42em; padding: 0 16px; font: italic 400 clamp(17px, 2.1vw, 26px)/1.4 Georgia, 'Times New Roman', serif;
|
|
34
|
+
color: rgba(240, 236, 228, 0.92); text-shadow: 0 1px 14px rgba(0, 0, 0, 0.55); opacity: 0; transition: opacity 2.4s ease; }
|
|
35
|
+
#captions p:not(.on) { position: absolute; left: 0; right: 0; }
|
|
36
|
+
#captions p.on { opacity: 1; }
|
|
37
|
+
|
|
38
|
+
/* widgets (spec.widgets) */
|
|
39
|
+
#widgets { position: fixed; inset: 0; z-index: 1; pointer-events: none; overflow: hidden; }
|
|
40
|
+
#widgets .widget { position: absolute; left: 0; top: 0; transform-origin: 0 0; opacity: 0; transition: opacity 1.2s ease; }
|
|
41
|
+
#widgets .widget.on { opacity: 1; }
|
|
42
|
+
|
|
43
|
+
/* lines said (speech.js): over the one who says it, glimmering while heard; the narrator's low in
|
|
44
|
+
the middle */
|
|
45
|
+
#speech { position: fixed; inset: 0; z-index: 2; pointer-events: none; overflow: hidden; }
|
|
46
|
+
#speech .bubble { position: absolute; left: 0; top: 0; max-width: min(340px, 40vw); display: flex; gap: 6px; align-items: flex-start;
|
|
47
|
+
padding: 8px 12px; border-radius: 14px; background: rgba(12, 14, 22, 0.78); border: 1px solid rgba(255, 255, 255, 0.14);
|
|
48
|
+
color: rgba(244, 240, 232, 0.95); font: 15px/1.4 Georgia, 'Times New Roman', serif; transition: opacity 1.2s ease, box-shadow 0.3s; }
|
|
49
|
+
#speech .bubble.narrator { max-width: min(640px, 80vw); background: rgba(12, 14, 22, 0.55); border-color: transparent; font-style: italic; font-size: 17px; }
|
|
50
|
+
#speech .bubble p { margin: 0; }
|
|
51
|
+
#speech .bubble button { pointer-events: auto; flex: none; border: 0; background: none; color: inherit; opacity: 0.6; cursor: pointer; font-size: 12px; padding: 2px; }
|
|
52
|
+
#speech .bubble button:hover { opacity: 1; }
|
|
53
|
+
#speech .bubble.speaking { animation: speaking 1.4s ease-in-out infinite; }
|
|
54
|
+
#speech .bubble.fading { opacity: 0; }
|
|
55
|
+
#speech .bubble.pending { padding: 4px 12px; letter-spacing: 0.2em; animation: working 1.2s ease-in-out infinite; }
|
|
56
|
+
@keyframes speaking { 50% { box-shadow: 0 0 18px rgba(255, 220, 160, 0.45); border-color: rgba(255, 220, 160, 0.6); } }
|
|
57
|
+
@keyframes working { 50% { opacity: 0.55; } }
|
|
58
|
+
|
|
59
|
+
/* the microphone over what the player pressed on: hold to speak */
|
|
60
|
+
#mic { position: fixed; left: 0; top: 0; z-index: 3; width: 64px; height: 64px; margin: -32px 0 0 -32px; border-radius: 50%;
|
|
61
|
+
border: 1px solid rgba(255, 228, 160, 0.6); background: rgba(12, 14, 22, 0.72); color: rgba(255, 236, 200, 0.95);
|
|
62
|
+
display: grid; place-items: center; cursor: pointer; touch-action: none; transition: transform 0.2s, background 0.2s, opacity 0.3s; }
|
|
63
|
+
#mic svg { width: 26px; height: 26px; }
|
|
64
|
+
#mic[hidden] { display: none; }
|
|
65
|
+
#mic.on { transform: scale(1.18); background: rgba(150, 40, 30, 0.75); border-color: rgba(255, 170, 140, 0.9); animation: listening 1.1s ease-in-out infinite; }
|
|
66
|
+
#mic.busy { opacity: 0.5; }
|
|
67
|
+
@keyframes listening { 50% { box-shadow: 0 0 0 12px rgba(255, 140, 110, 0.15); } }
|
|
68
|
+
|
|
69
|
+
/* what the player said, as it is heard */
|
|
70
|
+
#heard { position: fixed; left: 50%; bottom: 6vh; z-index: 3; transform: translateX(-50%); max-width: min(640px, 86vw); padding: 8px 16px;
|
|
71
|
+
border-radius: 14px; background: rgba(255, 255, 255, 0.1); color: rgba(255, 255, 255, 0.92); font: 16px/1.4 Georgia, serif;
|
|
72
|
+
pointer-events: none; opacity: 0; transition: opacity 0.4s; }
|
|
73
|
+
#heard.on { opacity: 1; }
|
|
74
|
+
#heard.partial { color: rgba(255, 255, 255, 0.6); font-style: italic; }
|
|
75
|
+
|
|
76
|
+
/* the theme's scenes and what is being drawn (strip.js), low on the right */
|
|
77
|
+
#strip { position: fixed; right: 12px; bottom: 12px; z-index: 3; display: flex; gap: 6px; max-width: 46vw; overflow-x: auto; padding: 4px; }
|
|
78
|
+
#strip[hidden] { display: none; }
|
|
79
|
+
#strip a { flex: none; display: block; width: 80px; aspect-ratio: 16 / 9; border-radius: 6px; overflow: hidden; border: 1px solid rgba(255, 255, 255, 0.18);
|
|
80
|
+
background: rgba(12, 14, 22, 0.6); opacity: 0.75; transition: opacity 0.2s, border-color 0.2s; }
|
|
81
|
+
#strip a:hover { opacity: 1; }
|
|
82
|
+
#strip a.here { opacity: 1; border-color: rgba(255, 228, 170, 0.85); }
|
|
83
|
+
#strip img { display: block; width: 100%; height: 100%; object-fit: cover; }
|
|
84
|
+
#strip img[hidden] { display: none; }
|
|
85
|
+
/* a scene being drawn: its sketch as it is now, marked; waiting ones dashed */
|
|
86
|
+
#strip a.sketch { position: relative; opacity: 1; border-color: rgba(255, 196, 120, 0.85); animation: drawing 1.6s ease-in-out infinite; }
|
|
87
|
+
#strip a.sketch.waiting { border-style: dashed; animation: none; opacity: 0.75; }
|
|
88
|
+
#strip .badge { position: absolute; left: 0; right: 0; bottom: 0; padding: 1px 4px; font: italic 10px/1.3 Georgia, serif; color: #ffe3c0;
|
|
89
|
+
background: linear-gradient(transparent, rgba(0, 0, 0, 0.75)); }
|
|
90
|
+
@keyframes drawing { 50% { box-shadow: 0 0 0 2px rgba(255, 176, 100, 0.35); } }
|
|
91
|
+
|
|
92
|
+
/* around a scene on a page (the crumbs top-left: nav.css): the game stumbling, what a scene was
|
|
93
|
+
asked for, a drawing's work */
|
|
94
|
+
|
|
95
|
+
/* the master stumbled (an error in its turn) */
|
|
96
|
+
#trouble { position: fixed; left: 14px; bottom: 12px; z-index: 3; max-width: 60vw; font: italic 13px/1.4 Georgia, serif; color: rgba(255, 170, 150, 0.85);
|
|
97
|
+
pointer-events: none; opacity: 0; transition: opacity 0.6s; }
|
|
98
|
+
#trouble.on { opacity: 1; }
|
|
99
|
+
|
|
100
|
+
#about { position: fixed; left: 14px; top: 12px; z-index: 4; max-width: min(520px, 80vw); max-height: 70vh; overflow: auto; padding: 8px 12px;
|
|
101
|
+
border-radius: 12px; background: rgba(12, 14, 22, 0.78); font: 13px/1.45 Georgia, serif; color: rgba(240, 236, 228, 0.9); }
|
|
102
|
+
#about summary { cursor: pointer; font-style: italic; opacity: 0.8; }
|
|
103
|
+
#about .note { white-space: pre-wrap; opacity: 0.75; font-size: 12px; }
|
|
104
|
+
#crumbs ~ #about, #crumbs ~ #work { top: 48px; }
|
|
105
|
+
|
|
106
|
+
/* a scene being drawn (drawing.html): what was asked, its state, what the artist says as it works */
|
|
107
|
+
#work { position: fixed; left: 14px; top: 12px; z-index: 4; width: min(420px, 80vw); max-height: 60vh; display: flex; flex-direction: column; gap: 6px;
|
|
108
|
+
padding: 10px 14px; border-radius: 12px; background: rgba(12, 14, 22, 0.8); font: 13px/1.45 Georgia, serif; color: rgba(240, 236, 228, 0.92); }
|
|
109
|
+
#work .state { margin: 0; font-style: italic; color: #ffcf9a; }
|
|
110
|
+
#work.drawing .state::before { content: '● '; animation: working 1.2s ease-in-out infinite; }
|
|
111
|
+
#work .asked { margin: 0; opacity: 0.8; max-height: 9em; overflow: auto; }
|
|
112
|
+
#work ol { margin: 0; padding: 0; list-style: none; overflow: auto; display: flex; flex-direction: column; gap: 3px; font-size: 12px; }
|
|
113
|
+
#work li { opacity: 0.85; }
|
|
114
|
+
#work li.tool { opacity: 0.45; font-family: ui-monospace, Consolas, monospace; font-size: 11px; }
|
|
115
|
+
|
|
116
|
+
/* the ways the scene can change (directions.js): a panel to try them */
|
|
117
|
+
#directions { position: fixed; left: 16px; bottom: 16px; z-index: 3; display: flex; flex-direction: column; gap: 6px; padding: 10px 12px;
|
|
118
|
+
border-radius: 12px; background: rgba(8, 10, 16, 0.78); font-size: 13px; -webkit-user-select: none; user-select: none; }
|
|
119
|
+
#directions[hidden] { display: none; }
|
|
120
|
+
#directions .direction { white-space: nowrap; display: grid; grid-template-columns: 15em auto 10em auto; align-items: center; gap: 6px; }
|
|
121
|
+
#directions .direction.blocked { opacity: 0.4; }
|
|
122
|
+
#directions button { border: 0; background: none; color: inherit; cursor: pointer; font-size: 12px; opacity: 0.75; }
|
|
123
|
+
#directions button:hover:not(:disabled) { opacity: 1; }
|
|
124
|
+
#directions input { width: 100%; accent-color: #e8b86a; }
|