.pp-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding-top: 4px;
}
.pp-body .stratum-section-label {
  margin-top: 6px;
}
.pp-hint {
  margin: 0;
  font-size: 13px;
  color: var(--ink-3);
}

/* Desktop: as wide as the composer it opens over (the shell docks it to the main column, as a
   session's bottom panels). */
@media (min-width: 768px) {
  .pp {
    --stratum-bottom-panel-max-width: calc(760px + 2 * 36px);
  }
}
/* Each page scrolls inside the shell's main area on desktop and in harmony builds, and scrolls the
 * document on vanilla mobile (AppShellLayout's native scroll mode - see index.css). overscroll-behavior
 * keeps a scroll that hits the top or bottom from chaining into the document, which in the AEA app's
 * browser would collapse its address bar anyway. */
.page {
  height: 100%;
  overflow-y: auto;
  overscroll-behavior: contain;
}
@media (max-width: 767px) {
  html:not(.harmony) .page {
    height: auto;
    overflow-y: visible;
  }
}

/* A page with a rail (e.g. FilterRail): side by side on desktop, the page alone on mobile, where
 * the rail hides itself. */
@media (min-width: 768px) {
  .page-with-rail {
    display: flex;
    height: 100%;
    overflow: hidden;
  }
  .page-with-rail-column {
    flex: 1;
    min-width: 0;
    height: 100%;
  }
}

/* Matches PageHeaderDesktop and PageHeaderMobile's own side padding, so content lines up with the
 * title above it. */
.page-content {
  padding: 16px 20px var(--stratum-app-shell-content-inset-bottom, 0px);
}
@media (min-width: 768px) {
  .page-content {
    padding: 16px 36px var(--stratum-app-shell-content-inset-bottom, 0px);
  }
}

.page-content section {
  margin-top: 24px;
}

.page-intro {
  margin: 0;
  font-size: 18px;
}

.page-label {
  margin: 0 0 8px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.page-content p {
  margin: 0 0 6px;
}
/* A new session's draft: where it starts, changeable until the first message. */
.new-session-draft {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  padding: 28px 0;
}
/* Desktop: in the thread's centered column, as a session's messages are, so it lines up with the
   composer below rather than the page's left edge. */
@media (min-width: 768px) {
  .new-session-draft {
    max-width: 760px;
    margin-inline: auto;
  }
}
.new-session-draft-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-3);
}
.new-session-draft-target {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  width: 100%;
  max-width: 480px;
  box-sizing: border-box;
  padding: 12px 40px 12px 14px;
  border: 1px solid var(--line-2);
  border-radius: 14px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: background-color 0.15s;
}
.new-session-draft-target:hover {
  background: var(--surface-2);
}
.new-session-draft-name {
  font-size: 16px;
  font-weight: 600;
  overflow-wrap: anywhere;
}
.new-session-draft-path {
  font-family: var(--mono);
  font-size: 12px;
  color: var(--ink-3);
  overflow-wrap: anywhere;
}
.new-session-draft-chevron {
  position: absolute;
  right: 14px;
  top: 50%;
  width: 16px;
  height: 16px;
  transform: translateY(-50%);
  stroke-width: 2;
  color: var(--ink-3);
}
.new-session-draft-hint {
  margin: 0;
  max-width: 480px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-3);
}

/* The header's folder: plain subtitle text that opens the picker, underlined on hover. */
.new-session-target-link {
  padding: 0;
  border: none;
  background: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
}
.new-session-target-link:hover {
  text-decoration: underline;
}

