/* The graphics, part one: the desktop window and the terminal. Built in CSS
   from the desktop app's own layout and drawn the way the graphite app is:
   one frame holding the title row, the sidebar, the tab strip and the status
   line with no borders between them, and the terminal set into it as the one
   recessed thing, a well with 12px corners and a hairline rim. The chrome
   follows the theme. The terminal
   does not: it paints Campbell's #0C0C0C and its exact ANSI values in both
   themes, as the apps do. The phone, the notices and the pairing scan are
   app-ui.css. */

/* ------------------------------------------------------- desktop window --- */

/* The window drawn at the real app's scale, with its own colours named once:
   the raised pill is the chosen tab's and the chosen project's face, and the
   quiet glyph tone is the one the app calls faint. The window is a size
   container so its parts can drop to the narrow arrangement the app takes
   when the tabs outgrow the strip, whatever the page around it is doing. */
.app-window {
  --pill: var(--elevated);
  --pill-shadow: 0 0 0 0.5px rgba(0, 0, 0, 0.45), 0 1px 2px rgba(0, 0, 0, 0.35);
  --faint: color-mix(in srgb, var(--label-2) 87%, transparent);
  position: relative;
  container: appwin / inline-size;
  border-radius: 12px;
  background: var(--base);
  box-shadow: 0 0 0 0.5px var(--hairline-strong), var(--shadow-device);
  overflow: hidden;
}

@media (prefers-color-scheme: light) {
  .app-window {
    --pill-shadow: 0 0 0 0.5px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.1);
  }
}

.app-titlebar {
  display: flex;
  align-items: center;
  height: 44px;
  padding: 0 10px 0 0;
  background: var(--base)
}

/* The sidebar toggle, then the icon on its white tile. */
.title-toggle,
.title-icon {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  flex: none;
  border-radius: 6px;
  color: var(--label-2);
}

.title-toggle {
  margin-left: 10px;
}

.title-toggle svg,
.title-icon svg {
  width: 17px;
  height: 17px;
}

.app-mark {
  width: 28px;
  height: 28px;
  flex: none;
  margin-left: 4px;
  border-radius: 7px
}

/* The name and the folder, cut before the badges. The name follows the icon
   tile by 12px, as the app's does, whether the sidebar is open or not (the
   tile is 28px here as in the app, so the gap needs no scaling). */
.app-title {
  display: flex;
  align-items: baseline;
  flex: 0 1 auto;
  gap: 10px;
  min-width: 0;
  margin-left: 12px;
  overflow: hidden;
}

.app-title b {
  color: var(--label);
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
}

.app-title span {
  overflow: hidden;
  color: var(--faint);
  font-size: 11px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.title-actions {
  display: flex;
  align-items: center;
  gap: 2px;
  margin-left: auto;
  padding-left: 12px;
}

/* The remote-access capsule: a dot and a few words on the control fill. */
.remote-capsule {
  display: flex;
  align-items: center;
  gap: 7px;
  height: 26px;
  margin-right: 8px;
  padding: 0 11px 0 10px;
  border-radius: 999px;
  background: var(--fill);
  color: var(--label-2);
  font-size: 12px;
  font-weight: 510;
  white-space: nowrap;
}

.remote-capsule i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--green);
}

@container appwin (max-width: 739px) {
  .title-actions {
    display: none;
  }

  .app-titlebar .window-dots {
    margin-left: auto;
  }
}

/* The undecorated window draws its own controls at the top right, in the
   Windows order (minimise, maximise, close) and the macOS colours. */
.window-dots {
  display: flex;
  gap: 9px;
  flex: none;
  margin-left: 14px;
}

.window-dots i {
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: #febc2e;
  box-shadow: inset 0 0 0 0.5px rgba(0, 0, 0, 0.22)
}

.window-dots i:nth-child(2) {
  background: #28c840
}

.window-dots i:nth-child(3) {
  background: #ff5f57
}


.app-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 620px) {
  .app-body.has-side {
    grid-template-columns: 204px minmax(0, 1fr);
  }
}

/* The projects sidebar, on the frame's own ground: rows have no box until
   one is open, which is a raised pill. Glyphs sit in one column 32px in, and
   the add row and the host's footer line up under them. */
.app-side {
  display: none;
  flex-direction: column;
  background: var(--base)
}

@media (min-width: 620px) {
  .app-side {
    display: flex;
  }
}

.side-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 40px;
  padding: 0 10px 0 23px;
  color: var(--faint);
  font-size: 11px;
  font-weight: 600;
}

.side-add {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  color: var(--label-2);
}

.side-add svg {
  width: 15px;
  height: 15px;
}

.side-item {
  display: grid;
  grid-template-columns: 32px 1fr;
  align-items: center;
  height: 56px;
  margin: 0 10px 4px;
  padding: 0 6px 0 8px;
  border-radius: 12px;
}

.side-item.is-active {
  background: var(--pill);
  box-shadow: var(--highlight), var(--pill-shadow);
}

