/* Global tokens + the shared layout primitives (groups, rows, buttons) the
   launcher components key off. The token names mirror the desktop / web app
   so the launcher reads as the same product; dark is the default, light is
   opted into via `data-theme="light"` on the document element. */

.launcher-demo-frame {
  --bg: #1c1c1e;
  --bg-card: #232325;
  --bg-elev: #2a2a2c;
  --border: #3a3a3c;
  --text: #f5f5f7;
  --text-secondary: #98989d;
  --link: #58a6ff;
  --btn-bg: #2a2a2c;
  --btn-border: #3a3a3c;
  --accent: #3fb950;
  --brand: #e58c4d;
  --danger: #f85149;
}

.launcher-demo-frame[data-theme="light"] {
  --bg: #faf9f7;
  --bg-card: #ffffff;
  --bg-elev: #ffffff;
  --border: #e2e0dc;
  --text: #1a1a1a;
  --text-secondary: #6a6a6a;
  --link: #0a64c8;
  --btn-bg: #f2f1ee;
  --btn-border: #d9d7d2;
  --accent: #2da44e;
  --brand: #c25e16;
  --danger: #d1242f;
}

* {
  box-sizing: border-box;
} .launcher-demo-frame {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  font-size: 15px;
}

/* ---- Buttons ---------------------------------------------------------- */

.btn {
  padding: 0.5rem 0.9rem;
  border: 1px solid var(--btn-border);
  border-radius: 7px;
  background: var(--btn-bg);
  color: var(--text);
  font-size: 0.9rem;
  cursor: pointer;
  transition:
    border-color 160ms ease,
    filter 160ms ease;
}

.btn:hover:not(:disabled) {
  border-color: var(--brand);
}

.btn:disabled {
  opacity: 0.55;
  cursor: default;
}

.btn.primary {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
  font-weight: 600;
}

.btn.primary:hover:not(:disabled) {
  filter: brightness(1.06);
}

.btn-ghost {
  padding: 0.3rem 0.55rem;
  border: 1px solid transparent;
  border-radius: 6px;
  background: transparent;
  color: var(--text-secondary);
  font-size: 0.82rem;
  cursor: pointer;
  transition:
    border-color 160ms ease,
    color 160ms ease;
}

.btn-ghost:hover:not(:disabled) {
  border-color: var(--border);
  color: var(--text);
}

.btn-ghost:disabled {
  opacity: 0.5;
  cursor: default;
}

/* Square icon button -- the registry rows' per-action affordances (new window,
   on/off, new terminal, edit, connect/disconnect, forget). `.on` tints it the
   accent (an active toggle); `.locked` flashes yellow for a foreign lock;
   `.lost` follows a broken connection state; `.danger` reddens it on hover
   (a destructive op). */
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 1px solid var(--btn-border);
  border-radius: 7px;
  background: var(--btn-bg);
  color: var(--text-secondary);
  cursor: pointer;
  transition:
    border-color 160ms ease,
    color 160ms ease;
}

.icon-btn:hover:not(:disabled) {
  border-color: var(--brand);
  color: var(--text);
}

.icon-btn:disabled {
  opacity: 0.45;
  cursor: default;
}

.icon-btn.on {
  border-color: var(--accent);
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
}

.icon-btn.lost {
  border-color: var(--danger);
  color: var(--danger);
  background: color-mix(in srgb, var(--danger) 12%, transparent);
}

.icon-btn.locked {
  opacity: 1;
  cursor: default;
  animation: lock-attention 1.6s ease-in-out infinite;
}

.icon-btn.danger:hover:not(:disabled) {
  border-color: var(--danger);
  color: var(--danger);
}

@keyframes lock-attention {
  0%,
  100% {
    border-color: var(--btn-border);
    color: var(--text-secondary);
    background: var(--btn-bg);
  }

  50% {
    border-color: #e3b341;
    color: #e3b341;
    background: color-mix(in srgb, #e3b341 18%, transparent);
  }
}

/* Reduced-motion: keep the border/colour hover cue. */
@media (prefers-reduced-motion: reduce) {
  .btn,
  .btn-ghost {
    transition:
      border-color 160ms ease,
      color 160ms ease,
      filter 160ms ease;
  }

  .icon-btn {
    transition:
      border-color 160ms ease,
      color 160ms ease;
  }

  .icon-btn.locked {
    animation: none;
    border-color: #e3b341;
    color: #e3b341;
    background: color-mix(in srgb, #e3b341 18%, transparent);
  }
}

/* In-flight spinner: a lucide <LoaderCircle class="spin"> on a button whose
   on/off / connect op is pending (see pending.svelte.ts). The class lands on the
   icon's own <svg>; this stylesheet is global so it reaches it. */
.spin {
  animation: chan-spin 0.9s linear infinite;
}

@keyframes chan-spin {
  to {
    transform: rotate(360deg);
  }
}

/* Multi-select affordances shared by the workspace + devserver lists. */
.row-check {
  margin-right: 0.6rem;
  cursor: pointer;
  flex-shrink: 0;
}

.row.selected {
  background: color-mix(in srgb, var(--brand) 10%, var(--bg-card));
}

/* ---- Groups + rows (registry lists and the window feed) --------------- */

.group {
  margin-top: 1.75rem;
}

.group-title {
  margin: 0 0 0.6rem;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--text-secondary);
}

.rows {
  list-style: none;
  margin: 0;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}

.row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.7rem 0.9rem;
  background: var(--bg-card);
}

