/* --- Preset commands --- */
/* The wrapper exists only to anchor the menu, so it must take exactly the
   button's box: as a block it laid the inline-flex button out on a line box and
   came out 2px taller, which the row is sized by — the bar went 37 to 39 for a
   button that is the same height as the mark beside it. */
#preset-menu-wrap { position: relative; display: flex; }
/* The two things you might do with a draft, dressed as the one thing you
   usually do with it: same circle, same 36px, same fill — mixed down to a
   quarter of the accent so the three read as one family with one of them
   clearly first. Filled rather than outlined, because an outline beside a
   filled circle reads as a different KIND of control rather than a quieter
   one.
   Clear wears the family's quiet circle too, and never Send's fill: it is the
   opposite of sending, and the look of a thing is how a thumb tells them
   apart. */
#clear-btn,
#save-pin-btn,
#note-btn,
#wake-btn {
  width: 36px;
  height: 36px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: color-mix(in srgb, var(--accent) 22%, var(--bg-surface));
  color: var(--text);
  cursor: pointer;
  /* 18 like the send mark beside them: three buttons acting on one draft. */
  font-size: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: background 0.15s;
}
#clear-btn:disabled,
#save-pin-btn:disabled,
#note-btn:disabled,
#wake-btn:disabled { opacity: 0.4; cursor: not-allowed; }
#clear-btn:not(:disabled):hover,
#save-pin-btn:not(:disabled):hover,
#note-btn:not(:disabled):hover,
#wake-btn:not(:disabled):hover {
  background: color-mix(in srgb, var(--accent) 40%, var(--bg-surface));
}
/* The delays this button asks about. Anchored on the button rather than on the
   row, and opening UPWARD, for the same reason #preset-menu does: the row is at
   the bottom of the screen and everything below it is keyboard. */
#wake-menu-wrap { position: relative; display: flex; flex-shrink: 0; }
#wake-menu {
  position: absolute;
  bottom: calc(100% + 6px);
  /* Centred on its button, not hung off one edge of it. Anchored `right: 0` it
     was fine while the button sat next to Send; with the three circles reversed
     the button moved left and the menu went with it — measured at 320px, its
     left edge landed at -41. Centred, it is 54..278 at 320 and 98..322 at 390,
     and this button can never be at the screen edge: Send and the pin are
     always to the right of it. */
  left: 50%;
  transform: translateX(-50%);
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 4px;
  /* Sized by the longest row rather than by a guess. Measured at 190px: a
     12-hour locale writes "Sep 8 12:03 AM" beside "in an hour" and both wrapped
     onto two lines, which turns a list of six choices into a wall. */
  width: max-content;
  min-width: 190px;
  max-width: min(300px, calc(100vw - 32px));
  z-index: 100;
  box-shadow: 0 4px 12px rgba(0,0,0,0.4);
}
#wake-menu.hidden { display: none; }
.wake-item {
  display: flex;
  align-items: baseline;
  gap: 8px;
  width: 100%;
  text-align: left;
  background: transparent;
  color: var(--text);
  border: none;
  padding: 8px 10px;
  border-radius: 4px;
  cursor: pointer;
  font-size: 13px;
  white-space: nowrap;
}
.wake-item:hover { background: var(--bg-hover); }
/* When it lands, in the clock the person is reading. The delay is the choice;
   this is the consequence, and it is what stops "8 hours" from needing to be
   worked out at two in the morning. */
.wake-item .at {
  margin-left: auto;
  color: var(--text-muted);
  font-family: var(--mono);
  font-size: 12px;
}

/* The custom-delay sheet's preview line. It carries two things — when this will
   land, and why what's typed isn't a delay — and they read differently on
   purpose: the answer in the clock font the rows above use, the complaint in
   plain muted text so it isn't mistaken for a time. */
.wake-delay-preview {
  margin: 4px 0 0;
  min-height: 18px;
  font-family: var(--mono);
  font-size: 12px;
  color: var(--text);
}
.wake-delay-preview.bad { font-family: inherit; color: var(--text-muted); }