/* The draft's place while the hub says which hosts there are: the "Start in" card's size. */
.new-session-draft-skeleton {
  width: 100%;
  max-width: 480px;
}
/* Title in normal case at one size, like the tool panel's (ClaudeChatDemo.css). */
.tsk-title {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink);
}
.tsk-title-count {
  font-weight: 400;
  color: var(--ink-3);
}
.tsk-section {
  margin: 10px 0 2px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.tsk-section:first-child {
  margin-top: 0;
}

/* The task list, with launched tasks under their agent. Each row's vertical midpoint is where its
   connector meets it; nested lists make each line run from its own parent to its last child. */
.tsk-tree {
  --tsk-gap: 6px;
  --tsk-indent: 22px;
  --tsk-row-mid: 28px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  padding-bottom: 8px;
}
.tsk-tree > .stratum-button {
  align-self: center;
  margin-top: 6px;
}
.tsk-children {
  list-style: none;
  margin: 0;
  padding: 0;
}
.tsk-children .tsk-children {
  padding-left: var(--tsk-indent);
}
.tsk-branch {
  position: relative;
  padding-top: var(--tsk-gap);
}
.tsk-children .tsk-children > .tsk-branch::before {
  content: '';
  position: absolute;
  left: calc(var(--tsk-indent) / -2 - 1px);
  top: 0;
  bottom: 0;
  border-left: 1px solid var(--line);
}
.tsk-children .tsk-children > .tsk-branch:last-child::before {
  bottom: auto;
  height: calc(var(--tsk-gap) + var(--tsk-row-mid));
  width: calc(var(--tsk-indent) / 2 - 2px);
  border-bottom: 1px solid var(--line);
  border-bottom-left-radius: 8px;
}
.tsk-children .tsk-children > .tsk-branch:not(:last-child)::after {
  content: '';
  position: absolute;
  left: calc(var(--tsk-indent) / -2 - 1px);
  top: calc(var(--tsk-gap) + var(--tsk-row-mid));
  width: calc(var(--tsk-indent) / 2 - 2px);
  border-top: 1px solid var(--line);
}

.tsk-row {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: calc(var(--tsk-row-mid, 28px) * 2);
  box-sizing: border-box;
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface);
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}
.tsk-row:active {
  background: var(--surface-2);
}
.tsk-chevron {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  color: var(--ink-4);
  /* The sprite's chevron points down. */
  transform: rotate(-90deg);
}
.tsk-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.tsk-name,
.tsk-facts {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tsk-name {
  font-size: 14.5px;
  font-weight: 500;
}
.tsk-facts {
  font-size: 12.5px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

/* A task's details. */
.tsk-detail {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding-bottom: 8px;
}
.tsk-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0;
  font-size: 13px;
  color: var(--ink-3);
}
.tsk-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

/* The session header's "2 running": plain header text, tappable. */
.session-running {
  padding: 0;
  border: none;
  background: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
}
.session-running:hover {
  text-decoration: underline;
}

/* Stop, in a task's status line: plain text, tappable, like the session header's items. */
.tsk-link {
  padding: 0;
  border: none;
  background: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
}
.tsk-link:hover {
  text-decoration: underline;
}
/* The thread scrolls in its own element with the bottom bar pinned below it — not the document
 * scroll other vanilla pages use on mobile. */
.session-page {
  height: 100%;
  display: flex;
  flex-direction: column;
}
/* Mobile: the shell's main area is unbounded in native-scroll mode, so bound to the viewport. */
@media (max-width: 767px) {
  .session-page {
    height: calc(var(--vh, 1vh) * 100);
    overflow: hidden;
  }
}

/* The thread's scroller, and what floats over its end (the jump-to-latest button). */
.session-scroll-wrap {
  position: relative;
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* Always scrolls itself. It keeps the shared .page class (desktop wheel forwarding finds it), so
 * this must out-rank .page's mobile document-scroll rule, `html:not(.harmony) .page`. */
.session-scroll-wrap > .session-scroll.page {
  flex: 1;
  min-height: 0;
  height: auto;
  overflow-y: auto;
  overscroll-behavior-y: contain;
}

/* Capped and centered on desktop, like the sessions list; 20px gutters on mobile. */
.session-thread,
.session-bar > * {
  max-width: 760px;
}
.session-thread {
  box-sizing: content-box;
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding: 8px 20px 24px;
}
@media (min-width: 768px) {
  .session-thread {
    padding: 8px 36px 24px;
  }
  .session-thread,
  .session-bar > * {
    margin-inline: auto;
  }
}

.session-loading {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding-top: 8px;
}

.session-earlier {
  margin: 0;
  text-align: center;
  font-size: 13px;
  color: var(--ink-3);
}

/* A user message's attached images, above its text. */
.session-thumbs {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 6px;
}
.session-thumb {
  display: grid;
  place-items: center;
  width: 88px;
  height: 88px;
  padding: 0;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface-2);
  cursor: zoom-in;
}
.session-thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.session-thumb--missing {
  font-size: 12px;
  color: var(--ink-3);
  cursor: default;
}

/* No top padding: the glass (mobile) or background (desktop) behind it starts right at the
   composer, so the fade above (AppShellAccessory) runs straight into it. */
.session-bar {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 0 20px 16px;
}
.session-bar > * {
  width: 100%;
  box-sizing: border-box;
}
/* Desktop: no room above it, and as wide as a bottom panel (the thread's width and its side
   padding), not the thread's text column. */
@media (min-width: 768px) {
  .session-bar {
    padding: 0 0 20px;
  }
  .session-bar > * {
    max-width: calc(760px + 2 * 36px);
  }
}
@media (max-width: 767px) {
  .session-bar {
    padding-bottom: 10px;
  }
}
/* The composer (and on mobile the nav) lie over the end of the thread (AppShellAccessory), so it
   scrolls clear of them - by exactly their height, not the content inset's extra room for a list's
   end. */
.session-scroll-wrap > .session-scroll.page {
  padding-bottom: var(--stratum-app-shell-bottom-chrome, 0px);
}

/* Back to the live end while scrolled up: a small round button centered just above the composer (or
   whatever banner sits over it), over the fade, as on claude.ai. Fixed over the scroller rather than in
   it, so scrolling (and its bounce) doesn't move it. The bottom chrome lies over the scroller's end -
   on mobile the nav, the accessory and the fade band above them, on desktop just the fade band (the
   accessory is below the page) - so it sits that high, less the band. Fades in and out. Over the
   shell's bottom chrome (z-index 20), so the glass doesn't cover it. */
.session-jump {
  position: absolute;
  left: 50%;
  bottom: calc(var(--stratum-app-shell-bottom-chrome, 0px) - var(--stratum-app-shell-bottom-fade, 0px) + 8px);
  z-index: 21;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  margin-left: -15px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: var(--surface);
  color: var(--ink-3);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s ease;
}
@media (min-width: 768px) {
  .session-jump {
    bottom: 8px;
  }
}
.session-jump--shown {
  opacity: 1;
  pointer-events: auto;
}
.session-jump:hover {
  color: var(--ink);
}
.session-jump svg {
  width: 14px;
  height: 14px;
  stroke-width: 2;
}

/* Tool details panel (claude/Thread.tsx's ToolPanel). */
.tool-panel-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding-bottom: 8px;
}