/* The divider sits between list items. A registry row IS its <li> (the li
   carries .row); a window-feed row wraps a .row button/div in its <li>. Keying
   off the <li> draws the divider uniformly either way. */
.rows > li + li {
  border-top: 1px solid var(--border);
}

.row-main {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-width: 0;
  /* Grow to fill the row so the label sits left, immediately after the
     checkbox, and pushes the actions to the far right. Without this a row with
     a leading checkbox has three space-between children and the label floats to
     the centre; the window feed (no checkbox) is already left-aligned, and
     growing here keeps it so. */
  flex: 1;
}

.row-name {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  font-size: 0.92rem;
  color: var(--text);
}

/* Workspace mount-error affordance: a danger-tinted icon beside the row name,
   carrying the backend's `error` reason as its tooltip. Shown when a row's
   lifecycle status is "error". */
.row-error {
  display: inline-flex;
  align-items: center;
  color: var(--danger);
}

.row-sub {
  font-size: 0.78rem;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 26rem;
}

.row-actions {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  flex-shrink: 0;
}

/* On/off pill toggle. */
.pill {
  min-width: 2.6rem;
  padding: 0.25rem 0.6rem;
  border: 1px solid var(--btn-border);
  border-radius: 999px;
  background: var(--btn-bg);
  color: var(--text-secondary);
  font-size: 0.78rem;
  cursor: pointer;
}

.pill.on {
  border-color: var(--accent);
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
}

/* A stored-token chip on a devserver row. */
.chip {
  font-size: 0.68rem;
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--text-secondary);
}

/* Connected/detached dot on a window-feed row. */
.dot {
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  background: var(--text-secondary);
  opacity: 0.4;
}

.dot.live {
  background: var(--accent);
  opacity: 1;
}

/* The mutable window-feed row exposes [FOCUS] + [SHOW/HIDE] icon buttons (the
   shared .icon-btn / .row-actions pattern); the read-only surface renders the
   row as a static <div> with the .dot as a plain connection indicator. */

/* ---- Window feed ------------------------------------------------------ */

.feed {
  margin-top: 2.25rem;
}