/* Note button — send the input as a mid-turn note (only shown while running).
   Dressed with #save-pin-btn above; only its hiding is its own. */
#preset-menu {
  position: absolute;
  bottom: calc(100% + 6px);
  /* Hung off the button's LEFT edge again: the mark moved back to the head of
     the row when the whole set arrived there, and from that end there is a
     screen's width to open into. (It was `right: 0` for as long as the button
     sat at the far right, where opening leftward was the only way to stay on
     screen at all — measured then at 1528 of 1440.) */
  left: 0;
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 4px;
  min-width: 160px;
  z-index: 100;
  box-shadow: 0 4px 12px rgba(0,0,0,0.4);
}
.preset-item {
  display: block; width: 100%; text-align: left;
  background: transparent; color: var(--text);
  border: none; padding: 6px 10px; border-radius: 4px;
  cursor: pointer; font-size: 13px; font-family: var(--mono);
}
.preset-item:hover { background: var(--bg-hover); }

.preset-event {
  margin: 8px 0;
  padding: 8px 10px;
  background: var(--bg-surface);
  border-left: 3px solid var(--accent);
  border-radius: 4px;
  font-size: 12px;
}
.preset-event.status-error { border-left-color: var(--red); }
.preset-event.status-ok    { border-left-color: var(--green); }
.preset-event-header {
  display: flex; align-items: center; gap: 8px;
  font-family: var(--mono);
}
.preset-event-label { font-weight: 600; color: var(--text); }
.preset-event-status {
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.5px;
  padding: 1px 6px; border-radius: 3px;
}
.preset-event.status-running .preset-event-status { background: var(--accent); color: var(--bg); }
.preset-event.status-ok .preset-event-status      { background: var(--green); color: var(--bg); }
.preset-event.status-error .preset-event-status   { background: var(--red); color: var(--bg); }
.preset-event-meta { color: var(--text-muted); font-size: 11px; margin-left: auto; }
.preset-event-out {
  margin-top: 6px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 6px 8px;
  font-family: var(--mono);
  font-size: 11px;
  white-space: pre-wrap;
  word-wrap: break-word;
  max-height: 320px;
  overflow-y: auto;
}
.preset-event-out.stderr { border-color: var(--red); opacity: 0.85; }
.preset-event-out-label { color: var(--text-muted); font-size: 10px; margin-top: 4px; }

/* Marks where the messages that arrived in the user's absence begin. A rule
   across the transcript with the count sitting in it, so it reads as a place in
   the conversation rather than as another message. */
.away-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 14px 0;
  color: var(--orange);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.away-divider::before,
.away-divider::after {
  content: "";
  flex: 1 1 0;
  height: 1px;
  background: var(--orange);
  opacity: 0.45;
}
/* The label can't shrink to nothing on a narrow screen; the rules either side
   give way instead. */
.away-divider span { flex: 0 0 auto; }

/* The way back past the window the chat opened on (chat.js loadEarlierRow).
   The away divider's shape — a rule with its words in it, a place in the
   transcript and not a message — in the border colour, because reaching back
   is not news. The words are the control. */
.load-earlier {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 6px 0 14px;
  white-space: nowrap;
}
.load-earlier::before,
.load-earlier::after {
  content: "";
  flex: 1 1 0;
  height: 1px;
  background: var(--border);
}
.load-earlier button {
  flex: 0 0 auto;
  background: none;
  border: 0;
  padding: 4px 6px;
  color: var(--text-muted);
  font: inherit;
  font-size: 11px;
  letter-spacing: 0.02em;
  cursor: pointer;
}
.load-earlier button:hover:not(:disabled) { color: var(--text); }
.load-earlier button:disabled { cursor: default; }

