221 lines
12 KiB
CSS
221 lines
12 KiB
CSS
/* wadamesh in the browser: the page around the device canvas.
|
|
Tokens are the site's Night palette (deploy/site/theme.css), dark only. */
|
|
:root{
|
|
color-scheme:dark;
|
|
--bg:#000400;
|
|
--card:rgba(11,14,16,.74);
|
|
--solid:#0B0E10;
|
|
--ink:#E6EBED; --ink2:#D2D9DD; --mut:#B0BAC0; --dim:#8C979D;
|
|
--line:#1C2428;
|
|
--control:#161D21; --control-hi:#222C31;
|
|
--teal:#15B6A6; --cyan:#19D6C2;
|
|
--accent-fill:#15B6A6; --on-accent:#00120F;
|
|
--accent-soft:rgba(25,214,194,.13);
|
|
--bar:rgba(0,0,0,.5);
|
|
--frame:#16191D; --frame-edge:#2A3036;
|
|
--warn:#F2A33A; --warn-bg:rgba(242,163,58,.13); --warn-line:rgba(242,163,58,.38);
|
|
--bad:#F06A6E;
|
|
--shadow:0 22px 50px -26px rgba(0,0,0,.85);
|
|
--bar-h:56px;
|
|
--gutter:16px;
|
|
}
|
|
*{box-sizing:border-box}
|
|
html,body{margin:0; height:100%}
|
|
html{background:var(--bg); overscroll-behavior:none; -webkit-text-size-adjust:100%}
|
|
body{overscroll-behavior:none}
|
|
body{
|
|
min-height:100%; display:flex; flex-direction:column;
|
|
color:var(--ink); background:
|
|
radial-gradient(1200px 600px at 20% -10%, rgba(25,214,194,.10), transparent 60%),
|
|
radial-gradient(900px 500px at 90% 110%, rgba(90,169,255,.07), transparent 60%),
|
|
var(--bg);
|
|
font-family:'Montserrat',-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif; font-weight:500;
|
|
-webkit-font-smoothing:antialiased;
|
|
}
|
|
::selection{background:rgba(25,214,194,.32)}
|
|
|
|
/* ---- the bar ---- */
|
|
.bar{
|
|
display:flex; align-items:center; gap:10px;
|
|
min-height:var(--bar-h); padding:8px var(--gutter);
|
|
padding-left:max(var(--gutter), env(safe-area-inset-left));
|
|
padding-right:max(var(--gutter), env(safe-area-inset-right));
|
|
background:var(--bar); border-bottom:1px solid var(--line);
|
|
-webkit-backdrop-filter:blur(10px); backdrop-filter:blur(10px);
|
|
position:relative; z-index:30; /* its menu opens over the stage */
|
|
padding-top:max(8px, env(safe-area-inset-top));
|
|
flex-wrap:nowrap; min-width:0;
|
|
}
|
|
.bar > *{flex-shrink:0}
|
|
.bar .badge{flex-shrink:1; min-width:0}
|
|
.brand{display:inline-flex; align-items:center; gap:8px; color:var(--ink); text-decoration:none;
|
|
font-weight:700; letter-spacing:.02em; font-size:17px}
|
|
.brand img{display:block}
|
|
.badge{display:inline-flex; align-items:center; height:24px; padding:0 10px; border-radius:12px;
|
|
background:var(--warn-bg); color:var(--warn); box-shadow:inset 0 0 0 1px var(--warn-line);
|
|
font-size:12px; font-weight:700; letter-spacing:.06em; text-transform:uppercase}
|
|
.spacer{flex:1}
|
|
.btn{
|
|
height:36px; padding:0 14px; border:0; border-radius:18px; cursor:pointer;
|
|
background:var(--control); color:var(--ink2); box-shadow:inset 0 0 0 1px var(--line);
|
|
font:inherit; font-size:14px; font-weight:600; white-space:nowrap;
|
|
transition:background .15s, box-shadow .15s, color .15s;
|
|
}
|
|
.btn:hover{background:var(--control-hi)}
|
|
.btn:focus-visible{outline:none; box-shadow:inset 0 0 0 1px var(--teal), 0 0 0 3px var(--accent-soft)}
|
|
.btn.primary{background:var(--accent-fill); color:var(--on-accent); box-shadow:none}
|
|
.btn.primary:hover{background:var(--cyan)}
|
|
.btn.icon{width:36px; padding:0; display:inline-grid; place-items:center}
|
|
.btn.icon svg{width:18px; height:18px; fill:none; stroke:currentColor; stroke-width:2; stroke-linecap:round; stroke-linejoin:round}
|
|
.btn[hidden]{display:none}
|
|
|
|
/* ---- the stage: the canvas, scaled by app.js (aspect kept, integer device pixels when it can) ---- */
|
|
#stage{
|
|
flex:1; min-height:0; display:flex; align-items:center; justify-content:center;
|
|
padding:var(--gutter);
|
|
padding-left:max(var(--gutter), env(safe-area-inset-left));
|
|
padding-right:max(var(--gutter), env(safe-area-inset-right));
|
|
}
|
|
#frame{position:relative; line-height:0; border-radius:10px; background:#000;
|
|
box-shadow:0 0 0 1px var(--frame-edge), 0 0 0 7px var(--frame), 0 0 0 8px var(--frame-edge), var(--shadow)}
|
|
#screen{display:block; width:800px; height:480px; border-radius:2px; touch-action:none; outline:none;
|
|
-webkit-user-select:none; user-select:none; -webkit-tap-highlight-color:transparent; cursor:default}
|
|
/* a field the UI focused by itself (a screen opened with it): the phone shows its keyboard
|
|
only for a tap, so this is the tap (app.js "phone keyboard") */
|
|
#kb-pill{position:absolute; left:50%; bottom:72px; transform:translateX(-50%); z-index:5;
|
|
display:inline-flex; align-items:center; gap:8px; line-height:1.2; padding:10px 18px;
|
|
border-radius:999px; box-shadow:0 6px 20px rgba(0,0,0,.45)}
|
|
#kb-pill[hidden]{display:none}
|
|
#kb-pill svg{width:20px; height:20px; fill:none; stroke:currentColor; stroke-width:2; stroke-linecap:round; stroke-linejoin:round}
|
|
#screen.crisp{image-rendering:crisp-edges; image-rendering:pixelated} /* integer device-pixel scale: nearest */
|
|
|
|
#overlay{position:absolute; inset:0; display:flex; flex-direction:column; align-items:center; justify-content:center;
|
|
gap:6px; padding:24px; text-align:center; line-height:1.45; background:var(--solid); border-radius:2px}
|
|
#overlay[hidden]{display:none}
|
|
#overlay img{opacity:.95; margin-bottom:8px}
|
|
#status{margin:0; font-size:16px; font-weight:600; color:var(--ink)}
|
|
#overlay .detail{margin:0; max-width:520px; font-size:13px; color:var(--mut)}
|
|
#overlay .detail code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:12px; color:var(--ink2)}
|
|
#overlay.busy #status::after{content:""; display:inline-block; width:1.2em; text-align:left;
|
|
animation:dots 1.2s steps(4,end) infinite}
|
|
@keyframes dots{0%{content:""}25%{content:"."}50%{content:".."}75%{content:"..."}}
|
|
#overlay.fatal #status{color:var(--bad)}
|
|
#overlay .btn{margin-top:10px; line-height:normal}
|
|
|
|
.hint{margin:0 auto; padding:0 var(--gutter) 18px; max-width:820px; text-align:center;
|
|
color:var(--dim); font-size:13px; line-height:1.5}
|
|
|
|
#toast{position:fixed; left:50%; top:calc(var(--bar-h) + 12px); transform:translateX(-50%);
|
|
max-width:min(460px, calc(100vw - 32px)); padding:12px 16px; border-radius:12px;
|
|
background:var(--solid); color:var(--ink2); box-shadow:inset 0 0 0 1px var(--line), var(--shadow);
|
|
font-size:14px; line-height:1.45; z-index:10}
|
|
|
|
/* fullscreen: only the device, on black */
|
|
#stage:fullscreen{padding:0; background:#000; align-items:center}
|
|
#stage:-webkit-full-screen{padding:0; background:#000; align-items:center}
|
|
#stage:fullscreen #frame, #stage:-webkit-full-screen #frame{box-shadow:none; border-radius:0}
|
|
|
|
/* a narrower window: the bar stays one row (labels shorten, the brand name goes first) */
|
|
@media (max-width:720px){
|
|
.wide{display:none}
|
|
.brand span{display:none}
|
|
.bar{gap:8px}
|
|
}
|
|
@media (max-width:420px){
|
|
.btn{height:34px; padding:0 10px; font-size:13px}
|
|
.btn.icon{width:34px}
|
|
#btn-reset{display:none} /* the More menu has it too */
|
|
}
|
|
|
|
/* ---- a phone or tablet, or a tall window: the canvas IS the screen (app.js "fill") ----
|
|
One slim bar row, then the canvas edge to edge; the safe areas (notch, home indicator,
|
|
rounded corners on a phone on its side) stay clear. */
|
|
body.fill{height:100vh; height:100dvh; min-height:0; overflow:hidden}
|
|
body.fill .bar{min-height:0; gap:8px; padding-top:max(6px, env(safe-area-inset-top)); padding-bottom:6px}
|
|
body.fill #stage{flex:1 1 auto; padding:0; align-items:flex-start; overflow:hidden;
|
|
padding-left:env(safe-area-inset-left); padding-right:env(safe-area-inset-right);
|
|
padding-bottom:env(safe-area-inset-bottom)}
|
|
body.fill #frame{border-radius:0; box-shadow:none; transition:transform .18s ease-out}
|
|
body.fill #screen{border-radius:0}
|
|
body.fill .hint{display:none}
|
|
/* a phone on its side: every pixel of height counts */
|
|
@media (max-height:500px){
|
|
body.fill .bar{padding-top:max(4px, env(safe-area-inset-top)); padding-bottom:4px}
|
|
body.fill .btn{height:30px; font-size:13px}
|
|
body.fill .btn.icon{width:30px}
|
|
body.fill .brand img{width:26px; height:17px}
|
|
}
|
|
body.fill #toast{top:calc(env(safe-area-inset-top) + 58px)}
|
|
body.fill .link-help{position:fixed; z-index:25; left:max(8px, env(safe-area-inset-left)); right:max(8px, env(safe-area-inset-right));
|
|
bottom:calc(env(safe-area-inset-bottom) + 72px); margin:0;
|
|
background:linear-gradient(var(--warn-bg), var(--warn-bg)), var(--solid)}
|
|
.rotate-hint{display:none}
|
|
@media (max-width:560px){
|
|
:root{--bar-h:auto}
|
|
.wide{display:none}
|
|
#stage{align-items:flex-start; flex:0 0 auto}
|
|
.bar{gap:8px}
|
|
.brand span{display:none}
|
|
.btn{height:34px; padding:0 12px; font-size:13px}
|
|
.btn.icon{width:34px}
|
|
#frame{border-radius:6px; box-shadow:0 0 0 1px var(--frame-edge), 0 0 0 4px var(--frame), 0 0 0 5px var(--frame-edge)}
|
|
}
|
|
@media (prefers-reduced-motion:reduce){ #overlay.busy #status::after{animation:none; content:"..."} }
|
|
|
|
/* ---- the node link ---- */
|
|
.badge{max-width:46vw; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
|
|
.badge.wait{background:var(--control); color:var(--mut); box-shadow:inset 0 0 0 1px var(--line)}
|
|
.badge.up{background:var(--accent-soft); color:var(--cyan); box-shadow:inset 0 0 0 1px rgba(25,214,194,.38)}
|
|
.badge.bad{background:var(--warn-bg); color:var(--warn); box-shadow:inset 0 0 0 1px var(--warn-line)}
|
|
.link-help{display:flex; align-items:center; gap:12px; flex-wrap:wrap; margin:10px auto 0; max-width:900px;
|
|
padding:10px 14px; border-radius:12px; background:var(--warn-bg); box-shadow:inset 0 0 0 1px var(--warn-line);
|
|
color:var(--ink2); font-size:14px; line-height:1.45}
|
|
.link-help[hidden]{display:none}
|
|
.link-help p{flex:1 1 320px; margin:0; min-width:0}
|
|
dialog#connect-dlg{
|
|
width:min(460px, calc(100vw - 2*var(--gutter))); padding:22px; border:0; border-radius:18px;
|
|
background:var(--solid); color:var(--ink); box-shadow:inset 0 0 0 1px var(--line), var(--shadow);
|
|
}
|
|
dialog#connect-dlg::backdrop{background:rgba(0,0,0,.6)}
|
|
#connect-dlg h2{margin:0 0 6px; font-size:19px}
|
|
#connect-dlg .lead{margin:0 0 16px; color:var(--mut); font-size:14px; line-height:1.45}
|
|
#connect-dlg .choices{display:flex; flex-direction:column; gap:10px}
|
|
#connect-dlg .choice{
|
|
display:flex; flex-direction:column; align-items:flex-start; gap:3px; width:100%;
|
|
padding:12px 14px; border:0; border-radius:12px; text-align:left; cursor:pointer;
|
|
background:var(--control); color:var(--ink); box-shadow:inset 0 0 0 1px var(--line); font:inherit;
|
|
}
|
|
#connect-dlg .choice[hidden]{display:none}
|
|
#connect-dlg .choice.wifi{cursor:default}
|
|
#connect-dlg button.choice:hover{background:var(--control-hi)}
|
|
#connect-dlg .choice strong{font-size:15px}
|
|
#connect-dlg .choice span{color:var(--dim); font-size:13px}
|
|
#connect-dlg .row{display:flex; gap:8px; width:100%; margin-top:8px}
|
|
#connect-dlg input{
|
|
flex:1; min-width:0; height:36px; padding:0 12px; border:0; border-radius:10px;
|
|
background:var(--bg); color:var(--ink); box-shadow:inset 0 0 0 1px var(--line); font:inherit; font-size:14px;
|
|
}
|
|
#connect-dlg input:focus{outline:none; box-shadow:inset 0 0 0 1px var(--teal)}
|
|
#connect-dlg .note{margin:14px 0 0; color:var(--mut); font-size:13px; line-height:1.45}
|
|
#connect-dlg .note .link-line{display:block; margin-top:6px}
|
|
#connect-dlg .note a{color:var(--cyan)}
|
|
#connect-dlg .actions{display:flex; justify-content:flex-end; margin-top:16px}
|
|
|
|
/* the hidden field the phone's own keyboard types into (app.js "phone keyboard") */
|
|
#ime{position:fixed; left:0; top:0; width:1px; height:1px; opacity:0; border:0; padding:0; margin:0;
|
|
font-size:16px; resize:none; background:transparent; color:transparent; caret-color:transparent; z-index:-1}
|
|
|
|
/* the bar's "More" menu: browser backup / restore */
|
|
.more{position:relative}
|
|
.btn.icon svg circle{fill:currentColor; stroke:none}
|
|
.menu{position:absolute; right:0; top:calc(100% + 6px); z-index:20; min-width:260px; padding:6px;
|
|
background:var(--solid); border:1px solid var(--line); border-radius:12px;
|
|
box-shadow:0 10px 30px rgba(0,0,0,.5); display:flex; flex-direction:column; gap:2px}
|
|
.menu[hidden], .menu button[hidden]{display:none}
|
|
.menu button{all:unset; cursor:pointer; padding:9px 12px; border-radius:8px; color:var(--ink);
|
|
font:600 14px/1.25 Montserrat, system-ui, sans-serif}
|
|
.menu button span{display:block; font-weight:500; font-size:12px; opacity:.7; margin-top:2px}
|
|
.menu button:hover, .menu button:focus-visible{background:var(--control-hi)}
|
|
#connect-dlg #wifi-handoff{margin-top:10px; width:100%}
|
|
#connect-dlg #wifi-handoff p{margin:0; color:var(--mut); font-size:13px; line-height:1.45}
|