/* Desktop: bottom panels (tool details, tasks) dock to the shell's main column, over the composer
 * (AppShellLayout, with an accessory), at the thread's outer width: 760px content + 36px padding each
 * side - the composer's. Mobile keeps BottomPanel's viewport-wide default. */
@media (min-width: 768px) {
  .session-page {
    --stratum-bottom-panel-max-width: calc(760px + 2 * 36px);
  }
}

/* Tool panel title: "Bash  Show the deploy result" in normal case, one size, like the tool rows
 * in the thread. The panel's usual small uppercase label doesn't work for a sentence: capitals look
 * bigger than lowercase at the same size, so an uppercase name never matches its description.
 * BottomPanel's header leaves room for the close button; the summary ellipsizes before it. */
.tool-panel-title {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink);
}
.tool-panel-summary {
  /* One line that scrolls sideways (swipe or trackpad) to show the rest, rather than an ellipsis;
     no visible scrollbar. */
  min-width: 0;
  overflow-x: auto;
  white-space: nowrap;
  scrollbar-width: none;
  font-weight: 400;
  color: var(--ink-2);
}
.tool-panel-summary::-webkit-scrollbar {
  display: none;
}

/* The model and the actions menu in the header subtitle: plain header text over a native <select>
   (SelectOverlay), like media's read-page actions. */
.session-model-trigger,
.session-actions-trigger {
  cursor: pointer;
}
.session-model:hover .session-model-trigger,
.session-actions:hover .session-actions-trigger {
  text-decoration: underline;
}