/* --- Dialog --- */
dialog {
  /* The global reset (* { margin: 0 }) at the top of this file nukes the
     UA-default `margin: auto` that centers modal dialogs combined with
     `inset: 0`. Restore it explicitly or the dialog pins to top-left. */
  margin: auto;
  background: var(--bg-surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 12px;
  /* A variable because two sticky rows have to reach the padding edge and back
     (see .dialog-actions and .sheet-head), and a phone sheet narrows it. Three
     places repeating `24` is three places to forget. */
  --dlg-pad: 24px;
  padding: var(--dlg-pad);
  /* Bounded by the VIEWPORT, not by a fixed number, and here rather than on
     each dialog: a modal wider than the screen puts its buttons off it, and a
     `showModal()` dialog has no backdrop click and no Esc key on a phone — the
     only way out of one is reloading the page. `min()` keeps the desktop width
     exactly as it was and only bites when the screen is narrower. */
  max-width: min(400px, calc(100vw - 32px));
  width: 90%;
  /* Nothing is set on the other axis on purpose. The UA already caps a dialog at
     `calc(100% - 34px)` and already gives it `overflow: auto`, so it scrolls
     inside the viewport by itself — checked, not assumed. What stranded the
     buttons was not the height but the action row scrolling away with the
     content, and `.dialog-actions` keeps it in place. A max-height here only
     shifted the UA's own limit by a couple of pixels and moved every tall
     dialog on desktop for nothing. */
}
dialog::backdrop { background: rgba(0,0,0,0.6); }

/* Desktop keeps Esc and a pointer that can reach anything, so the arrow is
   phone-only — but the wrapper is not, so one markup serves both. */
.sheet-head {
  display: flex;
  align-items: center;
  gap: 10px;
}
/* Phone only, like .sheet-back used to be: on a desktop these are modals with
   Escape and a Close button, and a bar across the bottom of one would be a
   phone idiom on a screen that has no use for it. */
.sheet-exit { display: none; }
.sheet-back {
  display: none;
  align-items: center;
  justify-content: center;
  /* 44px: this is the primary way out of a full-screen form on a touch screen,
     and it is the one control here that has no second chance — everything else
     in these dialogs can be tapped again. */
  width: 44px;
  height: 44px;
  margin-left: -10px;
  flex-shrink: 0;
  padding: 0;
  border: none;
  border-radius: 8px;
  background: none;
  color: var(--text);
  font-size: 20px;
  cursor: pointer;
}
.sheet-back:active { background: var(--bg-hover); }

/* The containers page (#containers-dialog). Cards are the dashboard block's,
   with one change the room here pays for: a job's command takes a line of its
   own. Measured in the popover it replaces, at 390px, the command column got
   122-172px of the 205-338 it needed and every row was clipped — and a page is
   only 12px wider, so width was never the answer. A line is.
   `order` rather than a move in the markup: one card serves the popover, the
   chat's jobs bar and this. */
#containers-body .dash-svc-group { margin-bottom: 14px; }
#containers-body .dash-svc-clear { margin-bottom: 10px; }
#containers-body .svc-card { margin-bottom: 6px; }
/* One kind, inside the merged page the phone's single section opens: sessions,
   turns, services, jobs, each under the rail's own heading. The gap is what
   makes them separate blocks rather than one long list — without it a heading sits
   6px under the last card of the block above and reads as that card's caption.
   The last one gives its margin back, so the page does not end in a space. */
#containers-body .container-block { margin-bottom: 18px; }
#containers-body .container-block:last-child { margin-bottom: 0; }
/* The first heading has the page's own top edge above it and does not need the
   4px the rail gives it between blocks. */
#containers-body .container-block:first-child .dash-svc-heading { margin-top: 0; }

/* --- Phone sheets ---------------------------------------------------------
   On a phone these five dialogs are already a page in everything but dressing.
   Measured at 390x844 with the lists filled: New Session is 810px tall in an
   844px viewport with 347px more below the fold, Settings 810 with 276 below.
   What the modal frame adds at that size is 39px of lost width (a dialog is
   90%/max-400, so 351 of 390) around something that already covers the screen,
   plus rounded corners and a backdrop that cannot be tapped — showModal() gives
   a phone neither a backdrop click nor Esc, which is why both sticky rows below
   exist at all.
   So: edge to edge, no frame, and the width goes back into the content — the
   Browse list, whose paths are what runs out of room first.
   This is presentation only. A sheet is still a <dialog>: nothing underneath is
   unloaded, so closing it returns to the same session, same scroll position,
   same half-typed message. See sheet-back and the popstate wiring in app.js for
   the two ways out. */
@media (max-width: 768px) {
  dialog.dialog-sheet {
    --dlg-pad: 16px;
    width: 100%;
    max-width: none;
    margin: 0;
    border: none;
    border-radius: 0;
    /* The visual viewport, not the layout one. A dialog lives in the top layer
       and knows nothing about the soft keyboard; #app has been sized by --vvh
       since the keyboard first hid the composer, and a full-screen sheet has
       the same problem and can take the same answer. Falls back to 100% where
       visualViewport never wrote it. */
    height: var(--vvh, 100%);
    max-height: var(--vvh, 100%);
    /* Both sticky rows supply their own padding and have to reach the sheet's
       edges to stick against them. With the dialog's own 16px still in place the
       head stuck 16px down, with content scrolling through the band above it,
       and a 16px strip of the form showed under the button row. */
    padding-top: 0;
    padding-bottom: 0;
  }
  /* The action row now owns the bottom edge, so it also owns the home
     indicator's strip — the same reason #mobile-bar carries this. */
  .dialog-sheet .dialog-actions {
    padding-top: 6px;
    padding-bottom: calc(10px + env(safe-area-inset-bottom, 0px));
    box-shadow: 0 -10px 0 var(--bg-surface);
  }
  /* One dialog sets a width of its own by id (see #prompt-buttons-dialog), and
     an id beats a class — it came out 358 wide inside a 390 sheet rule. */
  #prompt-buttons-dialog.dialog-sheet { min-width: 0; max-width: none; }
  /* The arrow stays for the sheets that open on top of a chat; the three
     dashboard PAGES drop it, because they carry a bar at the bottom instead
     (see .sheet-exit). */
  .dialog-sheet:not(.dialog-page) .sheet-back { display: flex; }
  .dialog-sheet .sheet-head {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--bg-surface);
    /* Out to the padding edge and back, like .dialog-actions at the other end,
       so nothing scrolls past it in the margin. */
    margin: 0 calc(-1 * var(--dlg-pad));
    margin-bottom: 4px;
    padding: 8px var(--dlg-pad);
  }
  .dialog-sheet .sheet-head h2 { margin-bottom: 0; }

  /* The sheet's own bottom bar. It is not the mobile bar and cannot be — a
     showModal() dialog is in the top layer, so the real one underneath is not
     tappable — but it is the same 44px, the same hairline, the same safe-area
     strip, in the same place. One section, because a sheet leads back to
     exactly one place.
     The height is a variable so the action row above can stick on top of it
     rather than under it. */
  .dialog-page {
    /* What the action row above has to clear. Same arithmetic as the bar's own
       box: a 44px section plus the strip below it. */
    --sheet-exit-h: calc(44px + max(env(safe-area-inset-bottom, 0px), 12px));
  }
  /* A column, so the exit bar can be pushed to the floor by `margin-top: auto`.
     Sticky alone only pins it when there is enough content to scroll: measured
     with the short sheets, it sat at y=69 and y=133 — a bar floating in the
     middle of the screen. */
  /* [open] is load-bearing. `display: flex` on the element itself beats the UA's
     `dialog:not([open]) { display: none }`, so without it all six sheets were
     laid out at 390x844 whether or not they were open — measured, the element
     under the middle of the phone screen was a CLOSED prompt-buttons dialog,
     which means it was taking the taps meant for the chat behind it. */
  dialog.dialog-page[open] {
    display: flex;
    flex-direction: column;
  }
  /* Everything the bar is comes from the shared rules above. What is only true
     here is WHERE it sits: pushed to the floor of the sheet, pinned there while
     the content scrolls, and stretched out to the sheet's padding edges — the
     bar's own box has no padding to escape. */
  .dialog-page .sheet-exit {
    margin-top: auto;
    position: sticky;
    bottom: 0;
    z-index: 2;
    margin-left: calc(-1 * var(--dlg-pad));
    margin-right: calc(-1 * var(--dlg-pad));
  }
  /* Above the exit bar, not behind it. */
  .dialog-page .dialog-actions { bottom: var(--sheet-exit-h); }
  /* Buttons whose only job was to close, and rows that held nothing else: the
     bar below says it once for all of them. */
  .dialog-page .sheet-close-only { display: none; }
  .dialog-page .dialog-actions.close-only { display: none; }
}

