/* board — one screen, near-monochrome, no chrome.
   Everything that is not a bubble or the launcher is deliberately invisible until needed. */

:root {
  --ink: #0b0b0c;
  --cream: #f2efe9;
  --dim: rgba(242, 239, 233, 0.42);
  --line: rgba(242, 239, 233, 0.12);
  --fill: rgba(242, 239, 233, 0.06);
  --gold: #c99a3b;
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-t: env(safe-area-inset-top, 0px);
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

/* Nothing on this board is text to be selected: holding a finger down should feel like
   holding an object, not like highlighting a word. Kills the blue selection and the iOS
   copy/paste callout everywhere — except inside the bubble he is actually typing in, which
   needs a real caret and a real selection. */
html, body, .board, .item, .bubble, .bar, .toast, .lock {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}
.item.is-editing,
[contenteditable='true'],
[contenteditable='plaintext-only'] {
  -webkit-user-select: text;
  user-select: text;
  -webkit-touch-callout: default;
}

/* The lock, the compose sheet, the popup and the toast are all shown and hidden with the
   `hidden` attribute, and every one of them carries an author `display` rule below. An
   author rule beats the UA stylesheet's [hidden]{display:none}, so without this line the
   lock screen sits on top of the board forever. Caught on a headless screenshot 2026-08-18,
   after the board underneath was already working. */
[hidden] { display: none !important; }

html, body {
  margin: 0; height: 100%;
  /* The page itself never scrolls: the board is a fixed canvas, and a scrolling page is
     exactly what makes a phone jump around when the keyboard opens. */
  overflow: hidden;
  position: fixed; inset: 0;
  background: var(--ink);
  color: var(--cream);
  font: 400 17px/1.35 -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", system-ui, sans-serif;
  overscroll-behavior: none;
}

body { display: flex; flex-direction: column; }

/* ── lock ─────────────────────────────────────────────────────────────────── */
.lock {
  position: fixed; inset: 0; z-index: 60;
  display: grid; place-content: center; justify-items: center; gap: 22px;
  background: var(--ink);
}
.lock__go {
  width: 96px; height: 96px;
  display: grid; place-items: center;
  color: var(--gold); background: none;
  border: 1px solid var(--line); border-radius: 30px;
}
.lock__go:active { background: var(--fill); }
.lock__msg { min-height: 20px; font-size: 14px; color: var(--dim); text-align: center; max-width: 78vw; }

/* ── frame ────────────────────────────────────────────────────────────────── */
.app { display: flex; flex-direction: column; height: 100%; }

.bar {
  display: flex; align-items: center; justify-content: space-between;
  padding: calc(var(--safe-t) + 12px) 18px 4px;
  position: relative; z-index: 5;
}
.bar__view {
  min-width: 34px; padding: 4px 2px;
  font: inherit; font-size: 15px; color: var(--dim);
  background: none; border: 0;
}
.bar__view.is-history { color: var(--gold); }
.bar__dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--line); transition: background .3s;
}
.bar__dot.is-pending { background: var(--gold); }
.bar__dot.is-off { background: #e06c5a; }

/* ── the board: a free canvas, bubbles live where he puts them ────────────── */
.board {
  position: relative;
  /* Only ever set while he is typing, and only if the keyboard would cover the bubble. */
  transition: transform .18s cubic-bezier(.2,.8,.3,1);
  flex: 1 1 auto;
  margin: 4px 14px calc(var(--safe-b) + 108px);
  overflow: visible;
  touch-action: none;          /* the bubbles own every gesture on this surface */
}

/* History is a list, not a canvas: past items have no place on the board. */
.board--flow {
  display: flex; flex-wrap: wrap; align-content: flex-start; gap: 10px;
  overflow-y: auto; touch-action: pan-y;
}

.item {
  --s: 1;                       /* pinch scale, set per bubble from JS */
  position: absolute;
  padding: calc(12px * var(--s)) calc(16px * var(--s));
  font-size: calc(17px * var(--s));
  line-height: 1.3;
  min-width: calc(34px * var(--s));
  max-width: min(92%, calc(260px * var(--s)));
  background: var(--fill); border: 1px solid var(--line);
  border-radius: calc(20px * var(--s));
  white-space: pre-wrap; overflow-wrap: anywhere;
  touch-action: none;
  outline: none;                /* it is contenteditable: no browser focus ring */
  will-change: transform, left, top;
  animation: land .22s ease-out;
}
@keyframes land { from { transform: scale(.9); opacity: 0; } to { transform: none; opacity: 1; } }

.item.is-dragging {
  transition: none; z-index: 3;
  border-color: rgba(242, 239, 233, .3);
  transform: scale(1.04);
  box-shadow: 0 14px 40px rgba(0, 0, 0, .45);
}
.item.is-settling { transition: transform .18s cubic-bezier(.2,.8,.3,1), opacity .18s; }

/* Tapped: it pops out of the board so he can see which one he has hold of. */
.item.is-selected {
  border-color: var(--gold);
  box-shadow: 0 10px 30px rgba(0,0,0,.5), 0 0 0 1px rgba(201,154,59,.35);
  transform: scale(1.05);
  transition: transform .14s cubic-bezier(.2,.9,.3,1.3), box-shadow .14s;
  z-index: 2;
}

/* Held between two fingers: no transition, or it would lag behind them. */
.item.is-pinching {
  transition: none;
  transform: none;
  z-index: 6;
  border-color: var(--gold);
  box-shadow: 0 18px 50px rgba(0,0,0,.55);
}

/* Being typed into. Same bubble, no writing screen: the caret is simply in it. */
.item.is-editing {
  border-color: var(--gold);
  background: rgba(242,239,233,.09);
  caret-color: var(--gold);
  transform: none;
  z-index: 4;
}
.item.is-editing:empty::before {
  content: '';
  display: inline-block;
  width: 1px; height: calc(17px * var(--s));
}
.item.is-gone { transition: transform .26s ease-in, opacity .26s ease-in; opacity: 0; }

/* Past items read as past tense: dimmed, done struck through, dropped just faded. */
.board--flow .item { position: static; animation: none; max-width: 100%; }
.item.is-past { background: none; border-color: rgba(242,239,233,.07); color: var(--dim); }
.item.is-past.is-done { text-decoration: line-through; text-decoration-color: rgba(242,239,233,.3); }

.empty {
  position: fixed; left: 0; right: 0; top: 42%;
  margin: 0; text-align: center; font-size: 15px; color: rgba(242,239,233,.25);
  pointer-events: none;
}

/* ── launcher ─────────────────────────────────────────────────────────────── */
.bubble {
  position: fixed; left: 50%; bottom: calc(var(--safe-b) + 26px);
  width: 64px; height: 64px; margin-left: -32px;
  display: grid; place-items: center;
  font: 300 30px/1 system-ui; color: rgba(11,11,12,.75);
  background: var(--gold); border: 0; border-radius: 50%;
  box-shadow: 0 8px 30px rgba(201,154,59,.28);
  touch-action: none; z-index: 20;
}
.bubble.is-settling { transition: transform .2s cubic-bezier(.2,.8,.3,1); }
.bubble.is-carrying { box-shadow: 0 14px 44px rgba(201,154,59,.45); }

/* ── toast ────────────────────────────────────────────────────────────────── */
.toast {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(var(--safe-b) + 104px); z-index: 30;
  display: flex; align-items: center; gap: 14px;
  padding: 10px 16px; font-size: 14px; color: var(--dim);
  background: #16161a; border: 1px solid var(--line); border-radius: 999px;
}
.toast__undo { font: inherit; color: var(--gold); background: none; border: 0; padding: 0; }

@media (prefers-reduced-motion: reduce) {
  .item { animation: none; }
}

/* ── portrait lock ────────────────────────────────────────────────────────
   The board never rotates. Bubbles are stored as fractions of the board, so a rotation
   reshapes the canvas under all of them at once and the ones low down land past the short
   landscape edge — which is exactly how they went missing. Android takes the manifest's
   `orientation: portrait`; iOS gives a web app no orientation lock at all, so the page is
   counter-rotated instead. The layout box below is the SAME portrait box either way
   (width = viewport height, height = viewport width), so nothing reflows and no bubble
   moves a pixel: only the direction the board faces changes. */
html.is-spun body {
  inset: auto; left: 0; top: 0;
  width: var(--vh); height: var(--vw);
  transform-origin: 0 0;
}
html.is-spun-cw body { transform: translateX(var(--vw)) rotate(90deg); }
html.is-spun-ccw body { transform: translateY(var(--vh)) rotate(-90deg); }