.feed-heading {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
}

  .topbar.svelte-120wshh {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.75rem 1.25rem;
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: 0;
    background: var(--bg);
    z-index: 10;
  }

  .title.svelte-120wshh {
    min-width: 0;
  }

  .brand.svelte-120wshh {
    display: block;
    font-size: 1.15rem;
    font-weight: 700;
    gap: 0;
    letter-spacing: -0.01em;
    line-height: 1.1;
    margin: 0;
    text-decoration: none;
  }

  /* The title as a flip toggle: a bare button inheriting the h1's face, with
     the brand hover as its affordance. */
  .title-toggle.svelte-120wshh {
    padding: 0;
    border: none;
    background: transparent;
    color: inherit;
    font: inherit;
    letter-spacing: inherit;
    cursor: pointer;
    transition: color 160ms ease;
  }

  .title-toggle.svelte-120wshh:hover {
    color: var(--brand);
  }

  .subtitle.svelte-120wshh {
    margin: 0.15rem 0 0;
    font-size: 0.78rem;
    color: var(--text-secondary);
  }

  .actions.svelte-120wshh {
    display: flex;
    gap: 0.5rem;
    flex-shrink: 0;
  }

  .icon-btn.svelte-120wshh {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border: 1px solid var(--btn-border);
    border-radius: 6px;
    background: var(--btn-bg);
    color: var(--text);
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
    transition:
      border-color 160ms ease,
      color 160ms ease;
  }

  .icon-btn.svelte-120wshh:hover {
    border-color: var(--brand);
    color: var(--brand);
  }

  /* Select mode active: the toggle holds the accent so it reads as engaged. */
  .icon-btn.select.active.svelte-120wshh {
    border-color: var(--accent);
    color: var(--accent);
    background: color-mix(in srgb, var(--accent) 14%, transparent);
  }


  /* Docked to the bottom of the viewport, above the content; App adds a spacer
     in select mode so the last rows clear the bar. */
  .bulk-bar.svelte-fkjub2 {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 40;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.75rem 1.25rem;
    border-top: 1px solid var(--border);
    background: var(--bg-elev);
    box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.25);
    font-size: 0.85rem;
  }

  .bulk-spacer.svelte-fkjub2 {
    flex: 1;
  }

  .bulk-count.svelte-fkjub2,
  .bulk-confirm.svelte-fkjub2 {
    font-weight: 600;
    color: var(--text);
  }

  .bulk-note.svelte-fkjub2 {
    color: var(--danger);
  }

  .bulk-btn.svelte-fkjub2 {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.4rem 0.8rem;
    border: 1px solid var(--btn-border);
    border-radius: 8px;
    background: var(--btn-bg);
    color: var(--text-secondary);
    font-size: 0.82rem;
    font-weight: 600;
    cursor: pointer;
    transition:
      border-color 160ms ease,
      background 160ms ease,
      color 160ms ease;
  }

  .bulk-btn.svelte-fkjub2:hover:not(:disabled) {
    border-color: var(--brand);
    color: var(--text);
  }

  .bulk-btn.svelte-fkjub2:disabled {
    opacity: 0.5;
    cursor: default;
  }

  .bulk-btn.accent.svelte-fkjub2 {
    border-color: color-mix(in srgb, var(--accent) 42%, transparent);
    background: color-mix(in srgb, var(--accent) 14%, transparent);
    color: var(--accent);
  }

  .bulk-btn.danger.svelte-fkjub2 {
    border-color: color-mix(in srgb, var(--danger) 40%, transparent);
    background: color-mix(in srgb, var(--danger) 12%, transparent);
    color: var(--danger);
  }

  .bulk-btn.danger.svelte-fkjub2:hover:not(:disabled) {
    border-color: var(--danger);
    background: color-mix(in srgb, var(--danger) 20%, transparent);
    color: var(--danger);
  }


  .screen-flip.svelte-1iq3uce {
    display: flex;
    flex-direction: column;
    -webkit-transform-style: preserve-3d;
    transform-style: preserve-3d;
  }

  .screen-flip-inner.svelte-1iq3uce {
    position: relative;
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    -webkit-transform-style: preserve-3d;
    transform-style: preserve-3d;
  }

  /* The back face: the incoming screen's name on the launcher background,
     turned away at rest so the hidden backface only shows mid-flip. */
  .screen-flip-inner.svelte-1iq3uce::before {
    content: attr(data-flip-label);
    position: absolute;
    inset: 0;
    z-index: 2;
    display: grid;
    place-items: center;
    background: var(--bg);
    color: color-mix(in srgb, var(--text) 70%, transparent);
    font-size: 28px;
    font-weight: 700;
    line-height: 1;
    pointer-events: none;
    transform: var(--screen-flip-back);
    -webkit-backface-visibility: hidden;
    backface-visibility: hidden;
  }

  .screen-flip-face.svelte-1iq3uce {
    position: relative;
    z-index: 1;
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    background: var(--bg);
    -webkit-backface-visibility: hidden;
    backface-visibility: hidden;
  }

  .screen-flip.flipActive.svelte-1iq3uce .screen-flip-inner:where(.svelte-1iq3uce) {
    transform-origin: center center;
    will-change: transform;
    animation: svelte-1iq3uce-launcher-screen-flip 520ms cubic-bezier(0.2, 0.7, 0.2, 1);
  }

  @keyframes svelte-1iq3uce-launcher-screen-flip {
    0% {
      transform: var(--screen-flip-start);
    }
    100% {
      transform: rotateX(0deg) rotateY(0deg);
    }
  }

  @media (prefers-reduced-motion: reduce) {
    .screen-flip.flipActive.svelte-1iq3uce .screen-flip-inner:where(.svelte-1iq3uce) {
      animation: none;
    }
  }

  /* The leading kind glyph (nested tree); the control terminal reads accent. */
  .row-glyph.svelte-1xma8vt {
    display: inline-flex;
    align-items: center;
    flex-shrink: 0;
    color: var(--text-secondary);
  }

  .row-glyph.control.svelte-1xma8vt {
    color: var(--accent);
  }

  /* Readonly hidden indicator: a muted, static EyeOff (no action) mirroring the
     server-persisted hidden state beside the connection dot. */
  .hidden-ind.svelte-1xma8vt {
    display: inline-flex;
    align-items: center;
    flex-shrink: 0;
    color: var(--text-secondary);
    opacity: 0.75;
  }

  /* A control terminal whose devserver is not responding: its eye slow-flashes
     yellow to request attention. The pulse overrides the .on accent tint while it
     runs; user action or a restored event clears it. */
  .icon-btn.attention.svelte-1xma8vt {
    animation: svelte-1xma8vt-control-attention 1.6s ease-in-out infinite;
  }

  @keyframes svelte-1xma8vt-control-attention {
    0%,
    100% {
      border-color: var(--btn-border);
      color: var(--text-secondary);
      background: var(--btn-bg);
    }
    50% {
      border-color: #e3b341;
      color: #e3b341;
      background: color-mix(in srgb, #e3b341 18%, transparent);
    }
  }

  /* Respect reduced-motion: hold a steady yellow instead of pulsing. */
  @media (prefers-reduced-motion: reduce) {
    .icon-btn.attention.svelte-1xma8vt {
      animation: none;
      border-color: #e3b341;
      color: #e3b341;
      background: color-mix(in srgb, #e3b341 18%, transparent);
    }
  }

  .os-icon.svelte-c37wte {
    display: inline-flex;
    align-items: center;
    /* Sit on the text baseline run without nudging the row's vertical rhythm. */
    vertical-align: -0.2em;
  }

  /* Each machine (LOCAL or a devserver) is a contained card whose background
     hosts the whole set: the header identity plus its terminal + workspace
     lists. The header is the top row; the lists sit below it as an indented peer
     list on the same surface. The whole badge wobbles on hover. */
  .machine.svelte-1dfzr5w {
    position: relative;
    margin-bottom: 0.8rem;
    padding: 0.3rem 0.5rem 0.7rem;
    border: 1px solid var(--border);
    border-radius: 14px;
    background: var(--bg-card);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.28);
    transform-origin: center;
    transition:
      transform 240ms cubic-bezier(0.34, 1.56, 0.64, 1),
      box-shadow 160ms ease;
  }

  /* The whole machine badge wobbles as one, including while the pointer is on
     nested controls. Buttons keep their own hover highlights without scaling. */
  .machine.svelte-1dfzr5w:hover {
    transform: scale(1.015);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.24);
    z-index: 1;
  }

  /* The machine header: icon + name + status on the left, machine-level actions
     pushed to the far right. The top row of the card. */
  .machine-header.svelte-1dfzr5w {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.4rem 0.2rem;
  }

  .machine-icon.svelte-1dfzr5w {
    display: inline-flex;
    align-items: center;
    color: var(--text-secondary);
    flex-shrink: 0;
  }

  .machine-name.svelte-1dfzr5w {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--text);
  }

  /* A small accent dot: this machine is present / the devserver is connected. */
  .status-dot.svelte-1dfzr5w {
    width: 0.45rem;
    height: 0.45rem;
    border-radius: 50%;
    background: var(--text-secondary);
    opacity: 0.4;
    flex-shrink: 0;
  }

  .status-dot.live.svelte-1dfzr5w {
    background: var(--accent);
    opacity: 1;
    box-shadow: 0 0 6px color-mix(in srgb, var(--accent) 70%, transparent);
  }

  /* Same dot, connection lost: the script died or the transport stopped
     answering. Steady red, no flashing. */
  .status-dot.lost.svelte-1dfzr5w {
    background: var(--danger);
    opacity: 1;
    box-shadow: 0 0 6px color-mix(in srgb, var(--danger) 70%, transparent);
  }

  /* The devserver identity block (name row over address row). On the mutable
     surface it is a button: the whole block opens the edit-config form, lifting
     a hover tint; the read-only surface renders it as a static div. */
  .ds-id.svelte-1dfzr5w {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 0;
    border-radius: 8px;
    padding: 0.2rem 0.45rem;
    margin: -0.2rem -0.45rem;
  }

  button.ds-id.svelte-1dfzr5w {
    border: none;
    background: transparent;
    text-align: left;
    font: inherit;
    color: inherit;
    cursor: pointer;
  }

  button.ds-id.editable.svelte-1dfzr5w:hover {
    background: color-mix(in srgb, var(--text-secondary) 8%, transparent);
  }

  /* Leading icon cell shared by both identity rows: the kind glyph (Globe) on the
     name row, the OS mark directly under it on the address row, so the two marks
     read as one left column. Fixed width keeps them aligned. */
  .ds-glyph.svelte-1dfzr5w {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.15rem;
    flex-shrink: 0;
    color: var(--text-secondary);
  }

  .ds-name-row.svelte-1dfzr5w {
    display: flex;
    align-items: center;
    gap: 0.4rem;
  }

  .ds-addr-row.svelte-1dfzr5w {
    display: flex;
    align-items: center;
    gap: 0.4rem;
  }

  /* The inline edit pencil beside the address (mutable surface only). */
  .ds-id.svelte-1dfzr5w .addr-pencil {
    flex-shrink: 0;
    color: var(--text-secondary);
    transition: color 160ms ease;
  }

  button.ds-id.editable.svelte-1dfzr5w:hover .addr-pencil {
    color: var(--brand);
  }

  .machine-actions.svelte-1dfzr5w {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin-left: auto;
    flex-shrink: 0;
  }

  /* The connected/local content (terminals + workspaces), tucked below the
     header on the same card surface with no left rule. */
  .machine-content.svelte-1dfzr5w {
    margin: 0.4rem 0.15rem 0 0.25rem;
  }

  .section-label.svelte-1dfzr5w {
    margin: 0.6rem 0 0.35rem 0.1rem;
    font-size: 0.66rem;
    font-weight: 600;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--text-secondary);
  }

  /* Flat (borderless) row lists for control + standalone terminals + loose
     windows: the rows read against the page, not boxed like the registry list. */
  .term-list.svelte-1dfzr5w .row {
    background: transparent;
    border-radius: 8px;
    padding: 0.45rem 0.5rem;
  }

  .term-list.svelte-1dfzr5w .row:hover {
    background: color-mix(in srgb, var(--text-secondary) 8%, transparent);
  }

  .connect-prompt.svelte-1dfzr5w {
    margin: 0.35rem 0 0 0.5rem;
    padding: 0.5rem 0.75rem;
    font-size: 0.82rem;
    color: var(--text-secondary);
  }

  /* The browser sign-in hand-off: the prompt gains the in-flight spinner
     (global .spin) beside the text. */
  .connect-prompt.waiting.svelte-1dfzr5w {
    display: flex;
    align-items: center;
    gap: 0.45rem;
  }

  .empty-hint.svelte-1dfzr5w {
    margin: 0.35rem 0 0;
    font-size: 0.85rem;
    line-height: 1.5;
    color: var(--text-secondary);
  }

  .empty-hint.svelte-1dfzr5w code:where(.svelte-1dfzr5w) {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.85em;
    padding: 0.1em 0.35em;
    border-radius: 4px;
    background: color-mix(in srgb, var(--text-secondary) 16%, transparent);
    color: var(--text);
    white-space: nowrap;
  }

  /* A workspace card: a rounded panel whose header collapses/expands its nested
     windows. Workspace cards stay visually stable; the controls inside them keep
     only their hover highlights. */
  .ws-card.svelte-1dfzr5w {
    position: relative;
    margin-bottom: 0.4rem;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--bg-elev);
    overflow: hidden;
  }

  /* Reduced-motion: keep colour/background hover cues, drop the wobble. */
  @media (prefers-reduced-motion: reduce) {
    .machine.svelte-1dfzr5w {
      transition: box-shadow 160ms ease;
    }
    .machine.svelte-1dfzr5w:hover {
      transform: none;
    }
  }

  .ws-head.svelte-1dfzr5w {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.55rem 0.65rem;
  }

  .ws-head.selected.svelte-1dfzr5w {
    background: color-mix(in srgb, var(--brand) 10%, var(--bg-elev));
  }

  /* The expand chevron rotates from ► (collapsed) to ▼ (expanded). */
  .chevron.svelte-1dfzr5w {
    --chevron-rotation: 0deg;

    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.25rem;
    height: 1.25rem;
    padding: 0;
    border: none;
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
    flex-shrink: 0;
    transform: rotate(var(--chevron-rotation));
    transform-origin: center;
    transition:
      transform 120ms ease,
      color 160ms ease;
  }

  .chevron.expanded.svelte-1dfzr5w {
    --chevron-rotation: 90deg;
  }

  .chevron.svelte-1dfzr5w:hover {
    color: var(--text);
  }

  .chevron-spacer.svelte-1dfzr5w {
    width: 1.25rem;
    flex-shrink: 0;
  }

  /* The window-count badge on a card with nested windows. */
  .count-badge.svelte-1dfzr5w {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.1rem 0.4rem;
    border: 1px solid transparent;
    border-radius: 6px;
    background: color-mix(in srgb, var(--text-secondary) 12%, transparent);
    color: var(--text-secondary);
    font-size: 0.7rem;
    font-weight: 600;
    flex-shrink: 0;
    cursor: pointer;
    transition:
      background 160ms ease,
      color 160ms ease;
  }

  .count-badge.svelte-1dfzr5w:hover {
    background: color-mix(in srgb, var(--text-secondary) 18%, transparent);
    color: var(--text);
  }

  /* The nested windows panel (darker, inside the card). */
  .ws-windows.svelte-1dfzr5w {
    border-top: 1px solid var(--border);
    background: color-mix(in srgb, #000 14%, var(--bg-elev));
    padding: 0.25rem;
  }

  .ws-windows.svelte-1dfzr5w .row {
    background: transparent;
    border-radius: 8px;
    padding: 0.4rem 0.5rem;
  }

  .ws-windows.svelte-1dfzr5w .row:hover {
    background: color-mix(in srgb, var(--text-secondary) 8%, transparent);
  }

  /* The decoupled add-devserver entry: a full-width dashed button under the
     machine list, brightening to the accent on hover. */
  .add-devserver.svelte-1dfzr5w {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    width: 100%;
    margin-top: 1.5rem;
    padding: 0.75rem;
    border: 1px dashed var(--btn-border);
    border-radius: 11px;
    background: transparent;
    color: var(--text-secondary);
    font-size: 0.9rem;
    font-weight: 500;
    cursor: pointer;
    transition:
      border-color 160ms ease,
      background 160ms ease,
      color 160ms ease;
  }

  .add-devserver.svelte-1dfzr5w:hover {
    border-color: color-mix(in srgb, var(--accent) 45%, var(--btn-border));
    color: var(--text);
    background: color-mix(in srgb, var(--text-secondary) 6%, transparent);
  }

  @media (prefers-reduced-motion: reduce) {
    .count-badge.svelte-1dfzr5w,
    .add-devserver.svelte-1dfzr5w {
      transition:
        border-color 160ms ease,
        background 160ms ease,
        color 160ms ease;
    }
  }

  /* Each gateway is a contained card, the machine-badge idiom: identity header
     over a one-line status narration. The whole badge wobbles on hover. */
  .gateway-card.svelte-16viogi {
    position: relative;
    margin-bottom: 0.8rem;
    padding: 0.3rem 0.5rem 0.7rem;
    border: 1px solid var(--border);
    border-radius: 14px;
    background: var(--bg-card);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.28);
    transform-origin: center;
    transition:
      transform 240ms cubic-bezier(0.34, 1.56, 0.64, 1),
      box-shadow 160ms ease;
  }

  .gateway-card.svelte-16viogi:hover {
    transform: scale(1.015);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.24);
    z-index: 1;
  }

  .gateway-header.svelte-16viogi {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 0.25rem 0.35rem;
  }

  .gw-id.svelte-16viogi {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    flex: 1;
    min-width: 0;
  }

  .gw-name-row.svelte-16viogi,
  .gw-addr-row.svelte-16viogi {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    min-width: 0;
  }

  .gw-glyph.svelte-16viogi {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1rem;
    flex-shrink: 0;
    color: var(--text-secondary);
  }

  .gw-name.svelte-16viogi {
    font-weight: 600;
    font-size: 0.92rem;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .gw-url.svelte-16viogi {
    font-size: 0.78rem;
    color: var(--text-secondary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .status-dot.svelte-16viogi {
    width: 0.45rem;
    height: 0.45rem;
    border-radius: 50%;
    background: var(--text-secondary);
    opacity: 0.4;
    flex-shrink: 0;
  }

  .status-dot.live.svelte-16viogi {
    background: var(--accent);
    opacity: 1;
    box-shadow: 0 0 6px color-mix(in srgb, var(--accent) 70%, transparent);
  }

  /* Same dot, connection lost: the roster poll keeps failing. Steady red. */
  .status-dot.lost.svelte-16viogi {
    background: var(--danger);
    opacity: 1;
    box-shadow: 0 0 6px color-mix(in srgb, var(--danger) 70%, transparent);
  }

  .gateway-actions.svelte-16viogi {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex-shrink: 0;
  }

  .gateway-prompt.svelte-16viogi {
    margin: 0.35rem 0 0 0.5rem;
    padding: 0.5rem 0.75rem;
    font-size: 0.82rem;
    color: var(--text-secondary);
  }

  /* The browser sign-in hand-off: the prompt gains the in-flight spinner
     (global .spin) beside the text. */
  .gateway-prompt.waiting.svelte-16viogi {
    display: flex;
    align-items: center;
    gap: 0.45rem;
  }

  .empty-hint.svelte-16viogi {
    margin: 0.35rem 0 0;
    font-size: 0.85rem;
    line-height: 1.5;
    color: var(--text-secondary);
  }

  /* The dashed add entry point, mirroring the Computers screen's Add devserver. */
  .add-gateway.svelte-16viogi {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    width: 100%;
    margin-top: 1.5rem;
    padding: 0.75rem;
    border: 1px dashed var(--btn-border);
    border-radius: 11px;
    background: transparent;
    color: var(--text-secondary);
    font-size: 0.9rem;
    font-weight: 500;
    cursor: pointer;
    transition:
      border-color 160ms ease,
      background 160ms ease,
      color 160ms ease;
  }

  .add-gateway.svelte-16viogi:hover {
    border-color: color-mix(in srgb, var(--accent) 45%, var(--btn-border));
    color: var(--text);
    background: color-mix(in srgb, var(--text-secondary) 6%, transparent);
  }

  @media (prefers-reduced-motion: reduce) {
    .gateway-card.svelte-16viogi,
    .gateway-card.svelte-16viogi:hover {
      transform: none;
      transition: box-shadow 160ms ease;
    }
  }

  .overlay.svelte-1p61rae {
    position: fixed;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
    padding: 1.5rem;
  }

  .backdrop.svelte-1p61rae {
    position: absolute;
    inset: 0;
    border: none;
    padding: 0;
    background: rgba(0, 0, 0, 0.45);
    cursor: default;
  }

  .modal.svelte-1p61rae {
    position: relative;
    width: min(34rem, 100%);
    max-height: 90vh;
    overflow-y: auto;
    background: var(--bg-elev);
    border: 1px solid var(--border);
    border-radius: 12px;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);
  }

  .modal.svelte-1p61rae:focus {
    outline: none;
  }

  .modal-header.svelte-1p61rae {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--border);
  }

  .modal-header.svelte-1p61rae h2:where(.svelte-1p61rae) {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 600;
  }

  .modal-close.svelte-1p61rae {
    border: none;
    background: transparent;
    color: var(--text-secondary);
    font-size: 1.5rem;
    line-height: 1;
    cursor: pointer;
  }

  .modal-close.svelte-1p61rae:hover {
    color: var(--text);
  }

  /* The corrected dialog spacing: the body has its own bottom padding so the
     action row never overlaps the last field (the old launcher's bug). */
  .modal-body.svelte-1p61rae {
    padding: 1.25rem;
  }

  .intro.svelte-17sc20u {
    margin: 0 0 1rem;
    color: var(--text-secondary);
    font-size: 0.9rem;
    line-height: 1.45;
  }

  .field.svelte-17sc20u {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    margin-bottom: 0.85rem;
    font-size: 0.85rem;
    color: var(--text-secondary);
  }

  /* Inline checkbox + label (the auto-hide control-terminal option). */
  .check-field.svelte-17sc20u {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.85rem;
    font-size: 0.85rem;
    color: var(--text-secondary);
    cursor: pointer;
  }

  .field.svelte-17sc20u input:where(.svelte-17sc20u),
  .field.svelte-17sc20u textarea:where(.svelte-17sc20u) {
    padding: 0.5rem 0.6rem;
    border: 1px solid var(--border);
    border-radius: 7px;
    background: var(--bg);
    color: var(--text);
    font-size: 0.9rem;
    font-family: inherit;
  }

  /* Address + path + script read as literal text the user pastes from a shell. */
  .mono.svelte-17sc20u {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace !important;
  }

  .field.svelte-17sc20u textarea:where(.svelte-17sc20u) {
    resize: vertical;
  }

  /* The folder field pairs its text input with a Browse… button (the native
     folder picker on the desktop surface). The input takes the remaining width;
     the button keeps its size. */
  .path-row.svelte-17sc20u {
    display: flex;
    gap: 0.5rem;
    align-items: stretch;
  }

  .path-row.svelte-17sc20u input:where(.svelte-17sc20u) {
    flex: 1;
    min-width: 0;
  }

  .path-row.svelte-17sc20u .btn:where(.svelte-17sc20u) {
    flex-shrink: 0;
    white-space: nowrap;
  }

  .field.svelte-17sc20u input:where(.svelte-17sc20u):focus,
  .field.svelte-17sc20u textarea:where(.svelte-17sc20u):focus {
    outline: none;
    border-color: var(--brand);
  }

  .muted.svelte-17sc20u {
    color: var(--text-secondary);
    font-weight: 400;
    opacity: 0.8;
  }

  /* The command-line tip box: a terminal-iconed hint that the same thing can be
     done from a shell (chan open). */
  .tip.svelte-17sc20u {
    display: flex;
    gap: 0.6rem;
    align-items: flex-start;
    margin: 0.25rem 0 0;
    padding: 0.65rem 0.75rem;
    border: 1px solid var(--border);
    border-radius: 9px;
    background: color-mix(in srgb, var(--text-secondary) 8%, transparent);
    color: var(--text-secondary);
    font-size: 0.82rem;
    line-height: 1.5;
  }

  .tip.svelte-17sc20u svg {
    flex-shrink: 0;
    margin-top: 0.1rem;
  }

  .tip.svelte-17sc20u code:where(.svelte-17sc20u) {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    color: var(--accent);
  }

  .error.svelte-17sc20u {
    margin: 0.5rem 0 0;
    padding: 0.5rem 0.65rem;
    border-radius: 7px;
    background: color-mix(in srgb, var(--danger) 16%, transparent);
    color: var(--danger);
    font-size: 0.85rem;
  }

  /* The action row keeps a clear top margin so the submit button never overlaps
     the last field. */
  .dialog-footer.svelte-17sc20u {
    display: flex;
    justify-content: flex-end;
    margin-top: 1.5rem;
  }

  .message.svelte-99q35t {
    margin: 0;
    color: var(--text);
    font-size: 0.95rem;
    line-height: 1.5;
  }

  .dialog-footer.svelte-99q35t {
    display: flex;
    justify-content: flex-end;
    gap: 0.6rem;
    margin-top: 1.5rem;
  }

  .notice-stack.svelte-1lzbaws {
    position: fixed;
    bottom: 2rem;
    right: 0.6rem;
    z-index: 41;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    width: 22rem;
    max-width: calc(100vw - 1.2rem);
  }

  .notice-bubble.svelte-1lzbaws {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 9px;
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.28);
    overflow: hidden;
  }

  .notice-bubble.error.svelte-1lzbaws {
    border-color: color-mix(in srgb, var(--danger) 45%, var(--border));
  }

  .nb-head.svelte-1lzbaws {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.4rem 0.6rem;
    border-bottom: 1px solid var(--border);
  }

  .nb-source.svelte-1lzbaws {
    flex-shrink: 0;
    padding: 0.05rem 0.35rem;
    border-radius: 5px;
    background: color-mix(in srgb, var(--text-secondary) 12%, transparent);
    color: var(--text-secondary);
    font-size: 0.7rem;
    white-space: nowrap;
  }

  .notice-bubble.error.svelte-1lzbaws .nb-source:where(.svelte-1lzbaws) {
    background: color-mix(in srgb, var(--danger) 14%, transparent);
    color: var(--danger);
  }

  .nb-title.svelte-1lzbaws {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--text);
  }

  .nb-close.svelte-1lzbaws {
    border: none;
    background: none;
    color: var(--text-secondary);
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
    padding: 0 0.2rem;
  }

  .nb-close.svelte-1lzbaws:hover {
    color: var(--text);
  }

  /* The whole body is the expand toggle: full-width bare button so the
     clamped message stays keyboard-reachable. */
  .nb-body.svelte-1lzbaws {
    display: block;
    width: 100%;
    margin: 0;
    padding: 0.5rem 0.6rem;
    border: none;
    background: none;
    text-align: left;
    cursor: pointer;
    font: inherit;
  }

  .nb-message.svelte-1lzbaws {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    font-size: 0.78rem;
    line-height: 1.4;
    color: var(--text-secondary);
    word-break: break-word;
  }

  .nb-message.expanded.svelte-1lzbaws {
    display: block;
    overflow: visible;
  }

  .content.svelte-1rrgju7 {
    max-width: 44rem;
    margin: 0 auto;
    padding: 1.5rem 1.25rem 4rem;
  }

  /* In select mode the bottom-docked bulk bar overlays the viewport; extra
     bottom padding keeps the last rows clear of it. */
  .content.with-bulk-bar.svelte-1rrgju7 {
    padding-bottom: 6rem;
  }

  .update-copy.svelte-1rrgju7 {
    margin: 0;
    color: var(--text);
    line-height: 1.45;
  }

  .update-error.svelte-1rrgju7 {
    margin: 0.85rem 0 0;
    padding: 0.55rem 0.65rem;
    border: 1px solid color-mix(in srgb, var(--danger) 35%, transparent);
    border-radius: 6px;
    background: color-mix(in srgb, var(--danger) 12%, transparent);
    color: var(--danger);
    font-size: 0.88rem;
  }

  .update-actions.svelte-1rrgju7 {
    display: flex;
    justify-content: flex-end;
    gap: 0.6rem;
    margin-top: 1.1rem;
  }

  .update-actions.svelte-1rrgju7 button:where(.svelte-1rrgju7) {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    min-height: 2.1rem;
    padding: 0 0.85rem;
    border-radius: 6px;
    font: inherit;
    cursor: pointer;
  }

  .update-actions.svelte-1rrgju7 button:where(.svelte-1rrgju7):disabled {
    cursor: progress;
    opacity: 0.65;
  }

  .update-actions.svelte-1rrgju7 .secondary:where(.svelte-1rrgju7) {
    border: 1px solid var(--border);
    background: var(--bg);
    color: var(--text-secondary);
  }

  .update-actions.svelte-1rrgju7 .primary:where(.svelte-1rrgju7) {
    border: 1px solid color-mix(in srgb, var(--accent) 70%, transparent);
    background: var(--accent);
    color: #fff;
  }

  .launcher-demo-frame.svelte-19il8s9 {
    background: var(--bg);
    color: var(--text);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
    display: flex;
    flex-direction: column;
    font-size: 14px;
    height: 100%;
    isolation: isolate;
    min-height: 100%;
    overflow: hidden;
    position: relative;
    transform: translateZ(0);
  }

  .launcher-demo-frame .topbar {
    flex: 0 0 auto;
    position: static;
  }

  /* Match the desktop launcher: the content column shares the top bar's 1.25rem
     side padding, so each machine card's edge aligns under the "Computers" title
     and the card internals (icon indent, gaps) fall back to the shipped launcher
     CSS instead of the embed-only nudges. Only the vertical padding is tightened
     for the shorter widget frame. */
  .launcher-demo-frame .content {
    background: var(--bg);
    flex: 1 1 auto;
    margin: 0;
    max-width: none;
    min-height: 0;
    overflow: auto;
    padding: 0.75rem 1.25rem 0.5rem;
  }

  .launcher-demo-frame .content.with-bulk-bar {
    padding-bottom: 4.25rem;
  }