dialog h2 { margin-bottom: 16px; font-size: 18px; }

.project-item {
  padding: 10px 14px;
  border-radius: var(--radius);
  cursor: pointer;
  margin-bottom: 4px;
  transition: background 0.15s;
}
.project-item:active { background: var(--bg-hover); }
@media (hover: hover) {
  .project-item:hover { background: var(--bg-hover); }
}
.project-item .pname { font-weight: 500; }
.project-item .pcwd { font-size: 12px; color: var(--text-muted); }

/* The scratch entry: the one row that names no existing folder, so it carries
   a mark (i-scratch) where the others carry a path. */
.project-item-scratch { display: flex; align-items: center; gap: 10px; }
.project-item-scratch .pitem-icon { flex: none; width: 20px; height: 20px; color: var(--accent); }
.project-item-scratch .pitem-text { flex: 1; min-width: 0; }

/* Recent rows carry a dismiss (×) button revealed on hover. */
.project-item-recent { display: flex; align-items: center; gap: 8px; }
.project-item-recent .pcwd { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.project-item .project-remove {
  flex: none;
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-size: 18px;
  line-height: 1;
  padding: 0 6px;
  cursor: pointer;
  border-radius: var(--radius);
  opacity: 0;
  transition: opacity 0.15s, color 0.15s, background 0.15s;
}
.project-item .project-remove:hover { color: var(--red); background: var(--bg-hover); }
@media (hover: hover) {
  .project-item-recent:hover .project-remove { opacity: 0.7; }
}
/* Touch devices have no hover — keep the button visible. */
@media (hover: none) {
  .project-item .project-remove { opacity: 0.7; }
}


/* --- Directory browser --- */
#browse-header {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}
#browse-up {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  cursor: pointer;
  font-size: 16px;
  padding: 4px 10px;
  flex-shrink: 0;
}
#browse-up:hover { background: var(--bg-hover); }
#browse-mkdir {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  cursor: pointer;
  font-size: 14px;
  padding: 4px 10px;
  flex-shrink: 0;
}
#browse-mkdir:hover { background: var(--bg-hover); }
/* At the top level there is nothing to go up to, create in, or select; and a
   lone root has no list above it. */
