mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-11-06 00:15:06 +00:00
- The keyboard: the WebView runs edge to edge and is not resized for it, so it covered the dock and the pane's last lines. The app now takes the size of the visual viewport, drops the home indicator's gap while the keyboard is up, and keeps the cursor's line in sight. - Scrolling: the terminal draws with xterm's WebGL renderer, which a scroll does not make lay every row out again. A swipe is applied once a frame, and moves the view by pixels: xterm scrolls whole rows, and the rest of a row is a GPU shift of the drawn screen, put on together with the rows it goes with. Claude-Session: https://claude.ai/code/session_01HVosmYyVSH3BrsLYx3tcSS
1744 lines
30 KiB
CSS
1744 lines
30 KiB
CSS
/* tty7 mobile. The desktop's neutral greys, light and dark following the
|
|
system; ink, not a system blue, for what is pressed; grouped cards on a warm
|
|
canvas; Hack wherever there is code. */
|
|
|
|
@font-face {
|
|
font-family: Hack;
|
|
src: url("./assets/fonts/Hack-Regular.ttf") format("truetype");
|
|
font-weight: 400;
|
|
font-display: block;
|
|
}
|
|
|
|
@font-face {
|
|
font-family: Hack;
|
|
src: url("./assets/fonts/Hack-Bold.ttf") format("truetype");
|
|
font-weight: 700;
|
|
font-display: block;
|
|
}
|
|
|
|
:root {
|
|
--canvas: #f3f3f1;
|
|
--cell: #fcfcfb;
|
|
--cell-press: #ecece9;
|
|
--raised: #fcfcfb;
|
|
--ink: #1c1c1e;
|
|
--ink-soft: rgb(0 0 0 / 0.72);
|
|
--ink-2: rgb(0 0 0 / 0.45);
|
|
--ink-3: rgb(0 0 0 / 0.3);
|
|
--hair: rgb(0 0 0 / 0.08);
|
|
--fill: rgb(0 0 0 / 0.06);
|
|
--fill-faint: rgb(0 0 0 / 0.035);
|
|
--line: rgb(0 0 0 / 0.15);
|
|
/* What is pressed or chosen is drawn in ink, not a system blue. */
|
|
--accent: var(--ink);
|
|
--accent-ink: #fcfcfb;
|
|
--tint: var(--fill);
|
|
--danger: #c43c43;
|
|
--warn-ink: #b7791f;
|
|
--ok-ink: #248a3d;
|
|
--term: var(--cell);
|
|
--bar: rgb(252 252 251 / 0.82);
|
|
/* Floating controls: a hairline ring and a soft drop. */
|
|
--lift: 0 0 0 0.5px rgb(0 0 0 / 0.08), 0 8px 24px -8px rgb(0 0 0 / 0.18);
|
|
--shadow: 0 0 0 0.5px rgb(0 0 0 / 0.08), 0 18px 44px -12px rgb(0 0 0 / 0.28);
|
|
|
|
/* Running and connected. */
|
|
--live: #34c759;
|
|
/* The desktop's status dots (cli_agent.rs `dot_rgb`), fixed across themes. */
|
|
--working: #3b82f6;
|
|
--waiting: #f59e0b;
|
|
--done: #22c55e;
|
|
|
|
--ui: -apple-system, BlinkMacSystemFont, "SF Pro Text", "PingFang SC", Roboto, "Segoe UI", system-ui, sans-serif;
|
|
--mono: Hack, "SF Mono", Menlo, ui-monospace, monospace;
|
|
--ease: cubic-bezier(0.32, 0.72, 0, 1);
|
|
|
|
/* The home indicator's gap; none while the keyboard is up, which covers
|
|
it (main.ts sets `keyboard` on <html>). */
|
|
--safe-bottom: env(safe-area-inset-bottom);
|
|
|
|
color-scheme: light dark;
|
|
font: 17px/1.35 var(--ui);
|
|
letter-spacing: -0.005em;
|
|
color: var(--ink);
|
|
background: var(--canvas);
|
|
-webkit-text-size-adjust: 100%;
|
|
-webkit-font-smoothing: antialiased;
|
|
}
|
|
|
|
@media (prefers-color-scheme: dark) {
|
|
:root {
|
|
--canvas: #0f0f10;
|
|
--cell: #1e1e20;
|
|
--cell-press: #29292c;
|
|
--raised: #242427;
|
|
--ink: #ececed;
|
|
--ink-soft: rgb(255 255 255 / 0.78);
|
|
--ink-2: rgb(255 255 255 / 0.5);
|
|
--ink-3: rgb(255 255 255 / 0.3);
|
|
--hair: rgb(255 255 255 / 0.1);
|
|
--fill: rgb(255 255 255 / 0.08);
|
|
--fill-faint: rgb(255 255 255 / 0.045);
|
|
--line: rgb(255 255 255 / 0.16);
|
|
--accent-ink: #18181a;
|
|
--danger: #f07878;
|
|
--warn-ink: #e0a345;
|
|
--ok-ink: #5fd07a;
|
|
--bar: rgb(30 30 32 / 0.82);
|
|
--lift: 0 0 0 0.5px rgb(255 255 255 / 0.08), 0 8px 24px -8px rgb(0 0 0 / 0.6);
|
|
--shadow: 0 0 0 0.5px rgb(255 255 255 / 0.08), 0 18px 44px -12px rgb(0 0 0 / 0.7);
|
|
}
|
|
}
|
|
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
html,
|
|
body {
|
|
margin: 0;
|
|
height: 100%;
|
|
overflow: hidden;
|
|
overscroll-behavior: none;
|
|
}
|
|
|
|
body {
|
|
-webkit-user-select: none;
|
|
user-select: none;
|
|
-webkit-touch-callout: none;
|
|
}
|
|
|
|
#app {
|
|
height: 100dvh;
|
|
}
|
|
|
|
html.keyboard {
|
|
--safe-bottom: 0px;
|
|
}
|
|
|
|
button {
|
|
font: inherit;
|
|
color: inherit;
|
|
background: none;
|
|
border: 0;
|
|
padding: 0;
|
|
margin: 0;
|
|
cursor: pointer;
|
|
-webkit-tap-highlight-color: transparent;
|
|
touch-action: manipulation;
|
|
}
|
|
|
|
button:focus-visible,
|
|
.field:focus-within {
|
|
outline: 2px solid var(--accent);
|
|
outline-offset: 2px;
|
|
}
|
|
|
|
[hidden] {
|
|
display: none !important;
|
|
}
|
|
|
|
p,
|
|
h1,
|
|
h2,
|
|
h3 {
|
|
margin: 0;
|
|
}
|
|
|
|
/* A control on the desktop, named where the text says to use it. */
|
|
strong {
|
|
font-weight: 600;
|
|
color: var(--ink);
|
|
}
|
|
|
|
code {
|
|
font: 0.82em var(--mono);
|
|
padding: 0.12em 0.4em;
|
|
border-radius: 6px;
|
|
background: var(--hair);
|
|
white-space: nowrap;
|
|
-webkit-user-select: text;
|
|
user-select: text;
|
|
}
|
|
|
|
.icon {
|
|
display: inline-flex;
|
|
flex: none;
|
|
width: 24px;
|
|
height: 24px;
|
|
}
|
|
|
|
.icon svg {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.mono {
|
|
font-family: var(--mono);
|
|
font-size: 0.84em;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Screens and the bar */
|
|
|
|
.screen {
|
|
position: relative;
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100%;
|
|
background: var(--canvas);
|
|
}
|
|
|
|
.nav {
|
|
flex: none;
|
|
display: grid;
|
|
grid-template-columns: 1fr auto 1fr;
|
|
align-items: center;
|
|
gap: 8px;
|
|
height: calc(44px + env(safe-area-inset-top));
|
|
padding: env(safe-area-inset-top) max(16px, env(safe-area-inset-right)) 0
|
|
max(16px, env(safe-area-inset-left));
|
|
background: var(--canvas);
|
|
box-shadow: 0 1px 0 transparent;
|
|
transition:
|
|
background 0.2s,
|
|
box-shadow 0.2s;
|
|
position: relative;
|
|
z-index: 2;
|
|
}
|
|
|
|
.nav.folded {
|
|
background: var(--bar);
|
|
-webkit-backdrop-filter: blur(20px);
|
|
backdrop-filter: blur(20px);
|
|
box-shadow: 0 0.5px 0 var(--hair);
|
|
}
|
|
|
|
.nav-lead,
|
|
.nav-trail {
|
|
display: flex;
|
|
align-items: center;
|
|
min-width: 0;
|
|
}
|
|
|
|
.nav-trail {
|
|
justify-content: flex-end;
|
|
}
|
|
|
|
.nav-title {
|
|
font-weight: 600;
|
|
font-size: 17px;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
max-width: 50vw;
|
|
opacity: 0;
|
|
transform: translateY(4px);
|
|
transition:
|
|
opacity 0.2s,
|
|
transform 0.25s var(--ease);
|
|
}
|
|
|
|
.nav.folded .nav-title {
|
|
opacity: 1;
|
|
transform: none;
|
|
}
|
|
|
|
/* Back is a floating pill that names where it goes. */
|
|
.nav-back {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
height: 38px;
|
|
padding: 0 14px 0 8px;
|
|
border-radius: 19px;
|
|
background: var(--cell);
|
|
box-shadow: var(--lift);
|
|
color: var(--ink);
|
|
font-size: 15px;
|
|
min-width: 0;
|
|
}
|
|
|
|
.nav-back span:last-child {
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.nav-back .icon {
|
|
width: 20px;
|
|
height: 20px;
|
|
}
|
|
|
|
.nav-back:active,
|
|
.nav-icon:active,
|
|
.round:active {
|
|
opacity: 0.55;
|
|
}
|
|
|
|
.nav-icon {
|
|
display: grid;
|
|
place-items: center;
|
|
width: 38px;
|
|
height: 38px;
|
|
border-radius: 19px;
|
|
background: var(--cell);
|
|
box-shadow: var(--lift);
|
|
color: var(--ink);
|
|
}
|
|
|
|
.nav-icon .icon {
|
|
width: 22px;
|
|
height: 22px;
|
|
}
|
|
|
|
/* A round control on a surface of its own: the terminal's bar, a sheet. */
|
|
.round {
|
|
display: grid;
|
|
place-items: center;
|
|
flex: none;
|
|
width: 38px;
|
|
height: 38px;
|
|
border-radius: 50%;
|
|
background: var(--fill);
|
|
color: var(--ink);
|
|
}
|
|
|
|
.round .icon {
|
|
width: 20px;
|
|
height: 20px;
|
|
}
|
|
|
|
.scroll {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
overscroll-behavior-y: contain;
|
|
-webkit-overflow-scrolling: touch;
|
|
padding: 0 max(0px, env(safe-area-inset-right)) calc(32px + var(--safe-bottom))
|
|
max(0px, env(safe-area-inset-left));
|
|
}
|
|
|
|
.title-block {
|
|
padding: 14px 24px 22px;
|
|
}
|
|
|
|
/* A top-level screen has nothing in its bar until the title folds into it:
|
|
the title starts 34pt under the status bar instead. */
|
|
.screen.root .nav {
|
|
height: calc(34px + env(safe-area-inset-top));
|
|
}
|
|
|
|
.screen.root .title-block {
|
|
padding-top: 0;
|
|
}
|
|
|
|
/* Clear of the floating bar at the bottom. */
|
|
.screen.docked .scroll {
|
|
padding-bottom: calc(104px + var(--safe-bottom));
|
|
}
|
|
|
|
.large-title {
|
|
font-size: 34px;
|
|
line-height: 1.12;
|
|
font-weight: 700;
|
|
letter-spacing: -0.024em;
|
|
overflow-wrap: anywhere;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Grouped lists */
|
|
|
|
.group {
|
|
margin: 0 20px 22px;
|
|
}
|
|
|
|
.group-head {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 12px;
|
|
padding: 0 4px;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.group-head .group-title {
|
|
padding: 0;
|
|
min-width: 0;
|
|
}
|
|
|
|
.group-count {
|
|
font-size: 13px;
|
|
color: var(--ink-2);
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
|
|
.group-title {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
padding: 0 4px 8px;
|
|
font-size: 13px;
|
|
font-weight: 500;
|
|
color: var(--ink-2);
|
|
overflow-wrap: anywhere;
|
|
}
|
|
|
|
.group-note,
|
|
.group-empty {
|
|
padding: 8px 4px 0;
|
|
font-size: 13px;
|
|
line-height: 1.45;
|
|
color: var(--ink-2);
|
|
}
|
|
|
|
.search-empty {
|
|
margin: 8px 24px;
|
|
font-size: 15px;
|
|
color: var(--ink-2);
|
|
overflow-wrap: anywhere;
|
|
}
|
|
|
|
.card {
|
|
background: var(--cell);
|
|
border-radius: 22px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.remote {
|
|
padding-top: 10px;
|
|
}
|
|
|
|
.remote-head {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
margin: 0 20px 16px;
|
|
}
|
|
|
|
.remote-titles {
|
|
min-width: 0;
|
|
}
|
|
|
|
.remote-name {
|
|
font-size: 22px;
|
|
font-weight: 700;
|
|
letter-spacing: -0.014em;
|
|
overflow-wrap: anywhere;
|
|
}
|
|
|
|
.remote-head .link {
|
|
margin-top: 1px;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.remote-note {
|
|
margin: -4px 20px 24px;
|
|
font-size: 14px;
|
|
line-height: 1.45;
|
|
color: var(--ink-2);
|
|
text-wrap: pretty;
|
|
}
|
|
|
|
.row.asleep > .avatar {
|
|
opacity: 0.45;
|
|
}
|
|
|
|
.tag {
|
|
margin-left: 8px;
|
|
vertical-align: 2px;
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
padding: 1px 7px;
|
|
border-radius: 6px;
|
|
background: var(--hair);
|
|
color: var(--ink-2);
|
|
}
|
|
|
|
.row {
|
|
position: relative;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 14px;
|
|
width: 100%;
|
|
min-height: 64px;
|
|
padding: 10px 16px;
|
|
text-align: left;
|
|
transition: background 0.35s;
|
|
}
|
|
|
|
.row.machine {
|
|
min-height: 68px;
|
|
}
|
|
|
|
.row.dim > :not(.row-chevron) {
|
|
opacity: 0.55;
|
|
}
|
|
|
|
.row + .row::before {
|
|
content: "";
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
left: 0;
|
|
height: 0.5px;
|
|
background: var(--hair);
|
|
}
|
|
|
|
.row:active {
|
|
background: var(--cell-press);
|
|
transition: none;
|
|
}
|
|
|
|
.row-text {
|
|
display: flex;
|
|
flex: 1;
|
|
flex-direction: column;
|
|
gap: 2px;
|
|
min-width: 0;
|
|
}
|
|
|
|
.row-title,
|
|
.row-sub {
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.row-title {
|
|
font-size: 17px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.row-sub {
|
|
font-size: 13px;
|
|
color: var(--ink-2);
|
|
}
|
|
|
|
.row-sub.link {
|
|
margin: 0;
|
|
gap: 6px;
|
|
font-size: 13px;
|
|
}
|
|
|
|
.row-chevron {
|
|
width: 16px;
|
|
height: 16px;
|
|
color: var(--ink-3);
|
|
}
|
|
|
|
.status-word {
|
|
font-weight: 600;
|
|
}
|
|
|
|
.status-word.working {
|
|
color: var(--ink-soft);
|
|
}
|
|
|
|
.status-word.waiting {
|
|
color: var(--warn-ink);
|
|
}
|
|
|
|
.status-word.done {
|
|
color: var(--ok-ink);
|
|
}
|
|
|
|
/* On the right of a pane's row: running, or waiting on you (hollow, so it
|
|
differs in shape and not only in hue). */
|
|
.status-dot {
|
|
flex: none;
|
|
width: 7px;
|
|
height: 7px;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.status-dot.working {
|
|
background: var(--live);
|
|
}
|
|
|
|
.status-dot.waiting {
|
|
width: 9px;
|
|
height: 9px;
|
|
box-shadow: inset 0 0 0 2px var(--waiting);
|
|
}
|
|
|
|
/* Machine tiles and pane avatars: quiet greys, the agent's mark in ink. */
|
|
|
|
.tile {
|
|
display: grid;
|
|
place-items: center;
|
|
flex: none;
|
|
width: 36px;
|
|
height: 36px;
|
|
border-radius: 10px;
|
|
background: var(--fill);
|
|
color: var(--ink-soft);
|
|
}
|
|
|
|
.tile .icon {
|
|
width: 20px;
|
|
height: 20px;
|
|
}
|
|
|
|
.tile.large {
|
|
width: 64px;
|
|
height: 64px;
|
|
border-radius: 18px;
|
|
}
|
|
|
|
.tile.large .icon {
|
|
width: 34px;
|
|
height: 34px;
|
|
}
|
|
|
|
.avatar {
|
|
position: relative;
|
|
display: grid;
|
|
place-items: center;
|
|
flex: none;
|
|
width: 32px;
|
|
height: 32px;
|
|
border-radius: 50%;
|
|
background: var(--fill);
|
|
color: var(--ink-soft);
|
|
}
|
|
|
|
.avatar .mark {
|
|
width: 17px;
|
|
height: 17px;
|
|
background: var(--ink-soft);
|
|
-webkit-mask: var(--mark) center / contain no-repeat;
|
|
mask: var(--mark) center / contain no-repeat;
|
|
}
|
|
|
|
.avatar .glyph {
|
|
font: 600 12px var(--mono);
|
|
letter-spacing: -0.06em;
|
|
}
|
|
|
|
.row.asleep > .avatar {
|
|
opacity: 0.45;
|
|
}
|
|
|
|
/* Loading */
|
|
|
|
.skeleton {
|
|
pointer-events: none;
|
|
}
|
|
|
|
.skeleton .avatar {
|
|
background: var(--hair);
|
|
}
|
|
|
|
.bone {
|
|
display: block;
|
|
height: 12px;
|
|
width: 58%;
|
|
border-radius: 6px;
|
|
background: var(--hair);
|
|
animation: breathe 1.6s ease-in-out infinite;
|
|
}
|
|
|
|
.bone.short {
|
|
width: 34%;
|
|
margin-top: 6px;
|
|
}
|
|
|
|
@keyframes breathe {
|
|
50% {
|
|
opacity: 0.45;
|
|
}
|
|
}
|
|
|
|
/* The connection line under a machine's title */
|
|
|
|
.link {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 7px;
|
|
margin-top: 6px;
|
|
font-size: 14px;
|
|
color: var(--ink-2);
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
|
|
.link-dot {
|
|
flex: none;
|
|
width: 6px;
|
|
height: 6px;
|
|
border-radius: 50%;
|
|
background: var(--ink-3);
|
|
}
|
|
|
|
.direct .link-dot,
|
|
.live .link-dot {
|
|
background: var(--live);
|
|
}
|
|
|
|
.relay .link-dot {
|
|
background: var(--waiting);
|
|
}
|
|
|
|
.offline .link-dot {
|
|
background: var(--danger);
|
|
}
|
|
|
|
.connecting .link-dot {
|
|
animation: breathe 1.2s ease-in-out infinite;
|
|
}
|
|
|
|
/* Empty states */
|
|
|
|
.empty {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
text-align: center;
|
|
padding: 56px 36px 24px;
|
|
}
|
|
|
|
.empty-mark {
|
|
width: 76px;
|
|
height: 76px;
|
|
margin-bottom: 22px;
|
|
}
|
|
|
|
.empty .tile.large {
|
|
margin-bottom: 18px;
|
|
}
|
|
|
|
.empty-title {
|
|
font-size: 22px;
|
|
font-weight: 700;
|
|
letter-spacing: -0.014em;
|
|
}
|
|
|
|
.empty-body {
|
|
margin: 8px 0 26px;
|
|
max-width: 30ch;
|
|
font-size: 16px;
|
|
line-height: 1.45;
|
|
color: var(--ink-2);
|
|
text-wrap: pretty;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Buttons */
|
|
|
|
.button {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 6px;
|
|
height: 54px;
|
|
padding: 0 28px;
|
|
border-radius: 27px;
|
|
font-size: 17px;
|
|
font-weight: 600;
|
|
transition:
|
|
transform 0.2s var(--ease),
|
|
opacity 0.2s;
|
|
}
|
|
|
|
.button:active {
|
|
transform: scale(0.97);
|
|
opacity: 0.8;
|
|
}
|
|
|
|
.button:disabled {
|
|
opacity: 0.35;
|
|
transform: none;
|
|
}
|
|
|
|
.button.primary {
|
|
background: var(--accent);
|
|
color: var(--accent-ink);
|
|
}
|
|
|
|
.button.primary:disabled {
|
|
opacity: 1;
|
|
background: var(--fill);
|
|
color: var(--ink-3);
|
|
}
|
|
|
|
.button.tinted {
|
|
background: var(--fill);
|
|
color: var(--ink);
|
|
}
|
|
|
|
.button.small {
|
|
height: 34px;
|
|
padding: 0 14px;
|
|
border-radius: 17px;
|
|
font-size: 15px;
|
|
}
|
|
|
|
.button.wide {
|
|
width: 100%;
|
|
}
|
|
|
|
.button.busy {
|
|
opacity: 0.7;
|
|
}
|
|
|
|
.chip {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 4px;
|
|
height: 28px;
|
|
padding: 0 11px 0 8px;
|
|
border-radius: 15px;
|
|
background: var(--tint);
|
|
color: var(--accent);
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.chip .icon {
|
|
width: 17px;
|
|
height: 17px;
|
|
}
|
|
|
|
.chip:active {
|
|
opacity: 0.6;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Pairing */
|
|
|
|
.chips {
|
|
display: flex;
|
|
gap: 8px;
|
|
}
|
|
|
|
/* Scanning: the camera runs behind the WebView, so everything of ours goes
|
|
transparent except the viewfinder, its hint and Cancel. */
|
|
html.scanning,
|
|
html.scanning body {
|
|
background: transparent;
|
|
}
|
|
|
|
html.scanning #app {
|
|
visibility: hidden;
|
|
}
|
|
|
|
.scanner {
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 100;
|
|
display: grid;
|
|
grid-template-rows: 1fr auto auto;
|
|
justify-items: center;
|
|
align-items: center;
|
|
gap: 24px;
|
|
padding: env(safe-area-inset-top) 24px calc(28px + var(--safe-bottom));
|
|
color: #fff;
|
|
}
|
|
|
|
.scanner-frame {
|
|
width: min(68vw, 280px);
|
|
aspect-ratio: 1;
|
|
border-radius: 24px;
|
|
/* The dimmed surround is the frame's own shadow, so the square stays clear. */
|
|
box-shadow:
|
|
0 0 0 2px rgb(255 255 255 / 0.9),
|
|
0 0 0 100vmax rgb(0 0 0 / 0.55);
|
|
}
|
|
|
|
.scanner-hint {
|
|
position: relative;
|
|
margin: 0;
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
text-align: center;
|
|
text-shadow: 0 1px 3px rgb(0 0 0 / 0.5);
|
|
}
|
|
|
|
.scanner-cancel {
|
|
position: relative;
|
|
min-width: 160px;
|
|
background: rgb(255 255 255 / 0.18);
|
|
color: #fff;
|
|
-webkit-backdrop-filter: blur(12px);
|
|
backdrop-filter: blur(12px);
|
|
}
|
|
|
|
.steps {
|
|
list-style: none;
|
|
counter-reset: step;
|
|
margin: 0 20px 26px;
|
|
padding: 0;
|
|
display: grid;
|
|
gap: 12px;
|
|
}
|
|
|
|
.steps li {
|
|
counter-increment: step;
|
|
display: grid;
|
|
grid-template-columns: 26px 1fr;
|
|
gap: 12px;
|
|
align-items: baseline;
|
|
font-size: 16px;
|
|
line-height: 1.45;
|
|
}
|
|
|
|
.steps li::before {
|
|
content: counter(step);
|
|
display: grid;
|
|
place-items: center;
|
|
width: 26px;
|
|
height: 26px;
|
|
border-radius: 13px;
|
|
background: var(--tint);
|
|
color: var(--accent);
|
|
font-size: 14px;
|
|
font-weight: 700;
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
.field {
|
|
display: flex;
|
|
}
|
|
|
|
.field:focus-within {
|
|
outline-offset: 0;
|
|
}
|
|
|
|
.field-input {
|
|
width: 100%;
|
|
border: 0;
|
|
outline: 0;
|
|
margin: 0;
|
|
padding: 14px 16px;
|
|
background: none;
|
|
color: var(--ink);
|
|
font: 17px/1.3 var(--ui);
|
|
-webkit-user-select: text;
|
|
user-select: text;
|
|
}
|
|
|
|
.field-input::placeholder {
|
|
color: var(--ink-2);
|
|
}
|
|
|
|
.field-input.code {
|
|
resize: none;
|
|
font: 14px/1.5 var(--mono);
|
|
word-break: break-all;
|
|
}
|
|
|
|
.field-error {
|
|
padding: 8px 4px 0;
|
|
font-size: 14px;
|
|
line-height: 1.4;
|
|
color: var(--danger);
|
|
}
|
|
|
|
.field-error:empty {
|
|
display: none;
|
|
}
|
|
|
|
.dock {
|
|
flex: none;
|
|
padding: 12px max(16px, env(safe-area-inset-right)) calc(12px + var(--safe-bottom))
|
|
max(16px, env(safe-area-inset-left));
|
|
background: var(--canvas);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Notices */
|
|
|
|
.notice-slot:empty {
|
|
display: none;
|
|
}
|
|
|
|
.notice {
|
|
display: flex;
|
|
gap: 12px;
|
|
margin: 0 16px 24px;
|
|
padding: 14px 16px;
|
|
border-radius: 16px;
|
|
background: color-mix(in srgb, var(--danger) 10%, var(--cell));
|
|
}
|
|
|
|
.notice.warn {
|
|
background: color-mix(in srgb, var(--waiting) 13%, var(--cell));
|
|
}
|
|
|
|
.notice-icon {
|
|
width: 21px;
|
|
height: 21px;
|
|
margin-top: 1px;
|
|
color: var(--danger);
|
|
}
|
|
|
|
.notice.warn .notice-icon {
|
|
color: var(--warn-ink);
|
|
}
|
|
|
|
.notice-text {
|
|
min-width: 0;
|
|
}
|
|
|
|
.notice-title {
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
line-height: 1.35;
|
|
overflow-wrap: anywhere;
|
|
}
|
|
|
|
.notice-body {
|
|
margin-top: 4px;
|
|
font-size: 14px;
|
|
line-height: 1.45;
|
|
color: var(--ink-2);
|
|
text-wrap: pretty;
|
|
}
|
|
|
|
.notice-actions {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 8px;
|
|
margin-top: 12px;
|
|
}
|
|
|
|
.notice .button.tinted,
|
|
.term-banner .button.tinted {
|
|
background: var(--cell);
|
|
box-shadow: 0 1px 2px rgb(0 0 0 / 0.08);
|
|
}
|
|
|
|
.term-banner .button.tinted {
|
|
background: var(--tint);
|
|
box-shadow: none;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* The ⋯ menu */
|
|
|
|
.menu-wrap {
|
|
position: relative;
|
|
}
|
|
|
|
.menu {
|
|
position: absolute;
|
|
top: 46px;
|
|
right: 2px;
|
|
z-index: 10;
|
|
min-width: 240px;
|
|
padding: 0;
|
|
border-radius: 16px;
|
|
background: var(--raised);
|
|
box-shadow: var(--shadow);
|
|
overflow: hidden;
|
|
transform-origin: top right;
|
|
animation: menu-in 0.28s var(--ease);
|
|
}
|
|
|
|
@keyframes menu-in {
|
|
from {
|
|
opacity: 0;
|
|
transform: scale(0.9);
|
|
}
|
|
}
|
|
|
|
.menu-item {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 16px;
|
|
width: 100%;
|
|
height: 48px;
|
|
padding: 0 16px;
|
|
font-size: 17px;
|
|
text-align: left;
|
|
}
|
|
|
|
.menu-item + .menu-item {
|
|
box-shadow: inset 0 0.5px 0 var(--hair);
|
|
}
|
|
|
|
.menu-item .icon {
|
|
width: 21px;
|
|
height: 21px;
|
|
}
|
|
|
|
.menu-item:active {
|
|
background: var(--cell-press);
|
|
}
|
|
|
|
.menu-item.danger {
|
|
color: var(--danger);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* The terminal */
|
|
|
|
.term-screen {
|
|
background: var(--term);
|
|
}
|
|
|
|
/* Back, the title with its state, and ⋯: nothing else. */
|
|
.term-nav {
|
|
flex: none;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
height: calc(56px + env(safe-area-inset-top));
|
|
padding: env(safe-area-inset-top) max(16px, env(safe-area-inset-right)) 0
|
|
max(16px, env(safe-area-inset-left));
|
|
background: var(--term);
|
|
box-shadow: 0 0.5px 0 var(--hair);
|
|
position: relative;
|
|
z-index: 2;
|
|
}
|
|
|
|
.term-titles {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 1px;
|
|
min-width: 0;
|
|
}
|
|
|
|
.term-title {
|
|
max-width: 100%;
|
|
font-size: 15px;
|
|
font-weight: 600;
|
|
line-height: 1.25;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.term-sub {
|
|
display: flex;
|
|
align-items: center;
|
|
max-width: 100%;
|
|
min-width: 0;
|
|
font-size: 12px;
|
|
line-height: 1.35;
|
|
color: var(--ink-2);
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.term-state {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 5px;
|
|
flex: none;
|
|
}
|
|
|
|
.term-state.offline {
|
|
color: var(--danger);
|
|
}
|
|
|
|
.term-state .link-dot {
|
|
width: 5px;
|
|
height: 5px;
|
|
}
|
|
|
|
.term-cwd {
|
|
min-width: 0;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.term-cwd:not(:empty)::before {
|
|
content: " · ";
|
|
white-space: pre;
|
|
}
|
|
|
|
.term-wrap {
|
|
position: relative;
|
|
flex: 1;
|
|
min-height: 0;
|
|
background: var(--term);
|
|
}
|
|
|
|
.term {
|
|
position: absolute;
|
|
inset: 0;
|
|
overflow: auto;
|
|
padding: 8px 6px;
|
|
}
|
|
|
|
.term.panning {
|
|
overflow-x: auto;
|
|
}
|
|
|
|
/* Panning, xterm's box has to span every column: at the view's width it ends
|
|
partway across the pane, so its scrollback stops taking touches past that
|
|
point and its scrollbar pans off with the text. `pinScrollbar` keeps the
|
|
bar at the visible edge. */
|
|
.term.panning .xterm {
|
|
width: max-content;
|
|
}
|
|
|
|
/* xterm's vertical scrollbar is VS Code's: a 14px square slider. Shape it like
|
|
the thin rounded indicator WebKit draws for the sideways pan, so the two
|
|
axes read as one kind of thing. The colours come from the theme. */
|
|
.term .xterm-scrollable-element > .scrollbar.vertical > .slider {
|
|
left: auto !important;
|
|
right: 2px;
|
|
width: 3px !important;
|
|
border-radius: 1.5px;
|
|
}
|
|
|
|
.term .xterm {
|
|
-webkit-user-select: text;
|
|
user-select: text;
|
|
}
|
|
|
|
/* Shifted by part of a row while a swipe scrolls it (main.ts `setFrac`):
|
|
kept on its own layer so that is a move, not a repaint. */
|
|
.term .xterm-screen {
|
|
will-change: transform;
|
|
}
|
|
|
|
/* The field typing into the terminal goes through: focusable, so the
|
|
keyboard and its input methods work, but never seen. 16px, or iOS zooms
|
|
the page when it takes focus. */
|
|
.term-typing {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 1px;
|
|
height: 1px;
|
|
margin: 0;
|
|
padding: 0;
|
|
border: 0;
|
|
opacity: 0;
|
|
resize: none;
|
|
pointer-events: none;
|
|
caret-color: transparent;
|
|
font-size: 16px;
|
|
}
|
|
|
|
.term-copy {
|
|
position: absolute;
|
|
inset: 0;
|
|
z-index: 2;
|
|
display: flex;
|
|
flex-direction: column;
|
|
background: var(--term);
|
|
}
|
|
|
|
.term-copy-bar {
|
|
flex: none;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 12px;
|
|
padding: 8px 12px 8px 16px;
|
|
box-shadow: 0 0.5px 0 var(--hair);
|
|
font-size: 14px;
|
|
color: var(--ink-2);
|
|
}
|
|
|
|
.term-copy-text {
|
|
flex: 1;
|
|
min-height: 0;
|
|
margin: 0;
|
|
padding: 10px 12px;
|
|
overflow: auto;
|
|
overscroll-behavior: contain;
|
|
font: 12.5px/1.45 var(--mono);
|
|
color: var(--ink);
|
|
/* Wrapped to the phone, not the desktop's width, so nothing needs panning
|
|
to select. */
|
|
white-space: pre-wrap;
|
|
overflow-wrap: anywhere;
|
|
-webkit-user-select: text;
|
|
user-select: text;
|
|
-webkit-touch-callout: default;
|
|
}
|
|
|
|
|
|
.term-banner-slot {
|
|
position: absolute;
|
|
top: 10px;
|
|
right: 12px;
|
|
left: 12px;
|
|
z-index: 3;
|
|
}
|
|
|
|
.term-banner {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
padding: 10px 10px 10px 14px;
|
|
border-radius: 14px;
|
|
background: var(--raised);
|
|
box-shadow: var(--shadow);
|
|
font-size: 15px;
|
|
line-height: 1.35;
|
|
animation: menu-in 0.3s var(--ease);
|
|
transform-origin: top center;
|
|
}
|
|
|
|
.term-banner > span {
|
|
flex: 1;
|
|
min-width: 0;
|
|
overflow-wrap: anywhere;
|
|
}
|
|
|
|
/* The dock under the terminal: a row of keys a page at a time, then the
|
|
message box and the keyboard. */
|
|
.term-dock {
|
|
flex: none;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
padding: 10px max(12px, env(safe-area-inset-right)) calc(10px + var(--safe-bottom))
|
|
max(12px, env(safe-area-inset-left));
|
|
background: var(--canvas);
|
|
box-shadow: 0 -0.5px 0 var(--hair);
|
|
}
|
|
|
|
.key-pages {
|
|
display: flex;
|
|
overflow-x: auto;
|
|
scroll-snap-type: x mandatory;
|
|
scrollbar-width: none;
|
|
overscroll-behavior-x: contain;
|
|
}
|
|
|
|
.key-pages::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
|
|
.key-page {
|
|
display: flex;
|
|
gap: 6px;
|
|
flex: 0 0 100%;
|
|
scroll-snap-align: start;
|
|
/* A page's last key clear of the next page's first. */
|
|
padding-right: 1px;
|
|
}
|
|
|
|
.key {
|
|
display: grid;
|
|
place-items: center;
|
|
flex: 1;
|
|
min-width: 0;
|
|
height: 42px;
|
|
padding: 0 2px;
|
|
border-radius: 10px;
|
|
background: var(--cell);
|
|
box-shadow:
|
|
0 0 0 0.5px var(--hair),
|
|
0 1px 0 var(--hair);
|
|
font: 14px var(--mono);
|
|
color: var(--ink);
|
|
white-space: nowrap;
|
|
transition:
|
|
background 0.25s,
|
|
transform 0.15s var(--ease);
|
|
}
|
|
|
|
.key .icon {
|
|
width: 17px;
|
|
height: 17px;
|
|
}
|
|
|
|
.key:active {
|
|
background: var(--cell-press);
|
|
transform: scale(0.94);
|
|
transition: none;
|
|
}
|
|
|
|
.key.on {
|
|
background: var(--ink);
|
|
color: var(--accent-ink);
|
|
}
|
|
|
|
.key-dots {
|
|
display: flex;
|
|
justify-content: center;
|
|
gap: 5px;
|
|
height: 4px;
|
|
}
|
|
|
|
.key-dots span {
|
|
width: 4px;
|
|
height: 4px;
|
|
border-radius: 50%;
|
|
background: var(--ink-3);
|
|
transition: background 0.2s;
|
|
}
|
|
|
|
.key-dots span.on {
|
|
background: var(--ink);
|
|
}
|
|
|
|
.compose {
|
|
display: flex;
|
|
align-items: flex-end;
|
|
gap: 10px;
|
|
}
|
|
|
|
.compose-input {
|
|
flex: 1;
|
|
min-width: 0;
|
|
min-height: 44px;
|
|
max-height: 132px;
|
|
margin: 0;
|
|
padding: 11px 16px;
|
|
border: 0;
|
|
outline: 0;
|
|
border-radius: 22px;
|
|
resize: none;
|
|
background: var(--cell);
|
|
box-shadow: 0 0 0 0.5px var(--hair);
|
|
color: var(--ink);
|
|
/* 16px or more, or iOS zooms the page when the field takes focus. */
|
|
font: 16px/1.35 var(--ui);
|
|
-webkit-user-select: text;
|
|
user-select: text;
|
|
}
|
|
|
|
.compose-input::placeholder {
|
|
color: var(--ink-2);
|
|
}
|
|
|
|
.compose .round {
|
|
width: 44px;
|
|
height: 44px;
|
|
}
|
|
|
|
.compose .round .icon {
|
|
width: 22px;
|
|
height: 22px;
|
|
}
|
|
|
|
.compose .round.on {
|
|
background: var(--ink);
|
|
color: var(--accent-ink);
|
|
}
|
|
|
|
.round.send {
|
|
background: var(--ink);
|
|
color: var(--accent-ink);
|
|
transition: transform 0.15s var(--ease);
|
|
}
|
|
|
|
.round.send:active {
|
|
transform: scale(0.92);
|
|
opacity: 1;
|
|
transition: none;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* The floating bar: search and the one "+", within the thumb's reach. */
|
|
|
|
.float-bar {
|
|
position: absolute;
|
|
z-index: 3;
|
|
left: max(16px, env(safe-area-inset-left));
|
|
right: max(16px, env(safe-area-inset-right));
|
|
bottom: calc(12px + var(--safe-bottom));
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
|
|
.search {
|
|
flex: 1;
|
|
min-width: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
height: 48px;
|
|
padding: 0 18px;
|
|
border-radius: 24px;
|
|
background: var(--bar);
|
|
-webkit-backdrop-filter: blur(20px);
|
|
backdrop-filter: blur(20px);
|
|
box-shadow: var(--lift);
|
|
color: var(--ink-2);
|
|
}
|
|
|
|
.search .icon {
|
|
width: 17px;
|
|
height: 17px;
|
|
}
|
|
|
|
.search-input {
|
|
flex: 1;
|
|
min-width: 0;
|
|
height: 100%;
|
|
border: 0;
|
|
outline: 0;
|
|
padding: 0;
|
|
background: none;
|
|
color: var(--ink);
|
|
font: 16px var(--ui);
|
|
-webkit-appearance: none;
|
|
appearance: none;
|
|
-webkit-user-select: text;
|
|
user-select: text;
|
|
}
|
|
|
|
.search-input::placeholder {
|
|
color: var(--ink-2);
|
|
}
|
|
|
|
.search-input::-webkit-search-cancel-button {
|
|
-webkit-appearance: none;
|
|
}
|
|
|
|
.fab {
|
|
display: grid;
|
|
place-items: center;
|
|
flex: none;
|
|
width: 48px;
|
|
height: 48px;
|
|
border-radius: 24px;
|
|
background: var(--ink);
|
|
color: var(--accent-ink);
|
|
box-shadow: var(--lift);
|
|
transition: transform 0.15s var(--ease);
|
|
}
|
|
|
|
.fab .icon {
|
|
width: 20px;
|
|
height: 20px;
|
|
}
|
|
|
|
.fab:active {
|
|
transform: scale(0.93);
|
|
transition: none;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* The New tab sheet */
|
|
|
|
.scrim {
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 20;
|
|
display: flex;
|
|
align-items: flex-end;
|
|
padding: 8px;
|
|
background: rgb(0 0 0 / 0.28);
|
|
animation: fade-in 0.22s ease-out;
|
|
}
|
|
|
|
.scrim.leaving {
|
|
animation: fade-out 0.22s ease-in forwards;
|
|
}
|
|
|
|
.sheet {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 20px;
|
|
width: 100%;
|
|
max-height: calc(100% - env(safe-area-inset-top) - 24px);
|
|
padding: 10px 20px calc(20px + var(--safe-bottom));
|
|
border-radius: 44px;
|
|
background: var(--canvas);
|
|
box-shadow: var(--shadow);
|
|
animation: sheet-in 0.36s var(--ease);
|
|
}
|
|
|
|
.scrim.leaving .sheet {
|
|
animation: sheet-out 0.22s ease-in forwards;
|
|
}
|
|
|
|
.sheet-grip {
|
|
align-self: center;
|
|
width: 36px;
|
|
height: 5px;
|
|
border-radius: 3px;
|
|
background: var(--line);
|
|
}
|
|
|
|
.sheet-head {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 0 4px;
|
|
}
|
|
|
|
.sheet-title {
|
|
font-size: 20px;
|
|
font-weight: 600;
|
|
letter-spacing: -0.015em;
|
|
}
|
|
|
|
.sheet-head .round {
|
|
width: 32px;
|
|
height: 32px;
|
|
color: var(--ink-2);
|
|
}
|
|
|
|
.sheet-head .round .icon {
|
|
width: 16px;
|
|
height: 16px;
|
|
}
|
|
|
|
.sheet-body {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 20px;
|
|
min-height: 0;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.sheet-group .group-title {
|
|
padding: 0 4px 8px;
|
|
}
|
|
|
|
.agent-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
gap: 8px;
|
|
}
|
|
|
|
.agent-choice {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 8px;
|
|
height: 84px;
|
|
border-radius: 18px;
|
|
background: var(--cell);
|
|
box-shadow: 0 0 0 0.5px var(--hair);
|
|
font-size: 14px;
|
|
transition: box-shadow 0.2s;
|
|
}
|
|
|
|
.agent-choice.on {
|
|
box-shadow: 0 0 0 1.5px var(--ink);
|
|
font-weight: 600;
|
|
}
|
|
|
|
.row.choice {
|
|
min-height: 52px;
|
|
gap: 12px;
|
|
}
|
|
|
|
.row.choice .row-title {
|
|
flex: 1;
|
|
min-width: 0;
|
|
font-size: 16px;
|
|
font-weight: 400;
|
|
}
|
|
|
|
.row-meta {
|
|
flex: none;
|
|
max-width: 45%;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
font-size: 13px;
|
|
color: var(--ink-2);
|
|
}
|
|
|
|
.choice-check {
|
|
flex: none;
|
|
width: 16px;
|
|
height: 16px;
|
|
}
|
|
|
|
.sheet-open {
|
|
flex: none;
|
|
}
|
|
|
|
@keyframes fade-in {
|
|
from {
|
|
background: rgb(0 0 0 / 0);
|
|
}
|
|
}
|
|
|
|
@keyframes fade-out {
|
|
to {
|
|
background: rgb(0 0 0 / 0);
|
|
}
|
|
}
|
|
|
|
@keyframes sheet-in {
|
|
from {
|
|
transform: translateY(105%);
|
|
}
|
|
}
|
|
|
|
@keyframes sheet-out {
|
|
to {
|
|
transform: translateY(105%);
|
|
}
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------ */
|
|
/* Moving between screens: the incoming screen slides over the outgoing one,
|
|
which recedes a little; back reverses it. */
|
|
|
|
::view-transition-group(root) {
|
|
animation-duration: 0.44s;
|
|
animation-timing-function: var(--ease);
|
|
}
|
|
|
|
::view-transition-old(root),
|
|
::view-transition-new(root) {
|
|
animation-duration: 0.44s;
|
|
animation-timing-function: var(--ease);
|
|
mix-blend-mode: normal;
|
|
}
|
|
|
|
html[data-nav="push"]::view-transition-old(root) {
|
|
animation-name: recede;
|
|
}
|
|
|
|
html[data-nav="push"]::view-transition-new(root) {
|
|
animation-name: arrive;
|
|
box-shadow: -12px 0 32px rgb(0 0 0 / 0.14);
|
|
}
|
|
|
|
html[data-nav="pop"]::view-transition-old(root) {
|
|
z-index: 2;
|
|
animation-name: depart;
|
|
box-shadow: -12px 0 32px rgb(0 0 0 / 0.14);
|
|
}
|
|
|
|
html[data-nav="pop"]::view-transition-new(root) {
|
|
z-index: 1;
|
|
animation-name: return;
|
|
}
|
|
|
|
@keyframes arrive {
|
|
from {
|
|
transform: translateX(100%);
|
|
}
|
|
}
|
|
|
|
@keyframes recede {
|
|
to {
|
|
transform: translateX(-28%);
|
|
filter: brightness(0.9);
|
|
}
|
|
}
|
|
|
|
@keyframes depart {
|
|
to {
|
|
transform: translateX(100%);
|
|
}
|
|
}
|
|
|
|
@keyframes return {
|
|
from {
|
|
transform: translateX(-28%);
|
|
filter: brightness(0.9);
|
|
}
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
*,
|
|
::view-transition-old(root),
|
|
::view-transition-new(root) {
|
|
animation: none !important;
|
|
transition: none !important;
|
|
}
|
|
}
|