/* ============================================================================
   LabSpace Mobile — phone UI
   ----------------------------------------------------------------------------
   Brand colours come from ../shared/design/tokens.css, loaded first by
   index.html and shared with the web app. The :root block below maps those
   tokens onto the short local names the rest of this sheet uses, and keeps a
   literal fallback so the app still looks right if the shared file is missing
   (a stale service-worker cache, an offline first run).
   ========================================================================== */

:root{
  /* mapped from the shared brand tokens, with literal fallbacks */
  --accent:      var(--ls-aqua,       #2f6df0);
  --accent-ink:  var(--ls-aqua-dark,  #1b4fc4);
  --accent-soft: var(--ls-aqua-soft,  rgba(47,109,240,.12));
  --bg:          var(--ls-l-bg,       #eef1f6);
  --card:        var(--ls-l-card,     #ffffff);
  --card-2:      var(--ls-l-card-2,   #f5f7fb);
  --ink:         var(--ls-l-ink,      #131a2b);
  --ink-soft:    var(--ls-l-ink-soft, #3a465e);
  --muted:       var(--ls-l-muted,    #7683a0);
  --line:        var(--ls-l-line,     #e4e9f1);
  --line-soft:   #eef1f6;
  --ok:          var(--ls-ok,   #0c9a89);
  --warn:        var(--ls-warn, #c9790a);
  --bad:         var(--ls-bad,  #d64545);
  --like:        var(--ls-like, #ff4d6d);
  --nav-h:56px;
  /* The floating dock's real footprint, so the scrolling body can clear it.
     46px button + 6px padding top and bottom + 1px border each side = 60,
     and it floats --dock-gap above the safe area. The padding used to be
     sized from --tab-h, which described the full-width tab bar this dock
     replaced — 4px of clearance, so the last row of a list sat tucked under
     it. That bar and its variable are gone now; measure from the dock. */
  --dock-h:60px; --dock-gap:12px;
  --dock-clear:calc(var(--dock-h) + var(--dock-gap) + var(--sab, 0px) + 16px);
  --sat:env(safe-area-inset-top); --sab:env(safe-area-inset-bottom);
  --font: var(--ls-font, -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",sans-serif);
}
@media (prefers-color-scheme:dark){:root{
  --accent:      var(--ls-aqua-light, #5fa0ff);
  --accent-ink:  #8fbcff;
  --accent-soft: rgba(95,160,255,.16);
  --bg:          var(--ls-d-bg,        #0b0e14);
  --card:        var(--ls-d-surface,   #141a24);
  --card-2:      var(--ls-d-surface-lo,#10151d);
  --ink:         var(--ls-d-ink,       #e9eef7);
  --ink-soft:    var(--ls-d-ink-soft,  #c2ccdb);
  --muted:       var(--ls-d-muted,     #8593ad);
  --line:        #222b39; --line-soft:#1a222e;
  --ok:#2fd0bb; --warn:#f2a83c; --bad:#ff6b6b; --like:#ff6b85;
}}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
/* The shell is a fixed viewport: exactly one thing scrolls, and it is .body.
   Without this the document itself can scroll — which is what happens when
   the search input takes focus and the on-screen keyboard shrinks the visual
   viewport: the browser scrolls the nearest thing it can to reveal the
   field, and with nothing pinned that is the whole app. The symptom is a
   swipe moving the page behind the list instead of the list. */
html,body{margin:0;height:100%;overflow:hidden}
body{background:#0b0e14;font-family:var(--font);color:var(--ink);overscroll-behavior:none}
button{font-family:inherit;cursor:pointer}
a{color:var(--accent-ink);text-decoration:none}

/* device frame (desktop preview only) */
.stage{min-height:100dvh;display:flex;align-items:center;justify-content:center;background:#0b0e14;
  background-image:radial-gradient(120% 80% at 50% -10%,#161c28,#0b0e14 70%);}
.device{position:relative;width:100%;max-width:430px;height:100dvh;background:var(--bg);overflow:hidden;
  display:flex;flex-direction:column}
/* The bezel is a *preview*: it shows a developer on a desktop what the app
   looks like on a phone. `min-width` alone cannot tell that screen apart from
   a tablet, so a tablet got the preview too — a phone-shaped app marooned in
   the middle of a big screen. `pointer:fine` is the honest question: a mouse
   means someone is previewing, a finger means someone is using it. */
@media (min-width:600px) and (pointer:fine){
  .device{height:90dvh;max-height:900px;border-radius:44px;border:11px solid #05070c;
    box-shadow:0 40px 90px rgba(0,0,0,.55),0 0 0 2px #1b2230}
}

/* screens */
.screen{position:absolute;inset:0;display:flex;flex-direction:column;background:var(--bg);
  overflow:hidden;
  opacity:0;visibility:hidden;transform:translateX(8px);transition:opacity .22s,transform .22s,visibility .22s}
.screen.on{opacity:1;visibility:visible;transform:none}

/* top nav */
.nav{flex:0 0 auto;padding-top:calc(var(--sat) + 8px);height:calc(var(--nav-h) + var(--sat));
  display:flex;align-items:center;gap:10px;padding-left:16px;padding-right:16px;
  background:var(--card);border-bottom:1px solid var(--line);position:relative;z-index:5}
.nav h1{font-size:19px;font-weight:700;letter-spacing:-.02em;margin:0;flex:1}
.nav .n-act{width:38px;height:38px;border-radius:11px;border:1px solid var(--line);background:var(--card-2);
  color:var(--ink);display:grid;place-items:center;font-size:16px}
.nav .n-act.primary{background:var(--accent);border-color:var(--accent);color:#fff}

/* scroll body */
/* `overscroll-behavior:contain` matters as much as the overflow: reaching the
   end of a long list must stop there, not hand the remaining swipe to
   whatever is behind it. */
.body{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;padding:16px 14px 0}
/* The clearance under the dock is an element, not padding.
   A scroll container's bottom padding is not reliably included in its
   scrollable height once the content overflows: the list would end at the
   dock, and the last row could only be read by over-scrolling, springing
   back the moment you let go. A block in the flow is always counted. */
.body::after{content:"";display:block;height:var(--dock-clear)}
.body::-webkit-scrollbar{width:0}

/* cards + lists */
.card{background:var(--card);border:1px solid var(--line);border-radius:16px;padding:15px;margin-bottom:12px}
.sec-t{font-size:12px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);
  margin:6px 4px 10px}
.row{display:flex;align-items:center;gap:12px}
/* `min-width:0` matters as much as the `flex:1`. A flex item defaults to
   min-width:auto, which refuses to shrink below its own content — so a spacer
   holding a long name or handle pushes the row wider than the phone instead of
   giving way, and whatever sits next to it is carried off the screen. */
.spacer{flex:1;min-width:0}
.muted{color:var(--muted)}
.pill{font-size:11px;font-weight:700;padding:3px 9px;border-radius:999px}
.pill.ok{background:rgba(12,154,137,.14);color:var(--ok)}
.pill.warn{background:rgba(201,121,10,.16);color:var(--warn)}
.pill.made{background:var(--accent-soft);color:var(--accent-ink)}
.pill.bad{background:rgba(214,69,69,.16);color:var(--bad)}
.maint-banner{background:rgba(214,69,69,.12);border:1px solid rgba(214,69,69,.4);color:var(--bad);
  border-radius:12px;padding:12px 14px;font-weight:600;font-size:13.5px;margin-bottom:12px}
.pill.processed{background:rgba(12,154,137,.14);color:var(--ok)}
.avatar{width:44px;height:44px;border-radius:50%;flex:0 0 auto;display:grid;place-items:center;
  color:#fff;font-weight:700;font-size:17px;background:linear-gradient(140deg,#4a86ff,#1852c8);background-size:cover;background-position:center}
.big{font-size:26px;font-weight:800;letter-spacing:-.02em}

/* stat tiles */
.tiles{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:14px}
.tile{border-radius:15px;padding:14px;color:#fff;position:relative;overflow:hidden}
.tile .k{font-size:11px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;opacity:.9}
.tile .v{font-size:24px;font-weight:800;margin-top:2px}
.tile .n{font-size:11px;opacity:.9;margin-top:2px}
.t-blue{background:linear-gradient(150deg,#4a86ff,#2559d6)}
.t-green{background:linear-gradient(150deg,#2bb583,#128a5a)}
.t-orange{background:linear-gradient(150deg,#ff9f43,#e07b1a)}
.t-purple{background:linear-gradient(150deg,#9b6bff,#6a3fd6)}

/* feed */
.compose{display:flex;flex-direction:column;gap:10px}
.compose textarea{width:100%;border:1px solid var(--line);border-radius:12px;background:var(--card-2);
  color:var(--ink);padding:12px;font-family:inherit;font-size:15px;resize:none;min-height:64px}
.post .p-head{display:flex;align-items:center;gap:10px;margin-bottom:8px}
.post .p-who{font-weight:700;font-size:14.5px;line-height:1.15}
.post .p-meta{font-size:11.5px;color:var(--muted)}
.post .p-text{font-size:14.5px;color:var(--ink-soft);line-height:1.5;margin:2px 0 10px}
.post .p-acts{display:flex;gap:18px;font-size:13px;color:var(--muted);font-weight:600;align-items:center}
.post .p-acts .a{display:flex;align-items:center;gap:5px;background:none;border:none;color:inherit;padding:4px 0}
.post .p-acts .a.liked{color:var(--like)}
.cmt{font-size:13px;color:var(--ink-soft);padding:7px 0;border-top:1px solid var(--line-soft)}
.cmt b{color:var(--ink)}
.cmt-form{display:flex;gap:8px;margin-top:8px}
.cmt-form input{flex:1;border:1px solid var(--line);border-radius:999px;background:var(--card-2);
  color:var(--ink);padding:8px 14px;font-size:13.5px;font-family:inherit}

/* list rows */
.lrow{display:flex;align-items:center;gap:12px;padding:12px 4px;border-bottom:1px solid var(--line-soft);
  min-width:0}
.lrow:last-child{border-bottom:none}
/* A name or handle is whatever length its owner chose, and a search result row
   also carries a Cite/Accept button. Truncate the text rather than let the row
   grow: the button is fixed-width and must stay reachable, and the name is
   still recognisable from its first few words. */
.lrow .li-t{font-size:14.5px;font-weight:600;line-height:1.2;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lrow .li-s{font-size:12px;color:var(--muted);margin-top:2px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Anything at the end of a row — a Cite button, an "In lab" pill — keeps its
   size; the text column is what gives way. */
.lrow>.btn,.lrow>.pill,.lrow>.citeb{flex:0 0 auto}
.lico{width:38px;height:38px;border-radius:11px;background:var(--card-2);border:1px solid var(--line);
  display:grid;place-items:center;font-size:17px;flex:0 0 auto}

/* buttons */
.btn{border:none;border-radius:13px;padding:13px 16px;font-size:15px;font-weight:700;
  background:var(--card-2);color:var(--ink);border:1px solid var(--line);width:100%}
.btn.primary{background:var(--accent);color:#fff;border-color:var(--accent);
  box-shadow:0 6px 18px var(--accent-soft)}
.btn.sm{padding:9px 14px;font-size:13px;width:auto}
.btn:active{transform:translateY(1px)}

/* auth */
.auth{position:absolute;inset:0;display:flex;flex-direction:column;background:var(--bg);
  padding:0 22px calc(var(--sab) + 24px);overflow-y:auto}
.auth .hero{padding-top:calc(var(--sat) + 44px);text-align:center;margin-bottom:26px}
.brand-mark{width:104px;height:104px;display:block;margin:0 auto 16px;border-radius:26px;
  box-shadow:0 18px 38px rgba(12,30,80,.42)}
.auth .logo{width:78px;height:78px;border-radius:22px;margin:0 auto 16px;display:grid;place-items:center;
  font-size:42px;background:radial-gradient(130% 130% at 30% 20%,#4a86ff,#123a86);
  box-shadow:0 16px 34px rgba(20,60,150,.4)}
.auth h2{font-size:26px;font-weight:800;letter-spacing:-.02em;margin:0}
.auth h2 span{color:var(--accent)}
.auth .tag{color:var(--muted);font-size:14px;margin-top:6px}
.seg{display:flex;background:var(--card-2);border:1px solid var(--line);border-radius:12px;padding:4px;margin-bottom:18px}
.seg button{flex:1;border:none;background:none;padding:10px;border-radius:9px;font-weight:700;font-size:14px;color:var(--muted)}
.seg button.on{background:var(--card);color:var(--ink);box-shadow:0 1px 3px rgba(0,0,0,.12)}
.field{margin-bottom:13px}
.field label{display:block;font-size:12px;font-weight:600;color:var(--muted);margin:0 2px 6px}
.field input{width:100%;border:1px solid var(--line);border-radius:12px;background:var(--card);
  color:var(--ink);padding:13px 14px;font-size:16px;font-family:inherit}
.field input:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.err{color:var(--bad);font-size:13px;margin:2px 2px 12px;min-height:16px}
.hint{text-align:center;color:var(--muted);font-size:12px;margin-top:16px;line-height:1.5}

/* misc */
.empty{text-align:center;color:var(--muted);font-size:14px;padding:40px 20px}
.loading{text-align:center;color:var(--muted);font-size:13px;padding:30px}
.spin{width:26px;height:26px;border:3px solid var(--line);border-top-color:var(--accent);
  border-radius:50%;animation:sp .8s linear infinite;margin:0 auto 10px}
@keyframes sp{to{transform:rotate(360deg)}}
.hidden{display:none!important}
.chipset{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
.logout-btn{color:var(--bad);border-color:color-mix(in srgb,var(--bad) 40%,var(--line));
  background:color-mix(in srgb,var(--bad) 8%,var(--card))}
.nav-signout{height:34px;padding:0 14px;border-radius:10px;font-size:13px;font-weight:700;
  border:1px solid color-mix(in srgb,var(--bad) 40%,var(--line));
  background:color-mix(in srgb,var(--bad) 10%,var(--card));color:var(--bad)}

/* profile (instagram-style) */
.pf-head{display:flex;align-items:center;gap:14px;padding:4px 4px 14px}
.pf-id{flex:1;min-width:0}
.pf-name{font-size:22px;font-weight:800;letter-spacing:-.02em;line-height:1.1}
.pf-handle{color:var(--muted);font-size:14px;margin-top:2px}
.pf-desig{font-size:13px;color:var(--ink-soft);margin-top:6px}
.pf-exp{font-size:12.5px;color:var(--muted);margin-top:2px}
.pf-av{flex:0 0 auto}
.pf-av .avatar{width:86px;height:86px;font-size:32px;box-shadow:0 6px 18px rgba(0,0,0,.18)}
.pf-stats{display:flex;background:var(--card);border:1px solid var(--line);border-radius:16px;
  overflow:hidden;margin-bottom:14px}
.pf-stat{flex:1;border:none;background:none;padding:14px 6px;text-align:center;position:relative;color:var(--ink)}
.pf-stat + .pf-stat{border-left:1px solid var(--line-soft)}
.pf-stat.on::after{content:"";position:absolute;left:16%;right:16%;bottom:0;height:3px;
  background:var(--accent);border-radius:3px 3px 0 0}
.pf-n{font-size:20px;font-weight:800;letter-spacing:-.02em}
.pf-stat.on .pf-n{color:var(--accent)}
.pf-l{font-size:11.5px;color:var(--muted);font-weight:600;margin-top:1px}

/* composer bar */
.compose-bar{display:flex;align-items:center;gap:8px;margin-top:2px}
.icobtn{width:40px;height:38px;border-radius:11px;border:1px solid var(--line);background:var(--card-2);
  font-size:18px;display:grid;place-items:center}
.vis-seg{display:flex;background:var(--card-2);border:1px solid var(--line);border-radius:11px;padding:3px;gap:2px}
.vis-seg button{border:none;background:none;padding:6px 10px;border-radius:8px;font-size:12px;font-weight:700;color:var(--muted)}
.vis-seg button.on{background:var(--card);color:var(--ink);box-shadow:0 1px 2px rgba(0,0,0,.12)}
.post-prev{position:relative;margin-top:4px}
/* The composer preview must never crop: it is showing the square that was just
   framed, and cutting it here would put the guesswork straight back. `contain`
   keeps the whole of it inside the height cap. */
.post-prev img{width:100%;border-radius:12px;display:block;max-height:260px;object-fit:contain}
.prev-x{position:absolute;top:8px;right:8px;width:28px;height:28px;border-radius:50%;border:none;
  background:rgba(0,0,0,.6);color:#fff;font-size:14px}
.vis-badge{font-size:10.5px;font-weight:700;padding:3px 8px;border-radius:999px;flex:0 0 auto;align-self:flex-start}
.vis-badge.pub{background:var(--accent-soft);color:var(--accent-ink)}
.vis-badge.lab{background:var(--card-2);color:var(--muted);border:1px solid var(--line)}
.p-head{align-items:flex-start}

/* lab hub */
.hub{display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px;margin-bottom:12px}
.hub-tile{border:1px solid var(--line);background:var(--card);border-radius:16px;padding:14px 8px;
  display:flex;flex-direction:column;align-items:center;gap:5px;color:var(--ink)}
.hub-ic{font-size:24px}
.hub-l{font-size:12px;font-weight:700;color:var(--ink-soft)}
.hub-n{font-size:17px;font-weight:800;color:var(--accent)}
.scopebar{display:flex;align-items:center;gap:8px;padding:2px 4px 12px;font-size:13.5px}
.scopebar b{color:var(--ink)}

/* full-screen sheet */
.sheet{position:absolute;inset:0;background:var(--bg);z-index:10;display:flex;flex-direction:column;
  animation:slideup .22s ease}
@keyframes slideup{from{transform:translateY(14px);opacity:.4}to{transform:none;opacity:1}}
.labopt{width:100%;display:flex;align-items:center;gap:10px;background:none;border:none;text-align:left;
  padding:12px 8px;border-bottom:1px solid var(--line-soft);color:var(--ink)}
.labopt:last-child{border-bottom:none}
.labopt.on{background:var(--accent-soft);border-radius:10px}
.labopt .chk{color:var(--accent);font-weight:800;font-size:18px}
.eqrow{width:100%;background:none;border:none;text-align:left;color:var(--ink);border-bottom:1px solid var(--line-soft)}
.eqrow:last-child{border-bottom:none}
.lrow .li-t,.eqrow .li-t{color:var(--ink)}
.ev-dot{width:10px;height:10px;border-radius:50%;flex:0 0 auto}
.fin{width:100%;border:1px solid var(--line);border-radius:11px;background:var(--card-2);color:var(--ink);
  padding:11px 12px;font-size:15px;font-family:inherit;margin-bottom:9px}
.frow{display:flex;gap:8px}.frow .fin{flex:1}

/* calendar */
.cal-head{display:flex;align-items:center;justify-content:space-between;padding:2px 4px 10px;font-size:16px;font-weight:700}
.calnav{width:36px;height:36px;border-radius:10px;border:1px solid var(--line);background:var(--card);color:var(--ink);font-size:18px}
.cal-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:3px;margin-bottom:6px}
.cal-w{text-align:center;font-size:11px;font-weight:700;color:var(--muted);padding:4px 0}
.cal-day{aspect-ratio:1;border:1px solid var(--line-soft);background:var(--card);border-radius:10px;
  font-size:13px;font-weight:600;color:var(--ink);position:relative;display:flex;flex-direction:column;
  align-items:center;justify-content:center;padding-top:2px}
.cal-day.today{border-color:var(--accent);color:var(--accent)}
.cal-day.on{background:var(--accent);color:#fff}
.cal-dots{display:flex;gap:2px;height:6px;margin-top:2px}
.cal-dots i{width:5px;height:5px;border-radius:50%;display:inline-block}

/* Server picker on the sign-in screen — the phone app and the API are separate
   projects, so it must be possible to say where the API actually is. */
.linkbtn{display:block;margin:14px auto 0;background:none;border:none;color:var(--muted);
  font-size:12px;padding:8px 12px;border-radius:8px}
.linkbtn:active{background:var(--card-2)}


/* ── Feed parity with web: FB cards, comment bubbles, composer ──────────── */
.post.fb .p-head { align-items: center; }
.p-own { display: flex; gap: 2px; }
.p-ico { border: none; background: none; cursor: pointer; font-size: 15px; padding: 4px 6px;
  border-radius: 8px; color: var(--muted); }
.p-ico:active { background: var(--card-2); }
.p-ico.danger { color: var(--bad, #d64545); }
.vis-badge { font-size: 11px; }
/* Show the photo at its own shape — the stored file is already the final crop,
   so nothing needs fitting. A fixed frame is what produced black bars on every
   photo that was not that shape. */
.p-media { width: 100%; border-radius: 12px; margin: 2px 0 10px; display: block;
  height: auto; background: #000; }
/* Video keeps its own shape — there is no cropper in front of it. */
video.p-media { aspect-ratio: auto; max-height: 70vh; object-fit: contain; }
.p-acts { border-top: 1px solid var(--line-soft); border-bottom: 1px solid var(--line-soft);
  padding: 6px 0; margin: 4px 0; justify-content: space-around; }
.p-acts .a { font-size: 13.5px; }

.p-edit { display: flex; flex-direction: column; gap: 8px; margin: 6px 0; }
.p-edit-t { width: 100%; box-sizing: border-box; border: 1px solid var(--line); border-radius: 10px;
  background: var(--card-2); color: var(--ink); font: inherit; font-size: 14px; padding: 8px 10px; resize: none; }
.p-edit-r { display: flex; gap: 6px; justify-content: flex-end; }

.cmts { margin-top: 6px; display: flex; flex-direction: column; gap: 8px; }
.cmt { display: flex; align-items: flex-start; gap: 8px; border: none; padding: 0; }
.avatar.sm { width: 30px; height: 30px; font-size: 13px; flex: 0 0 auto; }
.cmt-b { background: var(--card-2); border-radius: 14px; padding: 7px 12px; min-width: 0; flex: 1; }
.cmt-w { font-weight: 700; font-size: 12.5px; }
.cmt-t { font-size: 13.5px; color: var(--ink-soft); word-wrap: break-word; }
.cmt-a { font-size: 11px; color: var(--muted); align-self: center; }
.cmt-del { border: none; background: none; color: var(--muted); font-size: 15px; cursor: pointer;
  padding: 2px 6px; align-self: center; }

.cbox { position: relative; display: flex; align-items: center; gap: 6px; margin-top: 4px; }
.cbox-t { flex: 1; border: 1px solid var(--line); border-radius: 999px; background: var(--card-2);
  color: var(--ink); font: inherit; font-size: 13.5px; padding: 8px 12px; min-width: 0; }
.cbox-e, .cbox-s { border: none; background: none; cursor: pointer; font-size: 17px; padding: 6px; }
.cbox-s { color: var(--accent); font-size: 15px; }
.cbox-menu { position: absolute; left: 0; bottom: calc(100% + 4px); z-index: 30; min-width: 200px;
  background: var(--card); border: 1px solid var(--line); border-radius: 12px;
  box-shadow: 0 12px 30px rgba(0,0,0,.25); overflow: hidden; }
.cbox-menu .men { display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
  border: none; background: none; padding: 8px 10px; font: inherit; font-size: 13px; color: var(--ink); }
.cbox-menu .men:active { background: var(--card-2); }
.cbox-menu .men small { color: var(--muted); }
.cbox-tray { position: absolute; right: 0; bottom: calc(100% + 4px); z-index: 30; width: 240px;
  display: flex; flex-wrap: wrap; gap: 2px; padding: 8px; max-height: 160px; overflow-y: auto;
  background: var(--card); border: 1px solid var(--line); border-radius: 12px;
  box-shadow: 0 12px 30px rgba(0,0,0,.25); }
.cbox-tray .emo { border: none; background: none; font-size: 20px; padding: 4px; cursor: pointer; }
.hidden { display: none !important; }

.btn.danger{color:#ffd9d6;background:linear-gradient(#8d3a34,#6d2b26);border-color:#4c1f1b}


/* ══ Instagram-style shell: global top bar + floating dock ═════════════════ */
.topbar { position: absolute; top: 0; left: 0; right: 0; z-index: 8;
  height: calc(var(--nav-h, 52px) + var(--sat, 0px)); padding-top: var(--sat, 0px);
  display: flex; align-items: center; gap: 8px; padding-left: 10px; padding-right: 10px;
  background: color-mix(in srgb, var(--bg) 86%, transparent);
  backdrop-filter: saturate(1.4) blur(12px); border-bottom: 1px solid var(--line-soft); }
.topbar.hidden { display: none; }
.tb-ic { width: 40px; height: 40px; border: none; background: none; border-radius: 12px;
  display: grid; place-items: center; color: var(--ink); position: relative; cursor: pointer; }
.tb-ic svg { width: 24px; height: 24px; fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round; }
.tb-ic:active { background: var(--card-2); }
.tb-switch { flex: 1; display: flex; align-items: center; justify-content: center; gap: 6px;
  border: none; background: none; cursor: pointer; font-size: 16px; font-weight: 800;
  color: var(--ink); letter-spacing: -.01em; }
.tb-switch.static { pointer-events: none; }
.tb-chev { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2.2;
  stroke-linecap: round; stroke-linejoin: round; opacity: .7; }
.tb-flask .tb-badge { position: absolute; top: 4px; right: 4px; min-width: 16px; height: 16px;
  padding: 0 4px; border-radius: 8px; background: var(--bad, #d64545); color: #fff; font-size: 10px;
  font-weight: 800; display: grid; place-items: center; }
.tb-badge.hidden { display: none; }

/* Only feed & search sit under the global top bar. */
#s-feed, #s-search { padding-top: calc(var(--nav-h, 52px) + var(--sat, 0px)); }
#s-feed .body, #s-search .body { padding-top: 12px; }

/* Floating dock */
.dock { position: absolute; left: 50%; transform: translateX(-50%);
  bottom: calc(var(--sab, 0px) + var(--dock-gap)); z-index: 9;
  display: flex; align-items: center; gap: 4px; padding: 6px;
  background: color-mix(in srgb, var(--card) 92%, transparent);
  border: 1px solid var(--line); border-radius: 999px;
  box-shadow: 0 10px 30px rgba(0,0,0,.28); backdrop-filter: blur(12px); }
.dock.hidden { display: none; }
.dtab { width: 46px; height: 46px; border: none; background: none; border-radius: 50%;
  display: grid; place-items: center; color: var(--muted); cursor: pointer; }
.dtab svg { width: 25px; height: 25px; fill: none; stroke: currentColor; stroke-width: 1.9;
  stroke-linecap: round; stroke-linejoin: round; }
.dtab.on { color: var(--ink); background: var(--card-2); }
.dtab.lab-only.hidden { display: none; }
.dtab-me .dock-av { width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center;
  font-weight: 800; font-size: 13px; color: #fff; background-size: cover; background-position: center;
  background-color: var(--accent); box-shadow: 0 0 0 2px transparent; }
.dtab-me.on .dock-av { box-shadow: 0 0 0 2px var(--ink); }

/* Search screen */
/* The field stays put while the results scroll under it. On a phone the
   list is longer than the screen, and a search box that scrolls away is a
   search box you have to scroll back to in order to change the query.
   The negative margins let the blurred background span the body's padding,
   so rows do not show through at the edges as they pass beneath. */
.srch { position: sticky; top: 0; z-index: 3; margin: -16px -14px 0;
  padding: 12px 14px; background: color-mix(in srgb, var(--bg) 88%, transparent);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); }
.srch input { width: 100%; box-sizing: border-box; height: 40px; padding: 0 14px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--card-2); color: var(--ink); font-size: 15px; }
.srch input:focus { outline: none; border-color: var(--accent); }

/* Notification rows */
.nitem { align-items: flex-start; }
.nact { display: flex; gap: 6px; margin-top: 6px; }

/* ── Encrypted messages ──────────────────────────────────────────────────────
 * The one screen whose content the server never sees; everything below is
 * painted from text decrypted on this device.
 */

.chat-new { display: flex; gap: 8px; margin-bottom: 10px; }
.chat-new input { flex: 1; min-width: 0; }

.chat-row {
  display: grid;
  grid-template-columns: 1fr auto;
  width: 100%;
  gap: 0 8px;
  text-align: left;
  padding: 12px;
  margin-bottom: 6px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 14px;
  color: inherit;
  font: inherit;
}
.chat-row .when { grid-column: 1; font-size: .8rem; opacity: .6; }
.chat-row .badge {
  grid-column: 2; grid-row: 1 / span 2; align-self: center;
  min-width: 22px; padding: 2px 7px;
  background: var(--accent, #1b9c9c); color: #fff;
  border-radius: 999px; font-size: .78rem; text-align: center;
}

.chat-msgs {
  display: flex; flex-direction: column; gap: 8px;
  /* Room for the compose row and the dock underneath it. */
  max-height: calc(100vh - 260px);
  overflow-y: auto;
  padding: 4px 0;
}

.msg {
  max-width: 82%;
  align-self: flex-start;
  padding: 8px 12px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 16px;
}
.msg.mine { align-self: flex-end; background: var(--accent-soft, #d9f2f2); }
.msg.failed { background: transparent; border-style: dashed; border-color: #c0392b; color: #c0392b; }
.msg p { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; }
.msg time { display: block; margin-top: 3px; font-size: .7rem; opacity: .55; }
/* The one plain-text first message to someone with no chat key yet
   (apps/api/app/stores/chat_first.py): always marked as not encrypted. */
.msg.ls-plain { border: 1px dashed #c98a12; }
.plain-note { display: block; margin-top: 3px; font-size: .7rem; font-weight: 600; opacity: .85; }
.plain-explain { font-size: .78rem; color: var(--muted); margin: 10px 0 0; line-height: 1.45; }
.first-lead { margin: 0 0 10px; line-height: 1.45; }
#first-box { width: 100%; box-sizing: border-box; min-height: 90px; padding: 8px 10px; font: inherit;
  border-radius: 10px; border: 1px solid var(--line, #ccd); background: transparent; color: inherit; }
#first-send, #first-unsend { margin-top: 8px; display: block; margin-left: auto; }

.chat-compose { display: flex; gap: 8px; margin-top: 10px; }
.chat-compose input { flex: 1; min-width: 0; }

/* A thread's bar: 👥 members, ＋ add a lab member, ‹ Back. */
.chat-actions { display: flex; gap: 6px; flex: none; }
.chat-actions .pill { min-width: 40px; min-height: 34px; }
/* Who said it, in a group. */
.msg-from { display: block; margin-bottom: 2px; font-size: .74rem; color: var(--accent, #1b9c9c); }
/* The ＋ / 👥 sheet at the top of a thread. */
.chat-panel { margin-bottom: 10px; }
.chat-panel[hidden] { display: none; }
.chat-panel-head { display: flex; align-items: center; gap: 8px; }
.chat-panel-head b { flex: 1; min-width: 0; }
#chat-panel-note { font-size: .8rem; margin: 6px 0; line-height: 1.45; }
.chat-person { display: flex; align-items: center; gap: 10px; padding: 6px 0;
  border-bottom: 1px solid var(--line); }
.chat-person span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-person .btn { min-height: 36px; }
#chat-panel-list > .btn { margin-top: 10px; }

.recovery-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 1.05rem;
  letter-spacing: .06em;
  padding: 12px;
  margin: 10px 0;
  background: var(--card-2, rgba(0, 0, 0, .04));
  border: 1px dashed var(--line);
  border-radius: 10px;
  user-select: all;
  word-break: break-all;
}

.ack { display: flex; align-items: center; gap: 8px; margin: 10px 0; }
.recover { margin-top: 14px; }
.recover summary { cursor: pointer; opacity: .75; }
.fp {
  margin-top: 12px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .72rem;
  opacity: .55;
  word-break: break-all;
}
.err { color: #c0392b; font-size: .85rem; margin-top: 8px; }
.warn { color: #b8860b; }

/* ── Tablets and any other big touch screen ─────────────────────────────────
   Fill the screen instead of showing a phone-shaped app stranded in the
   middle of one. This block lives at the end of the sheet on purpose: a media
   query adds no specificity, so overriding .body / .tiles / .hub only works
   from below their own definitions. Moving it higher would silently do
   nothing, which is a nasty way to lose an afternoon.

   The chrome — background, top bar, dock — spans the full width; the
   scrolling column keeps a readable measure and centres, rather than dragging
   a 14px line of text across ten inches. The dock already centres itself and
   is sized by its contents, so it needs nothing here. */
@media (min-width:600px) and (pointer:coarse){
  .stage{background:var(--bg);background-image:none}
  .device{max-width:none;height:100dvh;border:none;border-radius:0;box-shadow:none}
  .body{max-width:760px;margin-inline:auto;width:100%;
    padding:20px 20px 0}
  .tiles{grid-template-columns:repeat(4,1fr)}
  .hub{grid-template-columns:repeat(3,1fr)}
}

/* ── Post carousel ─────────────────────────────────────────────────────────
   The swipe is the browser's: a snap-scroller, so no touch handler of ours
   competes with the feed's own vertical scroll. */
.p-carousel { position: relative; border-radius: 12px; overflow: hidden;
  margin: 2px 0 10px; background: #000; }
.pc-track { display: flex; overflow-x: auto; scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain; scrollbar-width: none;
  -webkit-overflow-scrolling: touch; }
.pc-track::-webkit-scrollbar { height: 0; }
.pc-shot { flex: 0 0 100%; width: 100%; height: auto; display: block;
  scroll-snap-align: center; }
.pc-count { position: absolute; top: 9px; right: 9px; background: rgba(0,0,0,.6);
  color: #fff; border-radius: 999px; padding: 2px 8px; font-size: 11px;
  font-weight: 700; pointer-events: none; }
.pc-dots { position: absolute; left: 0; right: 0; bottom: 8px; display: flex;
  justify-content: center; gap: 5px; pointer-events: none; }
.pc-dot { width: 5px; height: 5px; border-radius: 50%; background: rgba(255,255,255,.45);
  transition: background .15s, transform .15s; }
.pc-dot.on { background: #fff; transform: scale(1.3); }
.prev-n { position: absolute; left: 8px; bottom: 8px; background: rgba(0,0,0,.62);
  color: #fff; border-radius: 999px; padding: 3px 9px; font-size: 11px;
  font-weight: 700; }
.prev-n.hidden { display: none; }

/* ── To do, on the public feed ───────────────────────────────────────────────
   The web app gives this a rail; a phone gets a card that stays one line until
   you open it. The time field brings its own styles from /shared/ui. */
.td-card { padding: 0; overflow: hidden; }
.td-head { display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 12px 14px; border: none; background: none; color: var(--ink);
  font: inherit; font-weight: 600; text-align: left; cursor: pointer; }
.td-head .spacer { flex: 1; color: var(--muted); font-weight: 500;
  font-size: 13px; }
.td-ic { color: var(--accent); font-weight: 800; }
.td-chev { color: var(--muted); font-size: 17px; line-height: 1; }

.td-add { padding: 0 14px 12px; display: grid; gap: 8px; }
.td-add input[type="text"] { width: 100%; box-sizing: border-box;
  padding: 9px 10px; border: 1px solid var(--line); border-radius: 8px;
  background: var(--card-2); color: var(--ink); font: inherit; }
.td-add-row { display: flex; align-items: center; gap: 8px; }
.td-notime { display: flex; align-items: center; gap: 5px; color: var(--muted);
  font-size: 12px; }

.td-row { align-items: flex-start; }
.td-tick, .td-x { border: none; background: none; cursor: pointer;
  padding: 2px 4px; line-height: 1; }
.td-tick { color: var(--accent); font-size: 17px; }
.td-x { color: var(--muted); font-size: 17px; }
.td-done .li-t { text-decoration: line-through; color: var(--muted); }
.td-late { color: var(--ls-bad, #d64545); font-weight: 600; }
.td-put { color: var(--ls-warn, #c9790a); font-size: 11px; font-weight: 700; }
.td-empty { padding: 4px 14px 14px; color: var(--muted); font-size: 13px; }

/* A card that has come due. Tinted, because it is the one thing here that is
   asking for an answer rather than reporting one. */
.td-due { margin: 0 14px 12px; padding: 11px 12px; border-radius: 10px;
  background: var(--accent-soft); border: 1px solid var(--accent); }
.td-due-t { font-weight: 600; margin-bottom: 9px; }
.td-acts, .td-pick { display: flex; flex-wrap: wrap; gap: 6px; }
.td-pick { margin-top: 9px; align-items: center; }
.td-pick-l { width: 100%; color: var(--muted); font-size: 12px; }

/* ── Papers: which shelf ─────────────────────────────────────────────────────
   Your own library and the lab's shared shelf are two different places, so the
   tab says which one you are looking at rather than showing one and calling it
   the other. */
.shelf-tabs { display: flex; gap: 6px; padding: 12px 14px 0; }
.shelf-tab { flex: 1; padding: 8px 0; border: 1px solid var(--line);
  border-radius: 9px; background: var(--card); color: var(--muted);
  font: inherit; font-size: 13px; font-weight: 600; cursor: pointer; }
.shelf-tab.on { background: var(--accent-soft); border-color: var(--accent);
  color: var(--ink); }

/* ── Compose tools: a symbol, not a button ───────────────────────────────────
   A row of filled pills under an empty box reads as things you have to press
   before writing anything. The symbol alone is the affordance, and it takes a
   ground only while it is being touched. */
.ctool { border: none; background: none; cursor: pointer; padding: 7px 9px;
  border-radius: 10px; font-size: 18px; line-height: 1; color: var(--ink-soft);
  -webkit-tap-highlight-color: transparent; }
.ctool:active { background: var(--card-2); transform: scale(.92); }

/* Emoji the sentence suggests, offered while you write. */
.c-suggest { display: flex; flex-wrap: wrap; align-items: center; gap: 5px;
  padding: 8px 12px 0; }
.c-suggest.hidden { display: none; }
.c-suggest-l { color: var(--muted); font-size: 10.5px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .4px; }
.c-sugg { border: 1px solid var(--line); background: var(--card-2);
  border-radius: 9px; cursor: pointer; font-size: 17px; line-height: 1;
  padding: 5px 8px; }
.c-sugg:active { border-color: var(--accent); transform: scale(.94); }

/* ── A mention inside the text ───────────────────────────────────────────────
   The word you typed is the link. It used to be listed twice — as plain words
   inline, and again as a pill row underneath — so the same fact sat in two
   places and the half you wrote was not tappable. Colour is the only marker,
   so a sentence still reads as a sentence. */
.mention { color: var(--accent); font-weight: 600; text-decoration: none; }
.mention-lab { color: var(--ok); }

/* ── Who liked it ────────────────────────────────────────────────────────────
   Before this, the only place a like had a name on it was your own
   notifications, which cover your own posts and nobody else's. */
.p-acts .a.who { font-size: 12px; color: var(--muted); font-weight: 600; }
.liker-row { width: 100%; border: none; background: none; font: inherit;
  color: inherit; text-align: left; cursor: pointer; }
.liker-row:active { background: var(--card-2); }

/* ── Sketcher ────────────────────────────────────────────────────────────────
   The desktop has the full toolbox; a phone gets the two things it is good at:
   pick a generated structure, then draw on it with a finger. */
.sk-bar { display: flex; align-items: center; gap: 8px; padding: 10px 14px; }
.sk-bar .ctool.on { background: var(--accent-soft); color: var(--ink); }
.sk-colour { width: 34px; height: 28px; padding: 0; border: 1px solid var(--line);
  border-radius: 7px; background: none; }
/* White whatever the theme is — a figure from here goes into a paper. */
.sk-canvas { display: block; width: calc(100% - 28px); margin: 0 14px;
  height: auto; background: #fff; border: 1px solid var(--line);
  border-radius: 10px; touch-action: none; }
/* Paging through a sketch with more than one slide (an imported deck). */
.sk-slides { display: flex; align-items: center; gap: 10px; padding: 8px 14px 0; }
.sk-slides[hidden] { display: none; }
.sk-slides > span { flex: 1; min-width: 0; text-align: center; font-size: 13px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sk-slides .btn { min-width: 44px; }
.sk-row { display: flex; align-items: center; gap: 10px; padding: 4px 14px;
  color: var(--muted); font-size: 12px; }
.sk-row > span { width: 54px; flex: none; }
.sk-row input[type="range"] { flex: 1; min-width: 0; }
.sk-suggest { display: grid; gap: 8px; padding: 10px 14px 0; }
.sk-option { display: block; width: 100%; padding: 0; cursor: pointer;
  border: 1px solid var(--line); border-radius: 10px; background: var(--card-2);
  overflow: hidden; text-align: left; }
.sk-option:active { border-color: var(--accent); }
.sk-option svg { display: block; width: 100%; height: 76px; }
.sk-option-n { display: block; padding: 6px 9px; font-size: 11px;
  color: var(--muted); }
.sk-swatches { display: flex; flex-wrap: wrap; gap: 5px; padding: 10px 14px 0; }
.sk-swatch { width: 26px; height: 26px; padding: 0; border: 1px solid var(--line);
  border-radius: 7px; cursor: pointer; }
.sk-swatch:active { border-color: var(--accent); transform: scale(1.1); }
.sk-row > b { width: 32px; flex: none; text-align: right;
  font-variant-numeric: tabular-nums; color: var(--ink); }

/* ── Web workspace parity ──────────────────────────────────────────────────
   Mobile keeps touch-first navigation, but uses the same graphite chrome,
   neon-blue accent, compact geometry and branded mark as the web workspace. */
:root {
  color-scheme: dark;
  --accent: var(--ls-aqua, #3d81f6);
  --accent-ink: var(--ls-aqua-light, #a9ccff);
  --accent-soft: rgba(61,129,246,.16);
  --bg: var(--ls-d-bg, #0c0d0f);
  --card: var(--ls-d-surface, #212227);
  --card-2: var(--ls-d-surface-lo, #191a1d);
  --ink: var(--ls-d-ink, #eceef2);
  --ink-soft: var(--ls-d-ink-soft, #b7bcc6);
  --muted: var(--ls-d-muted, #7e8590);
  --line: var(--ls-d-line, #3a3d44);
  --line-soft: var(--ls-d-hairline, rgba(255,255,255,.06));
  --nav-h: 56px;
  --dock-h: 70px;
  --dock-gap: 0px;
}

body, .stage { background: var(--bg); }
.stage { background-image: radial-gradient(120% 65% at 50% 0,#1a1c20,#101114 58%,#0b0c0e); }
.device { background: var(--bg); }

.topbar {
  gap: 8px;
  padding-left: 12px;
  padding-right: 10px;
  background: linear-gradient(var(--ls-metal-top,#4a4d54),var(--ls-metal-mid,#303237) 52%,var(--ls-metal-lo,#232529));
  border-bottom: 1px solid #000;
  box-shadow: 0 1px 0 rgba(255,255,255,.10) inset,0 -1px 0 rgba(0,0,0,.6) inset;
  backdrop-filter: none;
}
.tb-brand { display:flex; align-items:center; gap:7px; flex:none; color:#eef1f6;
  font-size:13px; letter-spacing:.1px; text-shadow:0 -1px 0 #000; }
.tb-brand img { width:30px; height:30px; border-radius:7px; display:block;
  box-shadow:0 0 0 1px rgba(255,255,255,.12),0 2px 5px rgba(0,0,0,.45); }
.tb-brand b { color:var(--ls-aqua-light,#a9ccff); }
.tb-switch { min-width:0; justify-content:flex-start; font-size:13px; font-weight:700;
  color:#eef1f6; padding:0 4px; overflow:hidden; }
.tb-switch > span { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.tb-ic { color:#eef1f6; border-radius:8px; }
.tb-ic:active { background:rgba(0,0,0,.28); }

.body { padding:16px 14px 0; }
.card, .chat-row { border-radius:var(--ls-radius,9px);
  background:linear-gradient(var(--ls-d-surface-hi,#2b2d33),var(--ls-d-surface,#212227));
  border-color:#08090a;
  box-shadow:0 1px 0 rgba(255,255,255,.06) inset,0 5px 14px rgba(0,0,0,.35); }
.sec-t { color:var(--ink-soft); font-size:11px; letter-spacing:.09em; }
.nav { background:linear-gradient(var(--ls-metal-top,#4a4d54),var(--ls-metal-mid,#303237) 52%,var(--ls-metal-lo,#232529));
  border-bottom-color:#000; box-shadow:0 1px 0 rgba(255,255,255,.1) inset; }
.nav .n-act { border-color:#111; border-radius:8px;
  background:linear-gradient(#50535a,#2b2d32); box-shadow:0 1px 0 rgba(255,255,255,.12) inset; }

.btn { border-radius:999px; color:var(--ink); border-color:#0a0a0b;
  background:linear-gradient(#5a5e66,#3f4249 48%,#34363c 52%,#26282c);
  box-shadow:0 1px 0 rgba(255,255,255,.18) inset,0 1px 2px rgba(0,0,0,.5); }
.btn.primary { border-color:#0d3a8f;
  background:linear-gradient(#9fc6ff,var(--accent) 48%,var(--ls-aqua-dark,#1a5fd6) 52%,#114fbf);
  box-shadow:0 1px 0 rgba(255,255,255,.55) inset,0 0 12px rgba(61,129,246,.32); }
.field input, .compose textarea, .srch input, .td-add input[type="text"] {
  background:#141518; border-color:#000; color:var(--ink); border-radius:8px;
  box-shadow:0 2px 4px rgba(0,0,0,.55) inset,0 1px 0 rgba(255,255,255,.05); }
.field input:focus, .compose textarea:focus, .srch input:focus {
  outline:none; border-color:var(--accent); box-shadow:0 2px 4px rgba(0,0,0,.55) inset,0 0 0 3px rgba(61,129,246,.25); }

.dock { left:0; right:0; bottom:0; transform:none; width:100%; justify-content:space-around;
  gap:0; padding:6px 4px calc(5px + var(--sab)); border-radius:0; border:0;
  border-top:1px solid #000;
  background:linear-gradient(var(--ls-metal-hi,#3c3f45),var(--ls-metal-mid,#303237) 48%,var(--ls-metal-lo,#232529));
  box-shadow:0 -1px 0 rgba(255,255,255,.08),0 -8px 24px rgba(0,0,0,.35); backdrop-filter:none; }
.dtab { width:auto; min-width:48px; height:58px; flex:1; max-width:76px; border-radius:8px;
  display:flex; flex-direction:column; gap:3px; color:#9ca3af; }
.dtab::after { content:attr(aria-label); display:block; max-width:100%; overflow:hidden;
  text-overflow:ellipsis; font-size:9px; line-height:11px; font-weight:600; white-space:nowrap; }
.dtab svg { width:22px; height:22px; }
.dtab.on { color:#fff; background:rgba(0,0,0,.28); box-shadow:0 1px 0 rgba(255,255,255,.08) inset; }
.dtab.on svg { color:var(--ls-aqua-light,#a9ccff); filter:drop-shadow(0 0 5px rgba(61,129,246,.7)); }
.dtab-me .dock-av { width:24px; height:24px; font-size:11px; }
.dtab-me.on .dock-av { box-shadow:0 0 0 2px var(--ls-aqua-light,#a9ccff); }

.workspace-intro { display:flex; flex-direction:column; gap:4px; margin:2px 0 20px;
  padding:16px; border:1px solid #0d3a8f; border-radius:var(--ls-radius,9px);
  background:radial-gradient(120% 180% at 0 0,rgba(61,129,246,.26),rgba(25,26,29,.96) 66%);
  box-shadow:0 1px 0 rgba(255,255,255,.08) inset,0 8px 22px rgba(0,0,0,.34); }
.workspace-intro b { font-size:18px; color:var(--ink); }
.workspace-intro span { color:var(--ink-soft); font-size:12px; }
.workspace-grid { display:grid; grid-template-columns:1fr 1fr; gap:10px; margin-bottom:20px; }
.workspace-tool { min-width:0; min-height:112px; display:flex; flex-direction:column; align-items:flex-start;
  gap:5px; padding:14px; text-align:left; color:var(--ink); cursor:pointer;
  border:1px solid #08090a; border-radius:var(--ls-radius,9px);
  background:linear-gradient(var(--ls-d-surface-hi,#2b2d33),var(--ls-d-surface,#212227));
  box-shadow:0 1px 0 rgba(255,255,255,.07) inset,0 5px 14px rgba(0,0,0,.32); }
.workspace-tool:active { border-color:var(--accent); transform:translateY(1px); }
.workspace-tool > span { display:grid; place-items:center; width:30px; height:30px; margin-bottom:2px;
  border-radius:8px; color:var(--ls-aqua-light,#a9ccff); background:rgba(61,129,246,.14);
  font-size:18px; box-shadow:0 0 12px rgba(61,129,246,.12); }
.workspace-tool b { font-size:13px; }
.workspace-tool small { color:var(--muted); font-size:10px; line-height:1.35; }
.workspace-tool.wide { grid-column:1 / -1; min-height:94px; }
.radar-topics { display:grid; gap:10px; }
.radar-topics > div { display:flex; flex-wrap:wrap; gap:6px; }
.radar-mobile-row { align-items:flex-start; }
.radar-mobile-row .li-t { white-space:normal; line-height:1.35; }
.radar-topic { display:inline-block; margin-top:6px; padding:2px 7px; border-radius:999px;
  color:var(--ls-aqua-light,#a9ccff); background:rgba(61,129,246,.14); font-size:10px; }

.auth { background:radial-gradient(120% 65% at 50% 0,#1a1c20,#101114 58%,#0b0c0e); }
.auth .hero { padding-top:calc(var(--sat) + 34px); margin-bottom:22px; }
.brand-mark { width:92px; height:92px; border-radius:22px; margin-bottom:14px;
  box-shadow:0 0 0 1px rgba(169,204,255,.4),0 14px 40px rgba(35,104,225,.28); }
.auth h2 { color:var(--ink); text-shadow:0 0 22px rgba(61,129,246,.22); }
.seg { border-color:#000; border-radius:999px; background:#141518; box-shadow:0 2px 5px rgba(0,0,0,.5) inset; }
.seg button { border-radius:999px; }
.seg button.on { color:#fff; background:linear-gradient(var(--ls-aqua-light,#a9ccff),var(--accent) 48%,var(--ls-aqua-dark,#1a5fd6) 52%,#114fbf);
  box-shadow:0 1px 0 rgba(255,255,255,.45) inset,0 2px 6px rgba(0,0,0,.45); }

@media (max-width:370px) {
  .tb-brand > span { display:none; }
  .dtab::after { font-size:8px; }
}

/* MarketSpace sheets (views/sheets.js market*) */
.mk-row{width:100%;text-align:left;background:none;border:0;color:inherit;font:inherit;cursor:pointer}
.mk-th{width:52px;height:42px;border-radius:9px;object-fit:contain;background:var(--card-2);border:1px solid var(--line);flex:none}
.mk-price{font-weight:700;margin-top:3px}.mk-price small{font-weight:500;color:var(--muted)}
.mk-hero{width:100%;max-height:240px;object-fit:contain;border-radius:14px;background:var(--card-2);margin-bottom:10px}

/* ── Reading a paper (views/reader.js) ───────────────────────────────────── */
.lrow[data-open]{cursor:pointer}
.rd{position:fixed;inset:0;z-index:300;display:flex;flex-direction:column;background:var(--bg, #0c0d0f)}
.rd-bar{display:flex;align-items:center;gap:8px;padding:8px 10px;padding-top:max(8px, env(safe-area-inset-top));
  background:var(--card, #1b1d22);border-bottom:1px solid var(--line-soft, #2a2d33)}
.rd-bar button{flex:none;min-width:40px;height:40px;border:1px solid var(--line-soft, #2a2d33);border-radius:10px;
  background:none;color:inherit;font-size:20px;line-height:1}
.rd-title{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px}
.rd-page{flex:none;font-size:12px;opacity:.75;font-variant-numeric:tabular-nums}
.rd-pages{flex:1;min-height:0;overflow:auto;-webkit-overflow-scrolling:touch;padding:8px 6px calc(16px + env(safe-area-inset-bottom));
  --rd-zoom:1}
.rd-sheet{width:calc(100% * var(--rd-zoom));margin:0 auto 8px;background:#fff;border-radius:2px;
  box-shadow:0 1px 6px #0004;position:relative}
.rd-sheet canvas{display:block;width:100%;height:100%}
.rd-msg{padding:28px 16px;text-align:center;opacity:.8;line-height:1.5}

/* "New message" bar: slides up above the tab dock, hides itself after a while. */
.msg-bar{position:fixed;left:12px;right:12px;bottom:calc(76px + env(safe-area-inset-bottom));z-index:60;
  display:flex;align-items:center;gap:10px;padding:11px 14px;border-radius:14px;border:1px solid var(--line);
  background:var(--card);color:var(--ink);text-align:left;font:inherit;box-shadow:0 10px 28px rgba(0,0,0,.28);
  transform:translateY(140%);opacity:0;pointer-events:none;transition:transform .28s cubic-bezier(.2,.8,.3,1),opacity .2s}
.msg-bar.on{transform:none;opacity:1;pointer-events:auto}
.msg-bar b{display:block;font-size:14px}
.msg-bar small{display:block;color:var(--muted);font-size:12px;margin-top:2px}
.msg-bar-dot{width:9px;height:9px;border-radius:50%;flex:none;background:#4ad07a;box-shadow:0 0 6px rgba(74,208,122,.7)}
@media (prefers-reduced-motion:reduce){.msg-bar{transition:none}}

/* Chat: files about to be sent, and the attach button. */
#attach-tray { padding-top: 8px; }
.chat-compose .lsf-add { width: 40px; height: 40px; min-width: 40px; }

/* Forgot password (index.html #reset-step): it takes the sign-in card's place. */
.auth.resetting > :not(.hero):not(#reset-step) { display: none !important; }
#reset-step { display: flex; flex-direction: column; }
#reset-step.hidden { display: none; }

/* Audience feedback from live presentations (views/sheets.js showLiveFeedback). */
.live-fb { margin: 10px 14px; }
.live-fb-fig { position: relative; margin: 8px 0; border-radius: 8px; overflow: hidden; background: #fff; }
.live-fb-fig img { display: block; width: 100%; }
.live-fb-fig svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.live-fb-note { padding: 8px 0; border-top: 1px solid var(--line); }
.live-fb-note p { margin: 2px 0 0; white-space: pre-wrap; }

/* Calendar: who a reminder is for (js/views/sheets.js). */
.ev-people { display: flex; flex-direction: column; gap: 4px; max-height: 160px; overflow-y: auto;
  margin: 6px 0; padding: 6px 8px; border: 1px solid var(--line, #d9dee7); border-radius: 10px; }
.ev-person { display: flex; align-items: center; gap: 8px; font-size: 14px; }