#browse-up:disabled, #browse-mkdir:disabled, #browse-select:disabled {
  opacity: 0.4;
  cursor: default;
  pointer-events: none;
}
#browse-path {
  font-size: 12px;
  color: var(--text-muted);
  word-break: break-all;
  flex: 1;
  min-width: 0;
}
#browse-list {
  max-height: 200px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg);
}
.browse-item {
  padding: 8px 12px;
  cursor: pointer;
  font-size: 13px;
  transition: background 0.1s;
}
.browse-item:active { background: var(--bg-hover); }
@media (hover: hover) {
  .browse-item:hover { background: var(--bg-hover); }
}
.browse-item::before { content: "\1F4C1 "; }
.browse-empty {
  padding: 12px;
  color: var(--text-muted);
  font-size: 12px;
  text-align: center;
}


.agent-picker {
  margin-bottom: 16px;
}
.agent-picker-label {
  display: block;
  font-size: 13px;
  color: var(--text-muted);
  margin-bottom: 6px;
}
.agent-option {
  flex: 1;
  padding: 8px 12px;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 13px;
  cursor: pointer;
}
.agent-option:hover { background: var(--bg-hover); }
.agent-option.active {
  background: var(--accent);
  color: var(--bg);
  border-color: var(--accent);
}
/* An agent agency holds no usable login for. Not a third look: `.proxy-disabled`
   is what the gh/glab chips wear with no proxy daemon and the ssh chip wears
   with no key (11-update-banner.css), and this is the same fact — a control
   still offered, pointing at Settings instead of acting.

   Two things a chip did not need. The :hover has to be put back, or a dead
   option still lights up under the pointer and reads as clickable; and .active
   keeps its accent underneath, because the selected-but-greyed state is the
   whole point of the clone case — the agent stays chosen while it cannot run. */