.side-icon {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  color: var(--faint);
}

.side-item.is-active .side-icon {
  color: var(--tint);
}

.side-icon svg {
  width: 18px;
  height: 18px;
}

.side-item.is-active .side-icon svg {
  fill: var(--tint-fill);
}

.side-copy {
  display: grid;
  gap: 2px;
  min-width: 0;
  padding-left: 6px;
}

.side-copy b {
  overflow: hidden;
  color: var(--label-body);
  font-size: 13px;
  font-weight: 510;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.side-item.is-active .side-copy b {
  color: var(--label);
  font-weight: 600;
}

.side-copy small {
  overflow: hidden;
  color: var(--label-2);
  font-size: 11px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Something in the project is running: a breathing green dot ahead of the
   count, the one thing in the list that moves. */
.side-copy small.is-live::before {
  display: inline-block;
  width: 6px;
  height: 6px;
  margin: 0 6px 1px 0;
  border-radius: 50%;
  background: var(--green);
  vertical-align: middle;
  animation: breathe 2.4s var(--ease-in-out) infinite;
  content: "";
}

/* Add a folder: a quiet row at the list's end, above the host. */
.side-new {
  display: flex;
  align-items: center;
  gap: 16px;
  height: 32px;
  margin: auto 10px 8px;
  padding: 0 0 0 15px;
  color: var(--label-2);
  font-size: 13px;
}

.side-new svg {
  width: 15px;
  height: 15px;
  flex: none;
}

.side-foot {
  display: flex;
  align-items: center;
  gap: 16px;
  height: 56px;
  padding: 0 14px 0 24px;
  color: var(--faint);
}

.side-foot svg {
  width: 16px;
  height: 16px;
  flex: none;
}

.side-foot div {
  display: grid;
  gap: 1px;
  min-width: 0;
}

.side-foot b {
  color: var(--label-body);
  font-size: 12px;
  font-weight: 600;
}

.side-foot small {
  font-size: 11px;
}

.app-main {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* The well: inset from the frame's edge, its rim drawn over the output. */
.app-main > .term {
  flex: 1;
  margin-right: 10px;
  border-radius: 12px;
  box-shadow: inset 0 0 0 1px var(--hairline), inset 0 1px 0 rgba(255, 255, 255, 0.03);
}

@media (max-width: 619.98px) {
  .app-main > .term {
    margin-left: 10px;
  }
}

/* The tab strip, one piece with the title bar above it, drawn as the app's
   is (tab-strip.css): a tab is a glyph, a left-aligned name, a state dot and
   a close, as text on the frame until it is the one on screen, which wears
   the raised pill (the tab's own ::after, inset 3px by 2px under the labels,
   so the strip isolates its stacking). The first pill starts on the well's
   edge. The close shows on the chosen tab only, there being no pointer. */
.app-tabs {
  position: relative;
  display: flex;
  flex: none;
  align-items: center;
  height: 40px;
  padding: 0 6px 0 0;
  background: var(--base);
  isolation: isolate;
  overflow: hidden;
}

.tab {
  position: relative;
  display: flex;
  flex: 0 0 160px;
  align-items: center;
  gap: 8px;
  height: 34px;
  padding: 0 8px 0 16px;
  color: var(--label-2);
  font-size: 12px;
  font-weight: 510;
}

@media (max-width: 619.98px) {
  .app-tabs {
    padding-left: 10px;
  }
}

.app-tabs > .tab:first-child {
  margin-left: -2px;
}

.tab::after {
  position: absolute;
  inset: 3px 2px;
  z-index: -1;
  border-radius: 10px;
  background: var(--pill);
  box-shadow: var(--highlight), var(--pill-shadow);
  opacity: 0;
  content: "";
}

.tab.is-active {
  color: var(--label);
}

.tab.is-active::after {
  opacity: 1;
}

.tab-glyph {
  width: 14px;
  height: 14px;
  flex: none;
  color: var(--faint);
}

.tab.is-active .tab-glyph {
  color: var(--label-2);
}

.tab-label {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-align: left;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The dot by the name: green while a command runs, a ring when idle, and the
   label's own colour once a run has finished and wants a look. */
.tab-dot {
  width: 6px;
  height: 6px;
  flex: none;
  box-sizing: border-box;
  border-radius: 50%;
  transition: background-color 0.25s var(--ease-out-soft);
}

.tab-dot.is-running,
.tab-dot.is-steady {
  background: var(--green);
}

.tab-dot.is-idle {
  border: 1.5px solid var(--faint);
}

[data-phase="idle"] .tab-dot.is-running {
  background: var(--label);
  animation: none;
}

.tab-x {
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
  flex: none;
  color: var(--faint);
  opacity: 0;
}

.tab.is-active .tab-x {
  opacity: 1;
}

.tab-x svg {
  width: 11px;
  height: 11px;
}

/* The run's progress, the app's running indicator (tab-progress.css in the
   desktop app): a 2px rounded track inset from the tab's edges and a band a
   little over a third of its width sweeping across it, by transform. Both are
   the tab's own label colour, so the band is white on the dark graphite tab and
   turns to the dark label on the light theme's white tab, where white would
   vanish; the track is that colour mixed a third of the way into the tab. When
   the run ends the indicator goes, as it does in the app. The dev server's
   bar is steady: it keeps running when the build ends. */
.tab-bar {
  position: absolute;
  right: 14px;
  bottom: 5px;
  left: 14px;
  height: 2px;
  border-radius: 1px;
  background: color-mix(in srgb, currentColor 30%, var(--elevated));
  overflow: hidden;
  transition: opacity 0.25s var(--ease-out-soft);
}

.tab-bar::before {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 35%;
  background: currentColor;
  content: "";
  animation: tab-progress-sweep 1.4s linear infinite;
}

[data-phase="idle"] .tab-bar:not(.is-steady) {
  opacity: 0;
}

[data-phase="idle"] .tab-bar:not(.is-steady)::before {
  animation-play-state: paused;
}

/* The add-tab group: a plus and a caret half its width, one small capsule that
   follows the last tab. When the tabs outgrow the strip it pins to the end as
   glass, a fade in the strip's colour ahead of it, so the tab under it stays
   faintly in sight. */
.add-tab-group {
  display: flex;
  flex: none;
  height: 30px;
  margin-left: 4px;
  border-radius: 10px;
}

.add-tab,
.add-tab-caret {
  display: grid;
  place-items: center;
  height: 30px;
}

.add-tab {
  width: 36px;
  color: var(--label-2);
}

.add-tab svg {
  width: 16px;
  height: 16px;
}

.add-tab-caret {
  width: 18px;
  color: var(--faint);
}

.add-tab-caret svg {
  width: 13px;
  height: 13px;
}

@container appwin (max-width: 739px) {
  .add-tab-group {
    position: absolute;
    top: 5px;
    right: 6px;
    margin: 0;
    background: var(--material);
    box-shadow: var(--highlight), var(--pill-shadow);
    -webkit-backdrop-filter: var(--material-blur);
    backdrop-filter: var(--material-blur);
  }

  .add-tab-group::before,
  .add-tab-group::after {
    position: absolute;
    top: -5px;
    bottom: -5px;
    content: "";
  }

  .add-tab-group::before {
    right: 100%;
    width: 44px;
    background: linear-gradient(to left, var(--base) 12%, transparent);
  }

  .add-tab-group::after {
    left: 100%;
    width: 6px;
    background: var(--base);
  }
}

.app-status {
  display: flex;
  align-items: center;
  gap: 7px;
  height: 24px;
  padding: 0 12px;
  background: var(--base);
  color: var(--label-2);
  font-size: 10.5px;
}

.app-status .spacer {
  margin-left: auto;
}

/* -------------------------------------------------------------- terminal --- */

.term {
  position: relative;
  padding: 14px 18px 16px;
  background: var(--term-bg);
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 1.62;
  letter-spacing: 0;
  overflow: hidden;
}

.term-lg {
  font-size: 12.5px;
  line-height: 1.72;
}

.term .line {
  min-height: 1.62em;
  color: var(--term-fg);
  white-space: pre;
  overflow: hidden;
  text-overflow: clip;
}

/* The scene driver takes a terminal over once it is running ([data-live]);
   with no script every line simply shows. Both skins are listed: the desk's
   .term and the phone's .mobile-device-term. */
.term[data-live] .line,
.mobile-device-term[data-live] .line {
  opacity: 0;
  transition: opacity 200ms var(--ease-out-soft);
}

.term[data-live] .line.is-on,
.mobile-device-term[data-live] .line.is-on {
  opacity: 1;
}

/* One cell per character, revealed in order; <i> is straightened back out. */
.term[data-live] i.tk,
.mobile-device-term[data-live] i.tk {
  font-style: normal;
  opacity: 0;
  transition: opacity 70ms linear;
}

.term[data-live] i.tk.is-on,
.mobile-device-term[data-live] i.tk.is-on {
  opacity: 1;
}

/* Campbell, exactly: the prompt, the path, the command, the output. */
.ps {
  color: #3a96dd;
}

.path {
  color: #f2f2f2;
}

.cmd {
  color: #f9f1a5;
}

.t-out {
  color: #cccccc;
}

.t-dim {
  color: #767676;
}

.t-ok {
  color: #16c60c;
}

.t-key {
  color: #3b78ff;
}

/* The desktop's completion notice, docked under the tab strip and centred on
   the window, clear of the phone that reaches over its corner. Centred by
   auto margins, not a transform, because the toast animates its transform. */
.app-window .toast-desk {
  position: absolute;
  top: 54px;
  right: 0;
  left: 0;
  z-index: 6;
  width: 256px;
  max-width: calc(100% - 32px);
  margin-inline: auto;
}
