/* p-chat: a videocassette sleeve. Cream card, ink type, the four bands
   (yellow, light orange, orange, red), a script on the red, boxed labels. */
@font-face { font-family: 'Righteous'; src: url(fonts/righteous-latin.woff2) format('woff2'); font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Righteous'; src: url(fonts/righteous-latin-ext.woff2) format('woff2'); font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Jost'; src: url(fonts/jost-latin.woff2) format('woff2'); font-weight: 100 900; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Jost'; src: url(fonts/jost-latin-ext.woff2) format('woff2'); font-weight: 100 900; font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Yellowtail'; src: url(fonts/yellowtail-latin.woff2) format('woff2'); font-display: swap; }

:root {
  --cream: #f3e8cf;
  --cream-2: #ebdfc2;
  --paper: #f8f0dc;
  --ink: #15120f;
  --ink-2: #4a4035;
  --yellow: #f3c63f;
  --amber: #f0a33b;
  --orange: #e96a2b;
  --red: #d4382a;
  --red-deep: #b72d22;
  --script: #f7ecd5;
  --live: #2c7a3f;
  --violet: #5b2bd8;
  --outside: #2a221b;
  --band-ink: var(--ink);
  --line: rgba(21,18,15,.85);
  --ledge: #000;
  --press: 0 4px 0 #000, 0 4px 0 #000, 0 4px 0 #000;
  --pressed: 0 0 0 #000, 0 0 0 #000, 0 0 0 #000;
  --press-ring: 0 5px 0 4px var(--ink), 0 5px 0 4px var(--ink), 0 5px 0 4px var(--ink);
  --pressed-ring: 0 0 0 4px var(--ink), 0 0 0 4px var(--ink), 0 0 0 4px var(--ink);
  --bubble: 0 2px 0 rgba(0,0,0,.18), 0 2px 0 rgba(0,0,0,0);
  --key-ledge: var(--ink);
  --mine: var(--orange);
  --mine-ink: #fffaf0;
  --foot: var(--red);
  --mark: #d4382a;
  --label-bg: var(--yellow);
  --count-ink: var(--yellow);
  --scan: rgba(0,0,0,.045);
  --vignette: rgba(80,50,20,.18);
  --scan-blend: multiply;
  --stripes: linear-gradient(var(--yellow) 0 3px, var(--amber) 3px 6px, var(--orange) 6px 9px);
  --stripes-up: linear-gradient(var(--orange) 0 3px, var(--amber) 3px 6px, var(--yellow) 6px 9px);
  --fallback: system-ui, -apple-system, 'Segoe UI', Roboto, 'Noto Sans', 'Noto Sans Arabic', 'Noto Sans Hebrew',
    'Noto Sans Devanagari', 'Noto Sans Thai', 'PingFang SC', 'Hiragino Sans', 'Noto Sans CJK SC', 'Noto Sans CJK JP',
    'Apple SD Gothic Neo', 'Malgun Gothic', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji';
  --display: 'Righteous', 'Arial Rounded MT Bold', var(--fallback);
  --sans: 'Jost', 'Futura', 'Avenir Next', var(--fallback);
  --script-font: 'Yellowtail', 'Brush Script MT', cursive;
  --gutter: 18px;
  color-scheme: light;
}
/* Dark: the black sleeve - white type, outlined labels, and the stripes
   from yellow through orange, red and magenta to violet. Follows the phone,
   unless chosen (html[data-theme]). */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme=light]) {
  --cream: #141414; --cream-2: #242424; --paper: #1d1d1d;
  --ink: #f3f1ec; --ink-2: #a7a39c;
  --yellow: #ffc21a; --amber: #ff8f1f; --orange: #ff4f2b; --red: #d81f8a; --violet: #5b2bd8;
  --script: #ffffff; --outside: #050505; --band-ink: #121212;
  --line: rgba(243,241,236,.82); --ledge: #5b2bd8; --key-ledge: #7a0f4e;
  --mine: #5b2bd8; --mine-ink: #ffffff; --foot: #5b2bd8; --mark: #ff4f2b;
  --label-bg: #141414; --count-ink: #121212;
  --scan: rgba(255,255,255,.035); --vignette: rgba(0,0,0,.35); --scan-blend: normal;
  --stripes: linear-gradient(var(--yellow) 0 2px, var(--amber) 2px 4px, var(--orange) 4px 6px, var(--red) 6px 8px, var(--violet) 8px 10px);
  --stripes-up: linear-gradient(var(--violet) 0 2px, var(--red) 2px 4px, var(--orange) 4px 6px, var(--amber) 6px 8px, var(--yellow) 8px 10px);
  --press: 1px 2px 0 #c9c4bb, 2px 4px 0 #c2187c, 3px 6px 0 #3b1d94;
  --pressed: 0 0 0 #c9c4bb, 0 0 0 #c2187c, 0 0 0 #3b1d94;
  --press-ring: 1px 2px 0 4px #c9c4bb, 2px 4px 0 4px #c2187c, 3px 6px 0 4px #3b1d94;
  --pressed-ring: 0 0 0 4px #c9c4bb, 0 0 0 4px #c2187c, 0 0 0 4px #3b1d94;
  --bubble: 1px 2px 0 rgba(201,196,187,.45), 2px 4px 0 rgba(194,24,124,.55);
  --sink: 6px; --sink-x: 3px;
  color-scheme: dark;
  }
}
:root[data-theme=dark] {
  --cream: #141414; --cream-2: #242424; --paper: #1d1d1d;
  --ink: #f3f1ec; --ink-2: #a7a39c;
  --yellow: #ffc21a; --amber: #ff8f1f; --orange: #ff4f2b; --red: #d81f8a; --violet: #5b2bd8;
  --script: #ffffff; --outside: #050505; --band-ink: #121212;
  --line: rgba(243,241,236,.82); --ledge: #5b2bd8; --key-ledge: #7a0f4e;
  --mine: #5b2bd8; --mine-ink: #ffffff; --foot: #5b2bd8; --mark: #ff4f2b;
  --label-bg: #141414; --count-ink: #121212;
  --scan: rgba(255,255,255,.035); --vignette: rgba(0,0,0,.35); --scan-blend: normal;
  --stripes: linear-gradient(var(--yellow) 0 2px, var(--amber) 2px 4px, var(--orange) 4px 6px, var(--red) 6px 8px, var(--violet) 8px 10px);
  --stripes-up: linear-gradient(var(--violet) 0 2px, var(--red) 2px 4px, var(--orange) 4px 6px, var(--amber) 6px 8px, var(--yellow) 8px 10px);
  --press: 1px 2px 0 #c9c4bb, 2px 4px 0 #c2187c, 3px 6px 0 #3b1d94;
  --pressed: 0 0 0 #c9c4bb, 0 0 0 #c2187c, 0 0 0 #3b1d94;
  --press-ring: 1px 2px 0 4px #c9c4bb, 2px 4px 0 4px #c2187c, 3px 6px 0 4px #3b1d94;
  --pressed-ring: 0 0 0 4px #c9c4bb, 0 0 0 4px #c2187c, 0 0 0 4px #3b1d94;
  --bubble: 1px 2px 0 rgba(201,196,187,.45), 2px 4px 0 rgba(194,24,124,.55);
  --sink: 6px; --sink-x: 3px;
  color-scheme: dark;
}