.agent-option.proxy-disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.agent-option.proxy-disabled:hover { background: var(--bg); }
.agent-option.proxy-disabled.active:hover { background: var(--accent); }

/* The run-behaviour toggles in the New Session dialog. They are the status bar's
   chips — same markup, same classes, same states — sized up to sit with the
   pickers above them rather than looking like a stray piece of the bar. */
#session-toggles {
  display: flex;
  /* Wraps, unlike the bar's row, which scrolls sideways instead. Six chips at
     this size are wider than a phone's dialog, and a dialog has the vertical
     room the bar does not — a second line costs nothing here, while an
     overflowing row would put `clean` past the edge with no way to reach it. */
  flex-wrap: wrap;
  gap: 6px;
}
#session-toggles .proxy-toggle,
#session-toggles .mode-chip {
  font-size: 15px;
  line-height: 20px;
  padding: 6px 12px;
}

/* The status bar's worktree marker (#status-worktree), distinct from the ⎇
   branch glyph so the two don't read as the same thing. It used to be worn by
   session rows and dashboard cards too; those dropped it, because the bar says
   the same thing about the session you are actually looking at — and it says it
   with the path beside it rather than as a glyph you have to hover.
   `pointer`, not `default`: the one place it survives is also the control that
   opens the worktree picker. */
.worktree-badge {
  display: inline-block;
  margin-left: 5px;
  font-size: 11px;
  line-height: 1;
  color: #b083d6;
  flex-shrink: 0;
  vertical-align: middle;
  cursor: pointer;
}
.worktree-badge.hidden { display: none; }

.spawned-badge {
  display: inline-block;
  margin-left: 4px;
  font-size: 11px;
  line-height: 1;
  color: var(--text-muted);
  flex-shrink: 0;
  vertical-align: middle;
  cursor: default;
}

/* The image tag a session runs on when it is not the default (`:next`), in the
   session row, the subagent row and the dashboard card. The muted mono of the
   app's other small factual asides, in an outline, because unlike them it
   says the session is set up differently from the rest. Never shrinks: the
   name ellipsises first. */
.image-chip {
  flex-shrink: 0;
  font-family: var(--mono);
  font-size: 10px;
  line-height: 14px;
  padding: 0 4px;
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--text-muted);
  white-space: nowrap;
  cursor: default;
}

/* AskUserQuestion tool card — readable question + options */
.tool-call-body.q-body { white-space: normal; }
.q-block { margin: 2px 0 8px; }
.q-block:last-child { margin-bottom: 2px; }
.q-text { font-weight: 600; margin-bottom: 4px; }
.q-multi { font-weight: 400; color: var(--text-muted); font-size: 12px; }
.q-options { margin: 0; padding-left: 16px; list-style: disc; }
.q-options li { margin: 2px 0; }
.q-opt-label { font-weight: 600; }
.q-opt-desc { color: var(--text-muted); }
.q-opt-desc::before { content: " — "; color: var(--text-muted); }
.q-result { margin-top: 8px; color: var(--text-muted); font-family: var(--mono); font-size: 12px; }