/* An Agent tool call's details (claude/AgentDetails.tsx) in the tool panel. */
.agent-details {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.agent-facts,
.agent-note {
  margin: 0;
  font-size: 13px;
  color: var(--ink-3);
}
.agent-loading {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.agent-thread {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

/* A task notification in the thread that opens its task: the note's own text, tappable. */
.session-note-link {
  padding: 0;
  border: none;
  background: none;
  font: inherit;
  color: inherit;
  text-align: inherit;
  cursor: pointer;
}
.session-note-link:hover {
  text-decoration: underline;
}

/* Find in session: every occurrence of the query in the thread in soft yellow, the current match in
   solid orange, as a browser's find does. */
::highlight(session-match) {
  background-color: color-mix(in srgb, #ffd60a 40%, transparent);
}
::highlight(session-match-active) {
  background-color: var(--accent-alt);
  color: #1c1c1e;
}

/* Above the composer: the query, its matches, and the way back to the live end. */
.session-find {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 4px 4px 4px 12px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface);
  font-size: 13px;
  color: var(--ink-2);
}
.session-find-input {
  flex: 1;
  min-width: 0;
  padding: 6px 0;
  border: none;
  outline: none;
  background: transparent;
  font: inherit;
  /* 16px: iOS zooms the page into smaller inputs on focus. */
  font-size: 16px;
  color: var(--ink);
}
.session-find-input::placeholder {
  color: var(--ink-4);
}
.session-find-count {
  flex-shrink: 0;
  padding: 0 6px;
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
}
.session-find-btn {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border: none;
  border-radius: 8px;
  background: transparent;
  color: var(--ink-2);
  cursor: pointer;
}
.session-find-btn:hover:not(:disabled) {
  background: var(--surface-2);
}
.session-find-btn:disabled {
  color: var(--ink-4);
  cursor: default;
}
.session-find-btn svg {
  width: 16px;
  height: 16px;
  /* Icons that leave their weight to the caller (i-x) match the chevrons' 2px. */
  stroke-width: 2;
}
.session-find-btn--up svg {
  transform: rotate(180deg);
}

/* "N running" at the bottom of the thread: the Thinking line's look, as a button for the Tasks panel. */
.session-running-indicator {
  align-self: flex-start;
  padding: 0;
  border: none;
  background: none;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

/* A queued message's images, sent from another device (only the one that sent them has them). */
.session-queued-images {
  display: block;
  margin-bottom: 4px;
  font-size: 13px;
  color: var(--ink-3);
}

/* A message waiting for Claude to take it: muted, with Send now and Discard in its meta. */
.session-queued .stratum-chat-msg-body {
  opacity: 0.55;
}

/* The tool panel's Run in background (claude/Thread.tsx), above the running call's details. */
.tool-panel-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
}
.tool-panel-hint {
  font-size: 13px;
  color: var(--ink-3);
}
/* On desktop the list centers in a readable column, like the session thread; the header title
 * stays left. */
.sessions-content {
  max-width: 760px;
  display: flex;
  flex-direction: column;
}
@media (min-width: 768px) {
  .sessions-content {
    margin-inline: auto;
  }
}

.sessions-host {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.sessions-skeleton-row {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 16px;
}
.sessions-skeleton-row + .sessions-skeleton-row {
  border-top: 1px solid var(--line);
}

.sessions-filter-count {
  color: var(--ink-4);
}
.sessions-mark {
  border-radius: 3px;
  background: color-mix(in srgb, var(--accent-alt) 28%, transparent);
  color: inherit;
}
/* Under the lists: a section's distance from them, not hugging the last row. */
.sessions-searching {
  margin: 20px 4px 0;
  font-size: 13px;
  color: var(--ink-3);
}

/* Active filters as removable pills. */

.settings {
  max-width: 620px;
  margin: 0 auto;
}
.viewport-debug {
  position: fixed;
  top: calc(env(safe-area-inset-top, 0px) + 8px);
  right: 8px;
  z-index: 1000;
  margin: 0;
  padding: 8px 10px;
  font: 11px/1.4 ui-monospace, Menlo, monospace;
  color: #fff;
  background: rgba(0, 0, 0, 0.75);
  border-radius: 8px;
  pointer-events: none;
}

/* Invisible elements whose measured heights read out CSS viewport units and the safe-area inset. */
.viewport-debug-probes {
  position: fixed;
  top: 0;
  left: -10px;
  width: 1px;
  visibility: hidden;
  pointer-events: none;
}
.viewport-debug-probes > div {
  position: absolute;
  top: 0;
  width: 1px;
}
.viewport-debug-safe {
  height: env(safe-area-inset-bottom, 0px);
}
:root {
  /* Extra bottom clearance stratum-ui's AppShellLayout adds under the installed PWA's bottom nav. */
  --pwa-nav-pad: 24px;
}

* {
  box-sizing: border-box;
}

/* --vh (index.tsx), not 100% or 100vh: iOS Safari can leave a CSS viewport height stale across
 * client-side route changes, leaving the page shorter than the screen. */
html,
body {
  margin: 0;
  padding: 0;
  height: calc(var(--vh, 1vh) * 100);
}

body {
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  background: var(--bg);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow: hidden;
}

/* Vanilla mobile pages scroll the document (AppShellLayout's native scroll mode), which keeps iOS
 * Safari's text selection working. Desktop scrolls inside the shell instead.
 *
 * Harmony keeps the document still on mobile too: the AEA app's browser collapses its address bar into
 * a floating pill whenever the document scrolls, covering the bottom nav, and it reports no viewport
 * change that the page could reliably lift the nav by. A document that never scrolls keeps the bar
 * expanded. .harmony is added only by harmony builds (see index.tsx). */
@media (max-width: 767px) {
  html:not(.harmony) body {
    overflow: visible;
  }
}

#root {
  height: 100%;
}