* { box-sizing: border-box; }
html { background: var(--outside); -webkit-text-size-adjust: 100%; }
body {
  margin: 0; min-height: 100dvh; font-family: var(--sans); color: var(--ink); background: var(--outside);
  display: flex; justify-content: center;
}
button, input, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; }
:focus-visible { outline: 3px solid var(--ink); outline-offset: 2px; }

/* The sleeve: a card, with print grain and the faint scan of a tape. */
#app {
  position: relative; width: 100%; max-width: 480px; min-height: 100dvh; display: flex; flex-direction: column;
  background: var(--cream); overflow: hidden;
  box-shadow: 0 0 0 1px rgba(0,0,0,.25), 0 30px 80px rgba(0,0,0,.45);
}
#app::after {
  content: ''; position: absolute; inset: 0; pointer-events: none; z-index: 50; mix-blend-mode: var(--scan-blend); opacity: .5;
  background:
    repeating-linear-gradient(0deg, var(--scan) 0 1px, transparent 1px 3px),
    radial-gradient(ellipse at 30% 20%, transparent 55%, var(--vignette) 100%);
}

/* The head of the sleeve: the mark, the year, the display type. */
.head { padding: 26px var(--gutter) 10px; position: relative; }
.display {
  font: 400 clamp(54px, 17vw, 86px)/.92 var(--display); letter-spacing: -.01em; margin: 18px 0 6px;
  text-shadow: 1.2px 0 rgba(212,56,42,.55), -1.2px 0 rgba(30,110,160,.35);
  overflow-wrap: anywhere;
}
.display.small { font-size: clamp(36px, 11vw, 54px); margin-top: 10px; }
.back {
  border: 0; background: none; padding: 6px 0; font: 700 14px/1 var(--sans); letter-spacing: .12em; text-transform: uppercase;
}

/* Bands: the stripes that cross the sleeve. */
.band { padding: 12px var(--gutter); position: relative; color: var(--band-ink); }
.band.yellow { background: var(--yellow); }
.band.amber { background: var(--amber); }
.band.orange { background: var(--orange); }
.band.red { background: var(--red); color: var(--script); }
.band + .band { border-top: 3px solid var(--cream); }
.band::before { /* the halftone of cheap print */
  content: ''; position: absolute; inset: 0; pointer-events: none; opacity: .14;
  background-image: radial-gradient(rgba(0,0,0,.6) .6px, transparent .8px); background-size: 3px 3px;
}
.caps { font: 700 17px/1.18 var(--sans); text-transform: uppercase; letter-spacing: .01em; margin: 0; }
.caps.light { font-weight: 500; }
.stripe { height: 34px; }
.script {
  font: 400 clamp(56px, 18vw, 96px)/.9 var(--script-font); color: var(--script); margin: 0;
  transform: rotate(-6deg); transform-origin: left; text-shadow: 1px 1px 0 rgba(0,0,0,.15);
}