.dialog-custom {
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}
.dialog-custom label {
  display: block;
  font-size: 13px;
  color: var(--text-muted);
  margin-bottom: 6px;
}
.dialog-custom input {
  width: 100%;
  padding: 8px 12px;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  font-size: 14px;
  outline: none;
}
.dialog-custom input:focus { border-color: var(--accent); }

.dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 16px;
}
/* The gate line that says why the submit beside it is dead (#new-session-gate,
   #subagent-gate). It takes the row's whole width rather than a share of it, so
   two buttons and a sentence never compete for 320px — and while it is `hidden`
   the row is exactly the row it always was. Scoped to the two rows that have
   one: `flex-wrap` on every .dialog-actions would change dialogs that have
   nothing to wrap. */
#new-session-actions, #new-subagent-actions { flex-wrap: wrap; }
.dialog-gate {
  flex: 1 0 100%;
  margin: 0;
  text-align: right;
}
/* On a phone the action row stays put while the content scrolls behind it, so
   Cancel / Close is reachable at every scroll position instead of only once you
   reach the end — on a screen this small every one of these dialogs overflows,
   and a `showModal()` dialog offers no backdrop tap and no Esc key, so buttons
   below the fold mean the only way out is reloading the page.
   
   Phone-only, and not because the desktop couldn't use it: `position: sticky`
   gives the row its own paint layer, which shifts text antialiasing inside
   #prompt-buttons-dialog by about a hundred sub-pixels. Invisible, but it is a
   change to screens that had no problem, so it stays on the side that does.
   
   Sticky binds to its containing block, so this only works while the row is a
   child of the dialog itself — #new-session-dialog's was nested one level in
   and had to be lifted out (see index.html). */
@media (max-width: 768px) {
  .dialog-actions {
    position: sticky;
    bottom: 0;
    background: var(--bg-surface);
    /* Out to the dialog's padding edge and back, so content scrolling
       underneath doesn't show through beside the buttons. Horizontal only: top
       padding would make the row taller and push the whole dialog down. The band
       above the buttons is painted by a shadow, which takes no space at all. */
    margin-left: calc(-1 * var(--dlg-pad));
    margin-right: calc(-1 * var(--dlg-pad));
    padding: 0 var(--dlg-pad);
    box-shadow: 0 -10px 0 var(--bg-surface);
  }
}
/* The same treatment for #new-session-dialog at EVERY width, because that one
   now outgrows a 900px-tall desktop viewport too: it was within 7px of the UA's
   own cap before the name row, and the row tipped it over. Once a dialog
   scrolls, an action row that scrolls with it is a Cancel button below the fold
   — the exact thing the block above exists to prevent, just arriving on the
   other kind of screen.
   Scoped to this dialog rather than lifting the media query, so
   #prompt-buttons-dialog keeps the paint layer it has and the hundred
   sub-pixels the comment above is about stay where they are. */
#new-session-dialog .dialog-actions {
  position: sticky;
  bottom: 0;
  background: var(--bg-surface);
  margin-left: calc(-1 * var(--dlg-pad));
  margin-right: calc(-1 * var(--dlg-pad));
  /* Sideways only. As the shorthand `padding: 0 var(--dlg-pad)` this claimed a
     bottom of 0 as well, and being id-scoped it outranked the phone-sheet rule
     that gives every other sheet its bottom margin — so on a phone the buttons
     here sat flush against the screen edge while Settings' were 10px up. */
  padding-inline: var(--dlg-pad);
  box-shadow: 0 -10px 0 var(--bg-surface);
}
.dialog-actions button {
  padding: 8px 20px;
  border: none;
  border-radius: var(--radius);
  cursor: pointer;
  font-size: 14px;
}
#dialog-cancel { background: var(--bg); color: var(--text); }
#dialog-cancel:hover { background: var(--bg-hover); }
#dialog-create { background: var(--accent); color: var(--bg); }
#dialog-create:hover:not(:disabled) { background: var(--accent-hover); }
/* Nothing chosen yet — and unlike every other disabled control in the app, this
   one says so in its own label ("Pick a folder"), so the dimming is confirming a
   sentence rather than replacing one. */
#dialog-create:disabled { opacity: 0.4; cursor: not-allowed; }

/* The button carries the destination, so it has to be able to give ground: it
   is the only thing in this row that can be arbitrarily long, and it must not
   push Cancel off a 390px screen. */
#dialog-create {
  display: inline-flex;
  /* Centre, not baseline: baseline stacks the tallest ascent on the deepest
     descent across the two faces, and the mono path's metrics made the row 1px
     taller than in the empty state. Both boxes are line-height 17 below, so
     centring them puts the text on the same line anyway. */
  align-items: center;
  gap: 0.35em;
  min-width: 0;
  max-width: 68%;
  white-space: nowrap;
  /* Pinned, because the path inside is set in the mono face at 13px and its
     line box is a pixel taller than the label's. Left alone, the sticky row
     twitched by 1px the moment a folder was picked. */
  line-height: 17px;
}
.create-target {
  font-family: var(--mono);
  font-size: 13px;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  /* A long path ellipsises from the LEFT: the tail is the folder you chose and
     the head is /Users/someone, which every row here shares. The path is wrapped
     in an LTR <bdi> for this to be safe — see setPendingCwd. */
  direction: rtl;
  text-align: left;
}
/* Which row was clicked. The line above says what it means; this says where it
   came from, and the two are needed for different questions — the row scrolls
   away, the line does not. */
.project-item.selected {
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  box-shadow: inset 3px 0 0 var(--accent);
}
/* It picks a directory now rather than creating in one, so it reads as one of
   the header's controls instead of a call to action. */
#browse-select {
  flex-shrink: 0;
  padding: 4px 10px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  cursor: pointer;
  font-size: 12px;
}
@media (hover: hover) {
  #browse-select:hover { background: var(--bg-hover); border-color: var(--accent); }
}

#confirm-dialog #confirm-message {
  margin-bottom: 20px;
  font-size: 14px;
  line-height: 1.5;
  /* The VM restart question is a list — what is about to die, one item a line —
     and a question that has to name numbers cannot be one paragraph. Every other
     message here is a single line and is unaffected: pre-line only honours the
     breaks that are in the text. */
  white-space: pre-line;
  /* Settings' questions name the thing that goes — a root's path, a key
     fingerprint, an image reference — and each of those is one unbreakable word.
     Measured at 320px, "Stop allowing /Users/nir/git/agents/agency/.worktrees/
     logoutstyle?" laid out 321px wide in a 238px box without this: 83px of the
     path past the sheet's edge. */
  overflow-wrap: anywhere;
}
#confirm-no { background: var(--bg); color: var(--text); }
#confirm-no:hover { background: var(--bg-hover); }
.dialog-actions button.danger { background: var(--red); color: white; }
.dialog-actions button.danger:hover { background: color-mix(in srgb, var(--red), black 20%); }

/* --- New-subagent dialog --- */
#new-subagent-dialog #subagent-agent-options { display: flex; flex-wrap: wrap; gap: 6px; }
#new-subagent-dialog #subagent-model-options { display: flex; flex-wrap: wrap; gap: 6px; }
#new-subagent-dialog #subagent-agent-options .agent-option,
#new-subagent-dialog #subagent-model-options .agent-option { flex: 0 1 auto; }
#new-subagent-dialog input[type="text"],
#new-subagent-dialog textarea {
  width: 100%;
  box-sizing: border-box;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 6px 8px;
  font-size: 14px;
  font-family: inherit;
  outline: none;
}
#new-subagent-dialog input[type="text"]:focus,
#new-subagent-dialog textarea:focus { border-color: var(--accent); }
#new-subagent-dialog textarea { resize: vertical; }
#subagent-cancel { background: var(--bg); color: var(--text); }
#subagent-cancel:hover { background: var(--bg-hover); }
#subagent-create { background: var(--accent); color: var(--bg); }
#subagent-create:hover { background: var(--accent-hover); }