/* Boxed labels: S-Video, 2D SOUL. */
.label {
  display: inline-flex; align-items: center; gap: 6px; border: 3px solid var(--ink); background: var(--label-bg);
  padding: 2px 8px; font: 500 18px/1.1 var(--display); color: var(--ink); white-space: nowrap;
  box-shadow: 0 0 0 2px var(--label-bg), 0 0 0 4px var(--ink);
  margin: 4px;
}
.label.cream { background: var(--cream); box-shadow: 0 0 0 2px var(--cream), 0 0 0 4px var(--ink); }
.label.live { background: #d9ecc8; box-shadow: 0 0 0 2px #d9ecc8, 0 0 0 4px var(--ink); }
.label .dot { width: 10px; height: 10px; border-radius: 50%; background: currentColor; }
.label.live .dot { background: var(--live); }

/* Main area. */
main { flex: 1; display: flex; flex-direction: column; position: relative; z-index: 1; }
.pad { padding: 14px var(--gutter); }
.muted { color: var(--ink-2); }
.fine { font: 500 13px/1.4 var(--sans); color: var(--ink-2); }
p { line-height: 1.45; margin: 8px 0; }

/* Buttons are pressed tape keys. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 48px; padding: 10px 18px;
  border: 3px solid var(--ink); background: var(--ink); color: var(--cream); font: 700 16px/1 var(--sans);
  letter-spacing: .1em; text-transform: uppercase; border-radius: 12px; box-shadow: var(--press); margin-bottom: 4px;
  transition: transform .06s, box-shadow .06s;
}
.btn:active { transform: translate(var(--sink-x, 0), var(--sink, 4px)); box-shadow: var(--pressed); }
button.label { box-shadow: 0 0 0 2px var(--label-bg), 0 0 0 4px var(--ink), var(--press-ring); transition: transform .06s, box-shadow .06s; }
button.label.cream { box-shadow: 0 0 0 2px var(--cream), 0 0 0 4px var(--ink), var(--press-ring); }
button.label:active { transform: translate(var(--sink-x, 0), var(--sink, 4px)); box-shadow: 0 0 0 2px var(--label-bg), 0 0 0 4px var(--ink), var(--pressed-ring); }
button.label.cream:active { box-shadow: 0 0 0 2px var(--cream), 0 0 0 4px var(--ink), var(--pressed-ring); }
.spine:active { background: var(--cream-2); }
.btn.light { background: var(--cream); color: var(--ink); }
.btn.warn { background: var(--red); border-color: var(--ink); color: var(--script); }
.btn.wide { width: 100%; }
.btn[disabled] { opacity: .5; cursor: default; }
.row { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }

/* Fields. */
.field { display: block; margin: 12px 0; }
.field span { display: block; font: 700 12px/1 var(--sans); letter-spacing: .14em; text-transform: uppercase; margin-bottom: 6px; }
.field input, .field textarea, .field select {
  width: 100%; border: 3px solid var(--ink); background: var(--paper); padding: 12px 12px; border-radius: 10px; font-size: 17px;
}
.field textarea { min-height: 96px; resize: vertical; }

/* The contact list: spines of tapes on a shelf. */
.shelf { list-style: none; margin: 0; padding: 0; }
.spine {
  display: grid; grid-template-columns: 14px 1fr auto; gap: 12px; align-items: center; width: 100%;
  border: 0; border-bottom: 3px solid var(--ink); background: var(--paper); padding: 14px var(--gutter) 14px 0; text-align: left;
}
.spine .tag { align-self: stretch; }
.spine:nth-child(4n+1) .tag { background: var(--yellow); }
.spine:nth-child(4n+2) .tag { background: var(--amber); }
.spine:nth-child(4n+3) .tag { background: var(--orange); }
.spine:nth-child(4n+4) .tag { background: var(--red); }
.spine .name { font: 400 26px/1 var(--display); display: block; overflow-wrap: anywhere; }
.spine .last { font: 500 14px/1.3 var(--sans); color: var(--ink-2); display: block; margin-top: 4px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 62vw; }
.count {
  min-width: 34px; height: 34px; padding: 0 8px; border-radius: 8px; background: var(--ink); color: var(--count-ink);
  font: 400 20px/34px var(--display); text-align: center;
}
.empty { padding: 26px var(--gutter); }

/* The conversation: the tape gets the room. */
.chathead { display: grid; grid-template-columns: auto 1fr auto; gap: 8px; align-items: center;
  padding: 10px var(--gutter) 8px; background: var(--cream); position: sticky; top: 0; z-index: 3; }
.chathead h1 { margin: 0; font: 400 24px/1.05 var(--display); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chathead .sub { font: 600 10px/1.2 var(--sans); letter-spacing: .14em; text-transform: uppercase; color: var(--ink-2); }
.chathead .back { font-size: 20px; padding: 6px 6px 6px 0; }
.chathead .label { font-size: 14px; padding: 1px 7px; border-width: 2px; box-shadow: var(--press); margin: 0 0 3px; }
.chathead .label:active { transform: translate(var(--sink-x, 0), var(--sink, 3px)); box-shadow: var(--pressed); }
.tape { flex: 1; overflow-y: auto; padding: 22px 12px 12px; display: flex; flex-direction: column; gap: 4px; }
.msg { max-width: 86%; padding: 8px 12px 7px; border-radius: 18px 18px 18px 6px; background: var(--paper);
  border: 2px solid var(--line); box-shadow: var(--bubble);
  font: 500 16.5px/1.38 var(--sans); white-space: pre-wrap; overflow-wrap: anywhere; }
.msg.mine { align-self: flex-end; background: var(--mine); color: var(--mine-ink); border-color: var(--line);
  border-radius: 18px 18px 6px 18px; }
.msg + .msg.mine, .msg.mine + .msg { margin-top: 6px; }
.msg .meta { display: inline-block; margin-left: 8px; font: 600 9.5px/1 var(--sans); letter-spacing: .1em; text-transform: uppercase;
  opacity: .62; vertical-align: 1px; white-space: nowrap; }
.day { align-self: center; font: 700 10px/1 var(--sans); letter-spacing: .16em; text-transform: uppercase; color: var(--ink-2); margin: 10px 0 6px; }
.composer { display: flex; align-items: flex-end; gap: 10px; padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
  background: linear-gradient(var(--cream) 0 0) padding-box; position: sticky; bottom: 0; z-index: 3; }
.composer::before { content: ''; position: absolute; left: 0; right: 0; bottom: 100%; height: 10px;
  background: var(--stripes-up); }
.composer textarea { flex: 1; border: 2px solid var(--line); background: var(--paper); border-radius: 22px; padding: 10px 16px;
  font: 500 16.5px/1.3 var(--sans); min-height: 44px; max-height: 140px; resize: none; box-shadow: inset 0 2px 0 rgba(21,18,15,.08); }
.composer textarea:focus { outline: none; border-color: var(--red); }
/* The send key: a round tape key, pressed in when pushed. */
.key { flex: none; width: 46px; height: 46px; border-radius: 50%; border: 2px solid var(--ink); background: var(--red); color: var(--script);
  display: grid; place-items: center; padding: 0; box-shadow: var(--press); transition: transform .06s, box-shadow .06s;
  margin-bottom: 6px; }
.key svg { width: 20px; height: 20px; margin-left: 3px; }
.key:active, .key.pressed { transform: translate(var(--sink-x, 0), var(--sink, 4px)); box-shadow: var(--pressed); }
.key[disabled] { background: var(--cream-2); color: var(--ink-2); }

/* Banners: what must be seen. */
.banner { margin: 10px var(--gutter); padding: 12px 14px; border: 3px solid var(--ink); border-radius: 12px; background: var(--yellow);
  font: 600 15px/1.35 var(--sans); color: var(--band-ink); }
.banner.red { background: var(--red); color: var(--script); }
.banner b { display: block; font: 400 20px/1.1 var(--display); margin-bottom: 4px; }

/* Invite: the code and the picture. */
.qr { background: #fff; border: 4px solid var(--ink); border-radius: 14px; padding: 14px; width: min(100%, 300px); margin: 6px auto;
  display: block; image-rendering: pixelated; aspect-ratio: 1; }
.words { display: grid; grid-template-columns: 1fr 1fr; gap: 6px 14px; counter-reset: w; margin: 10px 0; padding: 0; list-style: none; }
.words li { counter-increment: w; font: 800 24px/1.2 var(--sans); }
.words li::before { content: counter(w); font: 400 15px/1 var(--display); margin-right: 8px; color: var(--red); }
.choice { display: block; width: 100%; text-align: left; border: 0; padding: 16px var(--gutter); position: relative; color: var(--band-ink); }
.choice.yellow { background: var(--yellow); } .choice.amber { background: var(--amber); } .choice.orange { background: var(--orange); }
.choice + .choice { border-top: 3px solid var(--cream); }
.choice .caps { font-size: 19px; }

/* The fingerprint. */
.emoji { display: flex; justify-content: center; gap: 10px; margin: 14px 0 6px; }
.emoji div { display: flex; flex-direction: column; align-items: center; width: 22%; }
.emoji .g { width: 48px; height: 48px; display: block; margin-bottom: 4px; }
.emoji .n { font: 600 11px/1.2 var(--sans); text-align: center; text-transform: uppercase; letter-spacing: .06em; }

/* Devices. */
.device { border: 3px solid var(--ink); border-radius: 12px; padding: 12px 14px; margin: 10px var(--gutter); background: var(--paper); }
.device .who { font: 400 20px/1.1 var(--display); }
.device .id { font: 500 12px/1.2 ui-monospace, monospace; color: var(--ink-2); overflow-wrap: anywhere; }

/* The foot: the red band and its script. */
.foot { background: var(--foot); padding: 14px var(--gutter) calc(16px + env(safe-area-inset-bottom)); position: relative; z-index: 1;
  border-top: 3px solid var(--cream); }
.foot .row { justify-content: space-between; }
.foot .script { font-size: clamp(48px, 15vw, 80px); }
.lines { border-top: 3px solid var(--ink); }
.lines::before, .lines::after { content: ''; display: block; height: 2px; background: var(--ink); margin-top: 3px; }
/* Centred by its margins: its rising animation moves it with a transform of its own. */
.toast { position: fixed; left: 16px; right: 16px; bottom: calc(18px + env(safe-area-inset-bottom)); margin: 0 auto; z-index: 99; max-width: 440px;
  overflow-wrap: anywhere;
  background: var(--ink); color: var(--cream); border-radius: 12px; padding: 12px 14px; font: 600 14px/1.35 var(--sans); }
.mono { font-family: ui-monospace, monospace; font-size: 13px; overflow-wrap: anywhere; }
.hidden { display: none !important; }
.check { display: flex; gap: 10px; align-items: flex-start; margin: 4px 0 14px; font: 500 14px/1.4 var(--sans); }
.check input { width: 22px; height: 22px; margin: 2px 0 0; accent-color: var(--orange); flex: none; }
/* The sleeve's bands, thin, under the conversation's head. */
.chathead::after { content: ''; position: absolute; left: 0; right: 0; top: 100%; height: 10px; pointer-events: none;
  background: var(--stripes); }

/* In the dark the print's dots and the sleeve's edge are light, not dark. */
@media (prefers-color-scheme: dark) { :root:not([data-theme=light]) .band::before { opacity: .1; } }
:root[data-theme=dark] .band::before { opacity: .1; }
.banner.red { color: var(--script); }
.theme { display: flex; gap: 8px; margin: 8px 0 14px; }
.theme button[aria-pressed=true] { background: var(--ink); color: var(--cream); }
/* The notification symbol: keys like the rest; the chosen one stays pressed in. */
.signals { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0 10px; }
.sig { width: 46px; height: 46px; display: grid; place-items: center; border: 3px solid var(--ink); border-radius: 12px;
  background: var(--cream); color: var(--ink); font: 700 20px/1 var(--sans); box-shadow: var(--press); margin-bottom: 4px;
  transition: transform .06s, box-shadow .06s; }
.sig img.g { width: 26px; height: 26px; }
.sig[aria-checked=true] { background: var(--yellow); transform: translate(var(--sink-x, 0), var(--sink, 4px)); box-shadow: var(--pressed); }
.guide ol { margin: 6px 0 8px 1.2em; padding: 0; }
.guide li { margin: 4px 0; }

/* The full run of stripes in the dark; only three in the light. */
.band.magenta { background: var(--red); } .band.violet { background: var(--violet); }
.band.dark-only { display: none; }
@media (prefers-color-scheme: dark) { :root:not([data-theme=light]) .band.dark-only { display: block; }
  }
:root[data-theme=dark] .band.dark-only { display: block; }

/* The wordmark: p, the tape's stripes for a dash, chat. */
.logo { display: inline-flex; align-items: center; font: 400 30px/1 var(--display); letter-spacing: -.01em; color: var(--ink);
  text-shadow: 1px 0 rgba(212,56,42,.5), -1px 0 rgba(30,110,160,.35); user-select: none; -webkit-tap-highlight-color: transparent; }
.logo .dash { display: inline-flex; flex-direction: column; width: 24px; height: 15px; margin: 5px 3px 0 4px; transform: skewX(-24deg); }
.logo .dash i { flex: 1; display: block; transform-origin: left; animation: wipe .55s cubic-bezier(.2,.9,.2,1) both; }
.logo .dash i:nth-child(1) { background: var(--yellow); animation-delay: .05s; }
.logo .dash i:nth-child(2) { background: var(--amber); animation-delay: .1s; }
.logo .dash i:nth-child(3) { background: var(--orange); animation-delay: .15s; }
.logo .dash i:nth-child(4) { background: var(--red); animation-delay: .2s; }
.logo .dash i:nth-child(5) { background: var(--violet); animation-delay: .25s; }
.logo:active .dash i { animation-name: wipe-again; }
@keyframes wipe { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes wipe-again { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* Entering a screen: in from the side it lies on, a pass of the tape's
   tracking, the title splitting into its colours and closing. Transforms
   and opacity only: cheap on any phone. */
#app.enter > main, #app.enter > .head, #app.enter > .chathead { animation: in-right .34s cubic-bezier(.2,.8,.2,1) both; }
#app.enter.from-left > main, #app.enter.from-left > .head, #app.enter.from-left > .chathead { animation-name: in-left; }
#app.enter > .head { animation-duration: .28s; }
#app.enter > .foot, #app.enter > .composer { animation: rise .38s cubic-bezier(.2,.8,.2,1) both; }
#app.enter::before { content: ''; position: absolute; left: 0; right: 0; top: 0; height: 90px; z-index: 60; pointer-events: none;
  background: linear-gradient(transparent, rgba(255,255,255,.22) 45%, rgba(255,45,140,.12) 55%, transparent);
  animation: track .45s linear both; }
#app.enter .display { animation: split .45s ease-out both; }
#app.enter .band, #app.enter .choice { animation: band-in .5s cubic-bezier(.2,.9,.2,1) both; transform-origin: left; }
#app.enter .band:nth-child(2), #app.enter .choice:nth-child(2) { animation-delay: .05s; }
#app.enter .band:nth-child(3), #app.enter .choice:nth-child(3) { animation-delay: .1s; }
#app.enter .band:nth-child(4) { animation-delay: .15s; }
#app.enter .band:nth-child(5) { animation-delay: .2s; }
#app.enter .band:nth-child(6) { animation-delay: .25s; }
#app.enter .spine { animation: in-right .4s cubic-bezier(.2,.8,.2,1) both; }
#app.enter li:nth-child(2) .spine { animation-delay: .04s; } #app.enter li:nth-child(3) .spine { animation-delay: .08s; }
#app.enter li:nth-child(4) .spine { animation-delay: .12s; } #app.enter li:nth-child(n+5) .spine { animation-delay: .16s; }
@keyframes in-right { from { opacity: 0; transform: translateX(28px); } to { opacity: 1; transform: none; } }
@keyframes in-left { from { opacity: 0; transform: translateX(-28px); } to { opacity: 1; transform: none; } }
@keyframes rise { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: none; } }
@keyframes track { from { transform: translateY(-90px); opacity: 1; } to { transform: translateY(100dvh); opacity: .6; } }
@keyframes split { 0% { text-shadow: 9px 0 rgba(212,56,42,.8), -9px 0 rgba(30,160,210,.7); } 60% { text-shadow: -2px 0 rgba(212,56,42,.6), 2px 0 rgba(30,160,210,.5); }
  100% { text-shadow: 1.2px 0 rgba(212,56,42,.55), -1.2px 0 rgba(30,110,160,.35); } }
@keyframes band-in { from { transform: scaleX(0); } to { transform: none; } }

/* A new message pops from its own side; the send key fires its triangle. */
.msg.new { animation: pop .36s cubic-bezier(.2,1.45,.4,1) both; transform-origin: bottom left; }
.msg.mine.new { transform-origin: bottom right; }
@keyframes pop { from { opacity: 0; transform: scale(.55) translateY(10px); } to { opacity: 1; transform: none; } }
.key.fire svg { animation: fire .44s cubic-bezier(.2,.8,.2,1); }
@keyframes fire { 0% { transform: none; } 40% { transform: translateX(16px) scale(.6); opacity: 0; }
  41% { transform: translateX(-14px) scale(.6); opacity: 0; } 100% { transform: none; opacity: 1; } }
.count.bump { animation: bump .5s cubic-bezier(.2,1.6,.4,1); }
@keyframes bump { 0% { transform: scale(.4); } 100% { transform: none; } }
.emoji > div { animation: drop .55s cubic-bezier(.2,1.5,.4,1) both; }
.emoji > div:nth-child(2) { animation-delay: .09s; } .emoji > div:nth-child(3) { animation-delay: .18s; } .emoji > div:nth-child(4) { animation-delay: .27s; }
@keyframes drop { from { opacity: 0; transform: translateY(-26px) rotate(-12deg) scale(.6); } to { opacity: 1; transform: none; } }
.words li { animation: rise .4s cubic-bezier(.2,.8,.2,1) both; }
.words li:nth-child(2) { animation-delay: .06s; } .words li:nth-child(3) { animation-delay: .12s; }
.words li:nth-child(4) { animation-delay: .18s; } .words li:nth-child(5) { animation-delay: .24s; } .words li:nth-child(6) { animation-delay: .3s; }
.banner.red { animation: shake .45s cubic-bezier(.3,.7,.4,1); }
@keyframes shake { 0%, 100% { transform: none; } 20% { transform: translateX(-7px); } 40% { transform: translateX(6px); } 60% { transform: translateX(-4px); } 80% { transform: translateX(2px); } }
.spine { transition: transform .12s, background .12s; }
.spine:active { transform: translateX(6px); }
.composer textarea { transition: border-color .15s, box-shadow .15s; }
.toast { animation: rise .3s cubic-bezier(.2,.8,.2,1) both; }

/* Someone who asked for less motion gets none. */
/* Live state: the court and the board. */
canvas.court, canvas.sheet { display: block; width: 100%; height: auto; border-radius: 14px; border: 3px solid #f3e8cf; touch-action: none;
  box-shadow: 2px 3px 0 #ffc21a, 4px 6px 0 #ff4f2b, 6px 9px 0 #5b2bd8; }
canvas.sheet { aspect-ratio: 1; cursor: crosshair; }
.swatches { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; }
.swatch { width: 34px; height: 34px; border-radius: 50%; border: 3px solid #f3e8cf; box-shadow: var(--press); }
.swatch[aria-checked=true] { transform: translate(var(--sink-x, 0), var(--sink, 4px)); box-shadow: var(--pressed); outline: 3px solid #ffc21a; }
.callhead .back { color: inherit; background: none; border: 0; font-size: 20px; padding: 0 6px 0 0; float: left; }

/* A call: the deck. The other side on the screen, you in a corner, the keys below. */
.call-key { display: inline-grid; place-items: center; padding: 2px 8px; }
.call-key svg { width: 18px; height: 18px; }
.banner.ring { background: var(--amber); animation: ring 1.2s ease-in-out infinite; }
@keyframes ring { 0%, 100% { transform: none; } 10% { transform: rotate(-1deg); } 20% { transform: rotate(1deg); } 30% { transform: none; } }
.callhead { padding: 14px var(--gutter) 6px; background: #141414; color: #f3e8cf; }
.callhead h1 { margin: 0; font: 400 26px/1.05 var(--display); }
.callhead .sub { font: 600 10px/1.2 var(--sans); letter-spacing: .14em; text-transform: uppercase; opacity: .7; }
main.call { position: relative; background: #141414; color: #f3e8cf; padding: 10px var(--gutter) 16px; min-height: 60vh; }
.tiles { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.tile { margin: 0; border: 3px solid #f3e8cf; border-radius: 14px; overflow: hidden; background: #000; position: relative;
  box-shadow: 2px 3px 0 #ffc21a, 4px 6px 0 #ff4f2b, 6px 9px 0 #5b2bd8; }
.tile canvas { display: block; width: 100%; aspect-ratio: 16 / 9; height: auto; }
.tile.picked { border-color: #ffc21a; }
.tile figcaption { position: absolute; left: 8px; bottom: 6px; font: 400 16px/1 var(--display); text-shadow: 0 1px 2px #000; }
video.me { position: absolute; right: calc(var(--gutter) + 6px); bottom: 46px; width: 28%; max-width: 160px; aspect-ratio: 16 / 9;
  object-fit: cover; border: 2px solid #f3e8cf; border-radius: 10px; background: #000; }
.call .waiting { padding: 40px 0; text-align: center; }
.call .stats { margin: 10px 0 0; font-size: 12px; opacity: .8; }
.decks { display: flex; gap: 12px; justify-content: center; align-items: center; padding: 14px var(--gutter) 22px; background: #141414; }
.deck { min-height: 44px; padding: 8px 14px; border: 2px solid #f3e8cf; border-radius: 12px; background: #222; color: #f3e8cf;
  font: 700 13px/1 var(--sans); letter-spacing: .1em; text-transform: uppercase; box-shadow: var(--press); }
.deck[aria-pressed=true] { background: #f3e8cf; color: #141414; transform: translate(var(--sink-x, 0), var(--sink, 4px)); box-shadow: var(--pressed); }
.hang { width: 64px; height: 64px; border-radius: 50%; border: 3px solid #f3e8cf; background: var(--red); color: #fff; display: grid;
  place-items: center; box-shadow: var(--press); transition: transform .06s, box-shadow .06s; }
.hang svg { width: 30px; height: 30px; }
.hang:active { transform: translate(var(--sink-x, 0), var(--sink, 4px)); box-shadow: var(--pressed); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}
.head .back { display: block; margin: -8px 0 8px; }

/* Files in the conversation. */
.msg.file { padding: 6px; max-width: 78%; }
.msg.file .meta { display: block; margin: 5px 6px 2px; }
.msg.file .pic { position: relative; border-radius: 12px; overflow: hidden; min-width: 160px; max-height: 360px; background: var(--cream-2); }
.msg.file .pic img, .msg.file .pic video { display: block; width: 100%; height: 100%; object-fit: cover; max-height: 360px; }
.msg.file .pic img.blur { filter: blur(6px) saturate(1.2); transform: scale(1.08); }
.msg.file .play { position: absolute; inset: 0; display: grid; place-items: center; font-size: 34px; color: #fff; text-shadow: 0 2px 6px rgba(0,0,0,.5); }
.msg.file .bar { position: absolute; left: 8px; right: 8px; bottom: 8px; height: 6px; border-radius: 3px; background: rgba(0,0,0,.35); overflow: hidden; }
.msg.file .bar i { display: block; height: 100%; background: var(--stripes); background: var(--yellow); transition: width .2s; }
.msg.file .doc, .msg.file .voice { position: relative; display: flex; gap: 10px; align-items: center; padding: 8px 10px 14px; min-width: 200px; }
.msg.file .doc a { color: inherit; display: flex; gap: 6px; align-items: center; text-decoration: none; }
.msg.file .doc span, .msg.file .voice { font-size: 13px; opacity: .85; }
.msg.file .voice audio { width: 230px; max-width: 100%; height: 36px; }
.msg.file .wave { letter-spacing: 2px; }
.msg.file .doc .bar, .msg.file .voice .bar { bottom: 4px; }
.msg.sticker { background: none; border: 0; box-shadow: none; padding: 0; }
.msg.sticker .sticker-img { width: 132px; height: 132px; display: block; }
.msg.sticker .meta { display: block; text-align: right; color: var(--ink-2); }
/* The attach key and its tray. */
.composer { flex-wrap: wrap; }
.key.attach { background: var(--paper); color: var(--ink); }
.key.attach svg { margin: 0; transition: transform .2s cubic-bezier(.2,1.6,.4,1); }
.key.attach.open svg { transform: rotate(45deg); }
.tray { display: flex; gap: 8px; width: 100%; order: -1; padding: 2px 0 6px; animation: rise .25s cubic-bezier(.2,.8,.2,1) both; }
.tray-key { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 8px 4px; border: 2px solid var(--line);
  border-radius: 14px; background: var(--paper); color: var(--ink); font: 700 11px/1 var(--sans); letter-spacing: .08em; text-transform: uppercase;
  box-shadow: var(--press); transition: transform .06s, box-shadow .06s; margin-bottom: 6px; }
.tray-key:active { transform: translate(var(--sink-x, 0), var(--sink, 4px)); box-shadow: var(--pressed); }
.tray-key svg { width: 22px; height: 22px; }
.tray-key.recording { background: var(--red); color: var(--script); animation: pulse 1s ease-in-out infinite; }
@keyframes pulse { 50% { filter: brightness(1.25); } }
.stickers { display: grid; grid-template-columns: repeat(6, 1fr); gap: 6px; width: 100%; order: -2; padding: 4px 0; }
.sticker-key { border: 0; background: none; padding: 2px; transition: transform .12s; }
.sticker-key:active { transform: scale(.88); }
.sticker-key img { width: 100%; display: block; }

/* Groups and channels. */
.badge { display: inline-block; margin-left: 8px; padding: 2px 6px; border: 2px solid var(--line); border-radius: 6px;
  font: 700 10px/1 var(--sans); letter-spacing: .12em; text-transform: uppercase; vertical-align: 4px; }
.speaker { font: 700 11px/1 var(--sans); letter-spacing: .08em; text-transform: uppercase; color: var(--ink-2); margin: 8px 0 0 6px; }
.composer.reader { justify-content: center; padding-top: 14px; }
.foot .row .row { flex-wrap: nowrap; gap: 8px; }
.foot .row .row .btn { padding: 10px 12px; font-size: 13px; }

/* About's lists, and what folds away (Advanced, the release's details). */
/* About: a few sections, one picture each, short sentences packed tight. */
.about .part { padding: 12px 0; border-bottom: 2px solid var(--cream-2); }
.about .part:first-child { padding-top: 2px; }
.about .part h2 { display: flex; align-items: center; gap: 8px; margin: 0 0 4px; font: 700 17px/1.2 var(--sans); text-transform: uppercase; letter-spacing: .02em; }
.about .part p { margin: 0; font: 400 15.5px/1.42 var(--sans); }
.about img.g { display: block; flex: none; }
details.more { margin-top: 18px; border-top: 3px solid var(--ink); padding-top: 10px; }
details.more summary { font: 700 14px/1.2 var(--sans); letter-spacing: .12em; text-transform: uppercase; cursor: pointer; padding: 6px 0; }
details.more .mono { word-break: break-all; }
/* The darkest pictures (a camera, a phone) keep their edge on the black sleeve. */
@media (prefers-color-scheme: dark) { :root:not([data-theme=light]) .about img.g { filter: drop-shadow(0 0 1px rgba(243,241,236,.7)); } }
:root[data-theme=dark] .about img.g { filter: drop-shadow(0 0 1px rgba(243,241,236,.7)); }

/* The fourth invite card, and the camera reading a code. */
.choice.red { background: var(--red); color: var(--script); }
.scanner { position: fixed; inset: 0; z-index: 50; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px;
  padding: 16px; background: rgba(20,18,15,.94); color: #f3e8cf; }
.scanner video { width: min(92vw, 420px); aspect-ratio: 1; object-fit: cover; border: 3px solid #f3e8cf; border-radius: 14px; background: #000; }

/* Chats with none yet: its two buttons kept apart. */
.empty .btn + .btn { margin-top: 14px; }

/* A screen with no bar at its foot: room for the phone's own edge. */
#app > main:last-child { padding-bottom: calc(28px + env(safe-area-inset-bottom)); }

/* A call key where no relay could bring a dropped call back: said, not used. */
.call-key.off { opacity: .4; }

/* A chat: as tall as what can be seen (the keyboard's room taken away), its
   messages scrolling inside it, the composer at its foot. */
#app.fitted { position: fixed; top: var(--view-top, 0); left: 0; right: 0; margin: 0 auto; height: var(--view-h, 100dvh); min-height: 0; }
#app.fitted > main { min-height: 0; overflow: hidden; }
#app.fitted .tape { min-height: 0; overscroll-behavior: contain; }
