/* This file is for your main application CSS. */

/*
 * The Plot design tokens.
 *
 * A quiet, neutral palette with a single indigo accent, hairline borders and
 * restrained radii. The tokens also restate the theme the daisyUI components
 * draw from, so this stylesheet and every component on the page speak with
 * one voice. This file loads after the component styles it refines.
 */
:root {
  --plot-surface: #ffffff;
  --plot-surface-muted: #fafbfc;
  --plot-surface-sunken: #f1f3f5;
  --plot-hairline: #e6e8eb;
  --plot-hairline-strong: #d3d7dd;
  --plot-ink: #111827;
  --plot-ink-muted: #6b7280;
  --plot-ink-faint: #9ca3af;

  /* The chevron a choice is opened with. */
  --plot-caret: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%23000' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 4.5 6 7.5 9 4.5'/%3E%3C/svg%3E");
  --plot-accent: #4f46e5;
  --plot-accent-soft: #eef0ff;
  /* The edge of an accent artefact that is not filled with the accent: a soft
   * blue a shade darker than the fill it replaces, so a mark reads on the
   * surface without competing with the accent itself. */
  --plot-accent-edge: #aab3f5;
  --plot-accent-ink: #3730a3;
  --plot-danger: #b91c1c;
  --plot-attention: #f5c518;

  --plot-radius-sm: 0.375rem;
  --plot-radius: 0.5rem;
  --plot-radius-lg: 0.75rem;

  --plot-shadow: 0 1px 2px rgb(17 24 39 / 5%);
  --plot-ring: 0 0 0 3px rgb(79 70 229 / 15%);

  /* The page width of Plot, the one width a screen of the site is read at: the
   * column an ordinary page is centred in, and the width the body of a model
   * section is read at beside the left-aligned menu or sidebar of the section.
   * The body of a section is read at it from the Model Layout, so Build, Deploy
   * and Settings read alike. A screen that asks one thing of its visitor reads
   * it in the narrower card. */
  --plot-page-width: 56rem;
  --plot-card-width: 24rem;

  /* The width of the Model Lineage Browser: the level of the model lineage a
   * person browses is read rather than stretched, so it keeps one width however
   * wide the workspace it is centred in is. */
  --plot-browser-width: 44rem;

  /* The height of the strip the shell reads its footer at: the bottom edge of
   * the viewport is where the footer is read, and a panel docked to the bottom
   * of the workspace is anchored above it rather than over it. */
  --plot-shell-footer-height: 2.125rem;

  /* The daisyUI theme the components draw from. */
  --color-base-100: var(--plot-surface);
  --color-base-200: var(--plot-surface-sunken);
  --color-base-300: var(--plot-hairline);
  --color-base-content: var(--plot-ink);
  --color-primary: var(--plot-accent);
  --color-primary-content: #ffffff;
  --color-neutral: #1f2937;
  --color-neutral-content: #ffffff;
  --color-error: var(--plot-danger);
  --radius-box: var(--plot-radius-lg);
  --radius-field: var(--plot-radius);
  --radius-selector: var(--plot-radius-sm);
  --depth: 0;
  --noise: 0;
}

body {
  background-color: var(--plot-surface-muted);
  color: var(--plot-ink);
  font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
}

:focus-visible {
  outline: 2px solid color-mix(in oklab, var(--plot-accent) 60%, white);
  outline-offset: 2px;
}

/* Headings are quiet and tight: the content carries the hierarchy. */
.app-shell-main h1 {
  font-size: 1.125rem;
  font-weight: 600;
  letter-spacing: -0.011em;
}

.app-shell-main p {
  color: var(--plot-ink-muted);
}

/*
 * The application shell: a slim top bar, the main screen and the footer.
 *
 * The shell IS the viewport: it is exactly as tall as the viewport, and the
 * screen it holds is the box that scrolls inside it. The top bar and the
 * footer are therefore read at the edges of the viewport whatever the screen
 * holds, and no content can extend below the footer, because the screen is a
 * scroll container that clips at its own box.
 *
 * `dvh` is the dynamic viewport height: the shell fits the viewport whether
 * the browser interfaces are shown or retracted. `vh` is the fallback for
 * browsers that do not know it, where it names the large viewport.
 */
.app-shell {
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh;
  width: 100%;
}

/* The top bar and the footer keep the height they ask for: the screen is the
 * only part of the shell that gives. */
.app-shell > header {
  flex: none;
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 0;
  height: 4.5rem;
  padding: 0 clamp(1rem, 3vw, 2rem);
  border-bottom: 1px solid var(--plot-hairline);
  background-color: color-mix(in oklab, var(--plot-surface) 90%, transparent);
  backdrop-filter: blur(10px);
}

/* The Plot mark and the name of the product: they are read at the size they
 * are written in whatever the cell holds beside them, so the name of the model
 * after them is the part of the cell that gives way. */
.app-shell-brand {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 0.5rem;
  color: inherit;
  text-decoration: none;
}

.app-shell-brand span {
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: -0.011em;
}

/* The brand cell of the top bar: the Plot mark, the name of the model the
 * screen is about and the slash that leads it. It keeps the width of the
 * Sidebar Layout of a model screen, so the Model Navigation after it starts
 * where the sidebar is closed and the work of the section begins. The name is
 * the part of the cell that gives way: it truncates rather than pushing the
 * navigation off the width the cell keeps. */
.app-shell-brand-cell {
  display: flex;
  flex: 0 0 15rem;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
  padding-right: 1rem;
}

/* The slash that leads the name of the model and the name itself: the slash is
 * an element of the cell rather than a character of the name, so the cell
 * spaces it equally on both sides rather than leaving its right side to the
 * space the name is written with. */
.app-shell-context-separator,
.app-shell-context {
  font-size: 1rem;
  font-weight: 500;
  color: var(--plot-ink-muted);
}

.app-shell-context-separator {
  flex: none;
}

/* The name of the model the screen is about, after the Plot logo and the slash
 * that leads it. The brand cell keeps the width of the Sidebar Layout the Model
 * Navigation is aligned with, so the name never pushes the navigation off that
 * width: it is set a size smaller as it runs long, and wraps to the second line
 * the bar has room for — the two lines are the floor of the reading, and the
 * whole of the name is read on hover. */
.app-shell-context {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  min-width: 0;
  overflow: hidden;
  overflow-wrap: anywhere;
  line-height: 1.25;
  text-overflow: ellipsis;
}

.app-shell-context-medium {
  font-size: 0.875rem;
}

.app-shell-context-small {
  font-size: 0.75rem;
}

/* The navigation the top bar holds, and the identity beside it: the
 * navigation stands where the brand cell leaves it and keeps the width of its
 * sections whatever the bar holds, so the sections are always read from the
 * edge of the sidebar beside them; everything the bar holds after it — the row
 * of video screens and the menus of the member — is read at the far end, in the
 * room the navigation leaves. The navigation takes the height of the bar rather
 * than the height of the links it holds, so a section is marked on the hairline
 * the bar is closed by. */
.app-shell-navigation {
  display: flex;
  flex: none;
  align-self: stretch;
  align-items: center;
  min-width: 0;
}

.app-shell-identity {
  display: flex;
  align-items: center;
  margin-left: auto;
  padding-left: 1rem;
}

.app-shell-main {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-height: 0;
  width: 100%;
  /* The screen is the box a panel docked to the bottom of the workspace is
   * positioned against, so a panel is anchored to the bottom of the screen it
   * is docked in rather than to the bottom of the document. */
  position: relative;
  /* The screen of the shell is the box that scrolls: it takes the height the
   * top bar and the footer leave it, clips what it holds to that box, and
   * scrolls it, so the footer is never carried off the bottom of the viewport
   * by a screen that is taller than the viewport. */
  overflow-y: auto;
  /* The main screen of an ordinary page is centred in the page width, so a
   * page never stretches its content across the whole workspace. */
  max-width: var(--plot-page-width);
  margin-inline: auto;
  padding: 1.5rem clamp(1rem, 3vw, 2rem) 2.5rem;
}

/* A screen that fills the workspace, like the Model Management screen, keeps
 * the full width of the shell. */
.app-shell-main-full {
  max-width: none;
}

/*
 * The Modelling UI is the screen the Canvas Graph is modelled in, so the
 * workspace shell gives its margins back to it: the canvas takes the height
 * and the width the viewport leaves rather than the height and the width a
 * page margin leaves, and the sections beside it keep their own spacing.
 *
 * The workspace is read 0.5rem clear of the edges of the shell, and 0.375rem
 * under the top bar: the bar closes the workspace it stands over, and the band
 * it leaves meets the gutter beside the sidebar in a corner, so it is held
 * tighter than that gutter rather than at it.
 */
.app-shell-workspace .app-shell-main {
  padding: 0.375rem 0.5rem;
}

/* The top bar of a screen that fills the workspace is read at the gutter the
 * workspace is read at, so the brand stands where the sidebar begins and the
 * Model Navigation after the brand cell starts where the sidebar is closed —
 * the sections of the model are read over the work of the section they name. */
.app-shell-workspace > header {
  padding-inline: 0.5rem;
}

/*
 * The workspace shell: the shell of a screen that fills the workspace. It is
 * exactly the height of the viewport, so the screen it holds is bounded by the
 * viewport rather than by what it holds: the canvas and the menu beside it are
 * boxes with a definite height that scroll inside it. The Plot Canvas measures
 * the box it is mounted in and mounts no stage in a box with no height.
 */
.app-shell-workspace {
  height: 100vh;
  height: 100dvh;
}

/* A screen that asks one thing of the visitor, like signing in or naming a
 * model, is centred in the shell, both ways, with the footer below it. The
 * centre is `safe`: a screen taller than the shell scrolls from its top rather
 * than being centred into content that cannot be scrolled back to. */
.app-shell-main-centered {
  align-items: center;
  justify-content: center;
  justify-content: safe center;
  max-width: none;
  padding-bottom: 1.5rem;
}

/*
 * The Card: one quiet surface that holds a title, the fields it asks for and
 * the action that commits them. It is the whole of a centred screen, so it
 * leads with its title and spans its action, the way a considered form does.
 */
.app-card {
  width: 100%;
  max-width: var(--plot-card-width);
  padding: 1.75rem;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius-lg);
  background-color: var(--plot-surface);
  box-shadow: var(--plot-shadow);
}

.app-card header {
  text-align: center;
}

.app-card .btn {
  width: 100%;
}

.app-card form > .btn {
  margin-top: 0.75rem;
}

.app-card .auth-hint {
  text-align: center;
}

/*
 * The footer of the shell: the bottom of the viewport is where it is read.
 * It is not part of the box the screen scrolls in — it is the last part of the
 * shell, below the scroll area — so no screen can carry it off the bottom, and
 * it keeps the height it asks for. It paints the surface it is read on, the
 * way the top bar does.
 *
 * It is a strip rather than a band: the height it asks for is the height of
 * the links it holds, so it reads as the edge of the shell under the screen
 * and not as another block of the page. The links are read at the far end of
 * the strip, away from the content they follow.
 */
.app-shell > footer {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: flex-end;
  width: 100%;
  height: var(--plot-shell-footer-height);
  padding: 0 clamp(1rem, 3vw, 2rem);
  border-top: 1px solid var(--plot-hairline);
  background-color: var(--plot-surface-sunken);
}

.app-shell > footer .link {
  font-size: 0.8125rem;
  color: var(--plot-ink-faint);
  text-decoration: none;
}

.app-shell > footer .link:hover {
  color: var(--plot-ink);
}

/*
 * TEMPORARY: the members working in the model the screen shows, read as a
 * horizontal strip in the footer. The strip is held at the leading edge of the
 * footer, so the Contact link stays at the trailing edge. It is taken out once
 * the collaboration of a model is presented by the interface itself.
 */
.footer-collaborators {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 0.375rem;
  margin-right: auto;
  font-size: 0.8125rem;
  color: var(--plot-ink-faint);
}

.footer-collaborators .footer-collaborator-label {
  margin-right: 0.125rem;
  letter-spacing: 0.01em;
}

.footer-collaborators .footer-collaborator {
  padding: 0.0625rem 0.5rem;
  border: 1px solid var(--plot-hairline);
  border-radius: 999px;
  color: var(--plot-ink-muted);
}

/*
 * The Model Navigation: the sections of a model, read as the links of the top
 * bar. The work of the model is read beside the brand; the Settings of the
 * model is no place of that work, so it is offered by the Account Menu rather
 * than as a link beside the sections.
 */
.model-navigation {
  display: flex;
  align-items: center;
  gap: 0.125rem;
  /* The navigation is the height of the bar, so the mark of the current
   * section is drawn on the hairline the bar is closed by. */
  height: 100%;
}

/* A section is a link of the whole height of the bar: the rule of the current
 * one meets the hairline beneath the bar, so the section reads as the head of
 * the body it names. */
.model-navigation-link {
  position: relative;
  display: inline-flex;
  align-items: center;
  height: 100%;
  padding: 0 0.875rem;
  color: var(--plot-ink-muted);
  font-size: 0.9375rem;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
  transition: color 120ms ease;
}

.model-navigation-link:hover {
  color: var(--plot-ink);
}

.model-navigation-link[aria-current="page"] {
  color: var(--plot-ink);
  font-weight: 600;
}

.model-navigation-link[aria-current="page"]::after {
  content: "";
  position: absolute;
  right: 0.875rem;
  bottom: -1px;
  left: 0.875rem;
  height: 2px;
  border-radius: 2px 2px 0 0;
  background-color: var(--plot-accent);
}

/*
 * The Model Layout: the Sidebar Layout of a section, or the fixed menu of the
 * Model Settings interface, beside the body of the interface. The Modelling
 * UI Layout of the sections that model content is the same region: the
 * Dynamic Sidebar Layout beside the body that holds the Modelling Context
 * Viewer over the Canvas Graph.
 *
 * The body is read 0.5rem beside the sidebar: the gutter between the two is the
 * air the workspace is read with on every side of it, so the sidebar and the
 * body beside it are read as one surface rather than as two.
 */
.model-management-layout,
.modelling-ui-region {
  display: flex;
  flex: 1 1 auto;
  align-items: stretch;
  gap: 0.5rem;
  min-height: 0;
}

/*
 * The page spec of a section: the menu or the sidebar of the section is aligned
 * to the left edge of the shell, and the body beside it is read at the page
 * width. Every section that reads a body — Build, Deploy and Settings — reads
 * it the same way, so the workspace of a model is one page rather than a page
 * per section.
 */
.model-management-body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 1.25rem;
  min-width: 0;
}

.model-management-body > * {
  max-width: var(--plot-page-width);
}

/*
 * The Sidebar Layout. The Collapse toggle Button collapses it horizontally:
 * the sidebar keeps its rail and hides its folders and views.
 */
/*
 * The wrapper the `SidebarTree` Vue component is mounted in, inside the column
 * the screen serves. The tree the component renders is read in that column, so
 * the wrapper takes no room of its own: the tree and the footer are columns of
 * the sidebar rather than children of a column inside it.
 */
[data-name="SidebarTree"] {
  display: contents;
}

.sidebar {
  display: flex;
  flex-direction: column;
  flex: 0 0 15rem;
  /* The folders are read 8px clear of the hairline the sidebar is closed by:
   * the margin is the air between a label and the edge it is read against, not
   * a column the sidebar holds. */
  padding-right: 0.5rem;
  /* The foot of the sidebar is read above the Plot Help panel, which is docked
   * to the foot of the screen: the panel is a little over 3rem tall while it
   * is collapsed and the screen holds 1rem below its content, so the panel
   * reaches a little over the 2rem above the foot of the sidebar — and the
   * sidebar keeps 2.5rem below its footer, which is the room the footer and
   * the Collapse toggle Button in it need to be read above the panel. The
   * panel expanded covers the footer the way it covers the folders above it. */
  padding-bottom: 2.5rem;
  border-right: 1px solid var(--plot-hairline);
  /* The Collapse toggle Button collapses the sidebar sideways, so its folders
   * and views are clipped sideways: the tree scrolls in the height the
   * workspace gives the sidebar and the sidebar itself does not. */
  overflow: hidden;
  transition: flex-basis 150ms ease;
}

.sidebar-collapsed {
  flex-basis: 3.25rem;
  padding-right: 0;
}

.sidebar-collapsed .sidebar-tree {
  display: none;
}

/* The folders of the sidebar are the part of it that scrolls, so the footer
 * below them is read at the foot of the sidebar whatever the folders are. */
.sidebar-tree {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}

/*
 * The footer of the sidebar: the Collapse toggle Button and nothing else. The
 * folders the sidebar holds name themselves in the tree above it, so the
 * footer carries no title of its own and is read at the height of the Button
 * it holds — the Button shrinking is the footer shrinking with it. It is the
 * last thing in the sidebar, so it is held at the foot of the column.
 */
.sidebar-footer {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: flex-end;
  margin-top: auto;
}

/*
 * The Collapse toggle Button is a lot smaller than a Button of the interface:
 * it is the control of the sidebar's edge rather than a control of the folders
 * the sidebar holds, so it is read as the arrow alone, held in a square the size
 * of it. It is read off the sidebar it is the control of, so the glyph it is
 * read as is held against the Button of the interface it is declared before.
 */
.sidebar .sidebar-collapse-toggle {
  flex: none;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border-color: transparent;
  background-color: transparent;
  color: var(--plot-ink-faint);
}

.sidebar .sidebar-collapse-toggle:hover {
  color: var(--plot-ink);
}

/* The collapsed sidebar is a rail: the Button that expands it is read in the
 * middle of the rail rather than at the edge of a column it no longer holds. */
.sidebar-collapsed .sidebar-footer {
  justify-content: center;
}

.sidebar-toggle-icon {
  transition: transform 150ms ease;
}

.sidebar-collapsed .sidebar-toggle-icon {
  transform: rotate(180deg);
}

/*
 * The Folder Layout and the View & recursive Subviews it contains. The tree is
 * read at the top of the sidebar: neither the tree nor the list of the views of
 * a folder is set down from the edge it is read at.
 */
.sidebar-tree,
.sidebar-views {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* The subviews of a view are read a step in from the view they are of, and the
 * list of them is the step they are read by: the step is held by each list of
 * subviews rather than by the list of the views of a folder — the views of a
 * folder are read at the edge the folder is read at — so the tree is read one
 * step further in at every level below the views of a folder. */
.sidebar-view > .sidebar-views {
  padding-left: 0.75rem;
}

/* The view a drag carries is read as the view the pointer carries, and where it
 * would be filed is read as the row or the folder the pointer is over: a drop is
 * the file, so the place it lands in is marked rather than the view it picks up.
 *
 * A drop on a row nests the view under that row, so the row is read with the
 * accent held inside its edge. A drop between the rows leads the folder the view
 * is of, so the view is read at the top of the views of that folder, above the
 * views it already holds — the line of a view placed there rather than a row it
 * is filed in. The two are read apart, because the drop a person makes is the one
 * they meant only where the two are told apart. */
.sidebar-row-dragging {
  opacity: 0.5;
}

.sidebar-drop {
  box-shadow: inset 0 0 0 2px var(--plot-accent);
}

.sidebar-views-drop {
  box-shadow: inset 0 2px 0 0 var(--plot-accent);
}

/*
 * The Folder Layout's header: the Add view Button and nothing else, read in the
 * shape the footer of the sidebar is read in — one row, the controls at the end
 * it is read at, the height of the Button it holds.
 *
 * The name of a folder and the surface that toggles it are held in the header
 * but not read in it: the header reads as the Add view Button alone. They are
 * hidden rather than removed, so nothing of the folder is lost by the sidebar
 * not reading it — the name is read again by removing this rule.
 */
.sidebar-folder-header {
  display: flex;
  align-items: center;
  justify-content: flex-end;
}

.sidebar-folder-header .sidebar-item {
  flex: 1 1 auto;
  min-width: 0;
}

.sidebar-folder-header .sidebar-row {
  display: none;
}

/* The Add view Button is read in the shape of the Collapse toggle Button of the
 * footer: the plus alone, held in a square the size of it at the same margin the
 * footer is read at. It is read off the sidebar it is the control of, so the
 * glyph it is read as is held against the Button of the interface it is declared
 * before. */
.sidebar .sidebar-add-view {
  flex: none;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border-color: transparent;
  background-color: transparent;
  color: var(--plot-ink-faint);
}

.sidebar .sidebar-add-view:hover {
  color: var(--plot-ink);
}

/* The actions of a view a person added are read from the Button at the end of
 * the row, which is read while the pointer is over the row or the menu it opened:
 * the row is the view, so the Button that acts on it is held back from it. */
.sidebar .sidebar-item-menu {
  flex: none;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border-color: transparent;
  background-color: transparent;
  color: var(--plot-ink-faint);
  opacity: 0;
  pointer-events: none;
  transition: opacity 120ms ease;
}

.sidebar .sidebar-row:hover .sidebar-item-menu,
.sidebar .sidebar-row:focus-within .sidebar-item-menu,
.sidebar .sidebar-item-menu-open {
  opacity: 1;
  pointer-events: auto;
}

.sidebar .sidebar-item-menu:hover {
  color: var(--plot-ink);
}

/* The dropdown the name of a view is read in is read under the Button it was
 * opened from, in the surface a menu of the interface is read in: it is a
 * Popover, so it is held above the page rather than in the column it is the
 * control of, and the Button it is read under places it. The dropdown of a view
 * a person added holds the deletion of the view beside the name of it, which is
 * read at the start of the actions rather than among them. */
.sidebar-popover {
  position: fixed;
  inset: auto;
  width: 14rem;
  margin: 0;
  padding: 0.75rem;
  border: 1px solid var(--plot-hairline-strong);
  border-radius: var(--plot-radius);
  background-color: var(--plot-surface);
  color: var(--plot-ink);
  box-shadow: 0 8px 24px rgb(17 24 39 / 12%);
}

/* The deletion of the view a dropdown names is read at the start of the actions
 * it holds, apart from the Cancel beside it. */
.sidebar-form-delete {
  margin-right: auto;
}

/* The row of an item is read as the two controls it holds: the caret that folds
 * the item and the Button that names it. The row is read at the height of a
 * named row whether the item holds a name or not, so every row of a tree is
 * read alike. */
.sidebar-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  height: 2.125rem;
  /* The caret and the name are read 8px in from the edge of the sidebar: the
   * margin the Collapse toggle Button of the footer is read at, so the caret
   * is not read against the edge the row begins at. The row is read to the edge
   * the name is read at, so the Button that names the row is read to it. */
  padding: 0 0 0 0.5rem;
  border-radius: var(--plot-radius);
  transition: background-color 120ms ease;
}

.sidebar-row:hover {
  background-color: var(--plot-surface-sunken);
}

/* The view a section models is read in the ink of the model the canvas holds:
 * the sidebar names the view the section is drawn in, and the tint is held
 * over the row the pointer passes over it. */
.sidebar-row-selected,
.sidebar-row-selected:hover {
  background-color: var(--plot-accent-soft);
  color: var(--plot-accent-ink);
}

/* The Button that names a row: the name is read at the width the caret leaves
 * it, so the name of an item is the rest of the row, and the Button is read at
 * the height of the row, so the row of an item is the Button that shows it. */
.sidebar-label {
  display: flex;
  align-items: center;
  align-self: stretch;
  flex: 1 1 auto;
  min-width: 0;
  padding: 0 0.5rem 0 0;
  border: 0;
  background: none;
  color: inherit;
  font-size: 0.875rem;
  text-align: left;
  cursor: pointer;
}

/* The caret of a folder or view is the triangle of the Collapse toggle Button of
 * the Help Panel, turned to the side. It is drawn with a border rather than
 * named, because the icon sheet of the deployment defines a fixed set of icons
 * and the caret of a tree is not one of them — named, it was read as the blank
 * space the name of the item was set in from. */
.sidebar-caret {
  flex: none;
  width: 0;
  height: 0;
  border-top: 0.25rem solid transparent;
  border-bottom: 0.25rem solid transparent;
  border-left: 0.3125rem solid currentColor;
  color: var(--plot-ink-faint);
  transition: transform 150ms ease;
}

/* The caret an item is folded by is the control of the row beside the name: it
 * is read at the size of the caret itself, so a name is read where the name of
 * an item that holds nothing to unfold is read, and the pointer reaches it by a
 * box around the caret that is larger than the caret is drawn in. */
.sidebar-caret-toggle {
  position: relative;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 0.3125rem;
  height: 0.5rem;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.sidebar-caret-toggle::after {
  content: "";
  position: absolute;
  inset: -0.75rem -0.5rem;
}

/* The caret of an item that holds no subview is read in the ink of a control
 * that is not offered: the item is still unfolded, but there is nothing under
 * it to unfold, so the names of the tree read alike. It is no control of the
 * row, so it is never turned. */
.sidebar-caret-disabled {
  color: var(--plot-hairline-strong);
}

.sidebar-caret-toggle[aria-expanded="true"] .sidebar-caret {
  transform: rotate(90deg);
}

.sidebar-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sidebar-edit {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* A name editor is read as one row: the name is read across the row the editor
 * holds rather than at the width of the word that saves it, and the Button that
 * saves it is held at the end of the row. */
.sidebar-edit .input {
  flex: 1 1 auto;
  min-width: 0;
}

/* The Button a name editor is saved by is read as the caret the name is saved
 * by rather than as the word: held at the size of the Add view Button the
 * editor was opened by, so a row an editor is read in is read at the height of
 * a row of the tree. The word the Button holds is not read — the caret is what
 * is read, before the editor is saved by it as well as while it is. It is read
 * off the sidebar it is the control of, so what it is read as is held against
 * the Button of the interface it is declared before. */
.sidebar .sidebar-save {
  flex: none;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  /* The word the Button holds is one of its contents and the caret is another,
   * so the gap a Button of the interface reads its contents with reads the
   * caret beside the middle of the Button rather than at it: the two are read
   * with no gap between them, which is the middle of the Button. */
  gap: 0;
  font-size: 0;
}

/* The mark of the Save Button is drawn rather than named, because the icon
 * sheet of the deployment defines a fixed set of icons and the caret of a name
 * editor is not one of them. It is the caret of a tree of the Sidebar turned to
 * the foot of the Button: the stroke of the top of a box, folded down by the two
 * strokes beside it.
 *
 * The caret is read at the size of the caret of the tree, and it is read at the
 * middle of the Button by the box it is drawn in being the caret itself — there
 * is no ink of it outside that box to hold back to the middle. */
.sidebar-save::after {
  content: "";
  width: 0;
  height: 0;
  border-left: 0.25rem solid transparent;
  border-right: 0.25rem solid transparent;
  border-top: 0.3125rem solid currentColor;
}

/*
 * The fixed menus of the Model Management interfaces: the Model Settings Menu
 * of the settings a model groups and the Model Build Menu of the interfaces a
 * build groups.
 */
.settings-menu,
.build-menu {
  flex: 0 0 15rem;
  padding-right: 1.25rem;
  border-right: 1px solid var(--plot-hairline);
}

.settings-menu-list,
.build-menu-list {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  margin-top: 0.75rem;
}

.settings-menu-item,
.build-menu-item {
  display: flex;
  align-items: center;
  min-height: 2.125rem;
  padding: 0.4rem 0.5rem;
  border-radius: var(--plot-radius);
  color: var(--plot-ink);
  font-size: 0.875rem;
  text-decoration: none;
  transition: background-color 120ms ease, color 120ms ease;
}

.settings-menu-item:hover,
.build-menu-item:hover {
  background-color: var(--plot-surface-sunken);
  color: var(--plot-ink);
}

.settings-menu-item[aria-current="page"],
.build-menu-item[aria-current="page"] {
  background-color: var(--plot-accent-soft);
  color: var(--plot-accent-ink);
  font-weight: 600;
}

/* The interfaces a build groups hold a submenu of their own where an interface
 * presents several lists: the Deliveries interface presents the runs a person
 * still works at apart from the runs a person archived. The submenu is read as
 * a part of the item it is held under rather than as an item of the menu, so it
 * is indented and set in the muted ink of the menu. */
.settings-submenu-list,
.build-submenu-list {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  margin: 0.125rem 0 0.25rem 0.75rem;
  padding-left: 0.5rem;
  border-left: 1px solid var(--plot-hairline);
}

.settings-submenu-item,
.build-submenu-item {
  display: flex;
  align-items: center;
  min-height: 1.875rem;
  padding: 0.3rem 0.5rem;
  border-radius: var(--plot-radius);
  color: var(--plot-ink-muted);
  font-size: 0.875rem;
  text-decoration: none;
  transition: background-color 120ms ease, color 120ms ease;
}

.settings-submenu-item:hover,
.build-submenu-item:hover {
  background-color: var(--plot-surface-sunken);
  color: var(--plot-ink);
}

.settings-submenu-item[aria-current="page"],
.build-submenu-item[aria-current="page"] {
  background-color: var(--plot-accent-soft);
  color: var(--plot-accent-ink);
  font-weight: 600;
}

/* A group of the Model Settings Menu, like the AI item, names the settings it
 * groups rather than being a setting of its own, so it is read as the label of
 * the submenu it leads and takes no room of the item a person selects. */
.settings-menu-group {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  margin-top: 0.25rem;
}

.settings-menu-group-label {
  display: flex;
  align-items: center;
  min-height: 2.125rem;
  padding: 0.4rem 0.5rem;
  color: var(--plot-ink-muted);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/*
 * The Modelling UI Layout: the box the Modelling UI and its interface hold the
 * Plot Canvas in. It fills the body of the interface it is in, so the canvas
 * mount point it holds is a box with a definite height for the canvas to
 * measure and fill. The layout adds no space of its own: the Modelling
 * Context Viewer over it is the whole of the header the canvas has.
 */
.modelling-ui-layout {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-height: 0;
}

/*
 * The body of the Modelling UI Layout: the Modelling Context Viewer over the
 * Canvas Graph. It fills the region beside the Dynamic Sidebar Layout, so the
 * canvas it holds is bounded by the viewport the way the sidebar is. The
 * context over the canvas is a header rather than a surface, so it is set
 * close to the canvas it names.
 */
.modelling-ui-body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 0.375rem;
  min-width: 0;
  min-height: 0;
}

/*
 * The Modelling Context Viewer: the Model Lineage of the element in focus,
 * the root of the lineage first and the element the screen presents last, read
 * as the chain that leads to the element. It is a header of the screen rather
 * than a surface of its own, so it takes the height it asks for and leaves the
 * rest to the screen.
 */
.modelling-context-viewer {
  flex: none;
}

/* The chain of a lineage: the elements that lead to an element, read in one
 * line where the box allows it and wrapped where it does not. The chain is the
 * Modelling Context of a screen and the title of a bundle of the deliveries of a
 * model, so it is laid out once rather than once per reader. */
.modelling-context-path {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.125rem;
  min-width: 0;
  line-height: 1.25;
}

/*
 * The Model Lineage Browser: the index page of the Design and Build sections,
 * which browses the Model Lineage as a tree of the Strategy Elements and the
 * Implementation elements of the model.
 *
 * The browser is one surface of a fixed width, aligned to the left of the body
 * of the section rather than stretched across the workspace: a level is read
 * rather than spread. A level is nested under the row it was reached from, so
 * the row that leads to it stays readable above it and the branch below it is
 * indented under the row rather than replacing it.
 */
.lineage-browser {
  flex: none;
  width: 100%;
  max-width: var(--plot-browser-width);
  margin: 0.5rem 0 0;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius-lg);
  background-color: var(--plot-surface);
  box-shadow: var(--plot-shadow);
  overflow: hidden;
}

.lineage-browser-branch {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  padding: 0.5rem;
}

/* The level below a row is read indented under it, and the hairline beside it
 * is the lineage the level hangs from. */
.lineage-browser-node > .lineage-browser-branch {
  margin-left: 1.375rem;
  padding: 0.125rem 0 0.25rem 0.375rem;
  border-left: 1px solid var(--plot-hairline);
}

.lineage-browser-list {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The Implementation elements of a level are read below its Strategy Elements:
 * the hairline is the only thing that separates the two. */
.lineage-browser-list + .lineage-browser-list {
  margin-top: 0.25rem;
  padding-top: 0.375rem;
  border-top: 1px solid var(--plot-hairline);
}

.lineage-browser-node {
  display: flex;
  flex-direction: column;
  border-radius: var(--plot-radius);
}

/*
 * A row: the glyph of the Element it names, the name itself, the type it is of,
 * and the chevron that leads into the level below it — pointing down once the
 * level is open. The row is one target, so the pointer reacts to the whole of
 * it, and the row of an Implementation element carries the grip it is dragged
 * by.
 */
.lineage-browser-row {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  padding-right: 0.5rem;
  border-radius: var(--plot-radius);
}

.lineage-browser-row:hover {
  background-color: var(--plot-surface-muted);
}

/*
 * The place a drop would land: the edge of the row the dragged element would be
 * read before or after, held in the accent as the drag goes.
 */
.lineage-browser-row-drop-before {
  box-shadow: inset 0 2px 0 0 var(--plot-accent);
}

.lineage-browser-row-drop-after {
  box-shadow: inset 0 -2px 0 0 var(--plot-accent);
}

.lineage-browser-node[draggable="true"] {
  cursor: grab;
}

.lineage-browser-node[draggable="true"]:active {
  cursor: grabbing;
}

.lineage-browser-grip {
  flex: none;
  width: 0.75rem;
  height: 1.25rem;
  margin-left: 0.4375rem;
  border-radius: 1px;
  background-image: radial-gradient(circle, var(--plot-ink-faint) 1px, transparent 1px);
  background-size: 0.25rem 0.25rem;
  opacity: 0.45;
}

.lineage-browser-item {
  display: flex;
  flex: 1 1 auto;
  align-items: center;
  gap: 0.625rem;
  min-width: 0;
  padding: 0.625rem;
  border: 0;
  border-radius: var(--plot-radius);
  background-color: transparent;
  color: var(--plot-ink);
  font: inherit;
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1.3;
  text-align: left;
  cursor: pointer;
}

.lineage-browser-item .element-label {
  gap: 0.625rem;
}

/* The actions of a row stand at the end of it rather than in the text of it. */
.lineage-browser-item .icon-button {
  margin-left: auto;
}

.lineage-browser-item .element-label-icon {
  width: 1.5rem;
  height: 1.5rem;
}

.lineage-browser-item .element-label-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.lineage-browser-item-static {
  cursor: default;
}

.lineage-browser-item:focus-visible {
  outline: none;
  box-shadow: var(--plot-ring);
}

/*
 * The action of a row: the design of a Plateau a Design opens, and the
 * Repository of a Plateau a Build delivers through — a glyph of the action
 * beside the name, so the row browses the lineage and the glyph opens the
 * Element in the section it is read in.
 */
/*
 * A glyph that stands for an action of a row is the same box wherever it is
 * read: the pen of an Environment Variable is the pen of a Model Element.
 */
.icon-button {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border: 0;
  border-radius: var(--plot-radius-sm);
  background-color: transparent;
  color: var(--plot-ink-muted);
  cursor: pointer;
}

.icon-button svg {
  width: 1.125rem;
  height: 1.125rem;
}

.icon-button:hover {
  background-color: var(--plot-surface-sunken);
  color: var(--plot-accent);
}

.icon-button:focus-visible {
  outline: none;
  box-shadow: var(--plot-ring);
}

.icon-button[aria-expanded="true"] {
  background-color: var(--plot-surface-sunken);
  color: var(--plot-accent);
}

.lineage-browser-pen {
  text-decoration: none;
}

.lineage-browser-action:disabled {
  color: var(--plot-ink-faint);
  opacity: 0.4;
  cursor: default;
}

/* The marker of a level is the Button the level is opened and closed with: it
 * carries no box of its own, so the marker of the row is what the person points
 * at rather than a control drawn beside it. */
.lineage-browser-toggle {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: none;
  background: none;
  color: inherit;
  cursor: pointer;
}

.lineage-browser-toggle:focus-visible {
  outline: none;
  border-radius: 0.25rem;
  box-shadow: var(--plot-ring);
}


.lineage-browser-chevron {
  flex: none;
  width: 0.375rem;
  height: 0.375rem;
  margin-right: 0.375rem;
  border-top: 1.5px solid var(--plot-ink-faint);
  border-right: 1.5px solid var(--plot-ink-faint);
  transform: rotate(45deg);
  transition: transform 120ms ease;
}

.lineage-browser-row[data-expanded="true"] .lineage-browser-chevron {
  transform: rotate(135deg);
}

[data-sortable-item].sortable-dragging {
  opacity: 0.4;
}

/*
 * The elements of the context: each is read as a row of the Model Lineage
 * Browser reads an Element — the icon of its element type beside its name — one
 * size smaller, because the context is the header of the screen rather than the
 * screen itself.
 *
 * The elements the screen's element is reached through are levels of the
 * browser, so they are links to the index page of the section expanded at them,
 * and the element the screen presents is read rather than browsed.
 */
.modelling-context-field {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  min-width: 0;
}

.modelling-context-separator {
  color: var(--plot-ink-faint);
  font-size: 0.8125rem;
}

.modelling-context-item {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
  padding: 0.1875rem 0.375rem;
  border-radius: var(--plot-radius);
  color: var(--plot-ink);
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1.3;
  text-decoration: none;
}

.modelling-context-item .element-label {
  gap: 0.5rem;
}

.modelling-context-item .element-label-icon {
  width: 1.375rem;
  height: 1.375rem;
}

.modelling-context-item .element-label-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

a.modelling-context-item:hover {
  background-color: var(--plot-surface-muted);
}

a.modelling-context-item:focus-visible {
  outline: none;
  box-shadow: var(--plot-ring);
}

/* The element the screen presents is no level of the browser, so it is read
 * rather than pointed at. */
.modelling-context-item-selected {
  cursor: default;
}

/*
 * The Element Label: an Element as the icon of its element type beside its
 * name. The icon is the canonical glyph the modelling language defines, drawn
 * at the size of the label's line, so the label sits in the line it is read in
 * rather than setting its height.
 */
.element-label {
  display: inline-flex;
  align-items: center;
  gap: 0.3125rem;
  min-width: 0;
  white-space: nowrap;
}

.element-label-icon {
  display: inline-flex;
  flex: none;
  width: 1rem;
  height: 1rem;
}

.element-label-icon svg {
  display: block;
  width: 100%;
  height: 100%;
}

.element-label-icon svg [stroke="#000000"] {
  stroke: currentcolor;
}

.element-label-icon svg [fill="#000000"] {
  fill: currentcolor;
}

/*
 * The Canvas Layout of the Modelling UI: the canvas fills the box the layout
 * that sizes it gives it, framed like any other surface.
 */
.modelling-ui {
  flex: 1 1 auto;
  min-height: 24rem;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius-lg);
  background-color: var(--plot-surface);
  overflow: hidden;
}

/*
 * On narrow screens a sidebar stacks above the body of its interface instead
 * of squeezing it, and the horizontal collapse only applies side by side.
 */
@media (max-width: 768px) {
  .model-management-layout,
  .modelling-ui-region {
    flex-direction: column;
  }

  /* The brand cell gives up the width of the sidebar the navigation is aligned
   * with: the sidebar stacks on a narrow screen, so there is no width to hold
   * the navigation at. */
  .app-shell-brand-cell {
    flex: 0 1 auto;
  }

  .sidebar,
  .sidebar-collapsed,
  .settings-menu,
  .build-menu {
    flex-basis: auto;
    width: 100%;
    padding-right: 0;
    border-right: 0;
    border-bottom: 1px solid var(--plot-hairline);
    padding-bottom: 1rem;
  }
}

/*
 * The one spec of a button: every action of Plot is the same box, and what tells
 * the actions of a screen apart is the weight they carry rather than the shape
 * of them. The action a form commits is filled with the accent, the action
 * beside it is a bordered box of the surface, and the action that gives
 * something up is read in the danger colour without carrying it until it is
 * pointed at.
 */
.btn {
  display: inline-flex;
  box-sizing: border-box;
  flex: none;
  align-items: center;
  justify-content: center;
  gap: 0.375rem;
  height: 1.75rem;
  padding: 0 0.75rem;
  border: 1px solid transparent;
  border-radius: var(--plot-radius);
  background-color: transparent;
  color: var(--plot-ink);
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  box-shadow: none;
  transition:
    background-color 120ms ease,
    border-color 120ms ease,
    color 120ms ease;
}

.btn:focus-visible {
  outline: none;
  box-shadow: var(--plot-ring);
}

.btn:disabled,
.btn[disabled] {
  opacity: 0.55;
  cursor: default;
}

.btn-primary {
  border-color: var(--plot-accent);
  background-color: var(--plot-accent);
  color: var(--plot-surface);
}

.btn-primary:hover:not(:disabled) {
  border-color: var(--plot-accent-ink);
  background-color: var(--plot-accent-ink);
}

.btn-ghost {
  border-color: var(--plot-hairline-strong);
  background-color: var(--plot-surface);
  color: var(--plot-ink);
}

.btn-ghost:hover:not(:disabled) {
  border-color: var(--plot-ink-faint);
  background-color: var(--plot-surface-muted);
}

.btn-danger {
  border-color: transparent;
  background-color: transparent;
  color: var(--plot-danger);
}

.btn-danger:hover:not(:disabled) {
  border-color: color-mix(in oklab, var(--plot-danger) 45%, var(--plot-hairline));
  background-color: color-mix(in oklab, var(--plot-danger) 8%, var(--plot-surface));
}

.btn-sm {
  height: 1.5rem;
  padding: 0 0.5rem;
  font-size: 0.75rem;
}

/*
 * The one spec of a form: a field is the name it is read by above the control
 * it is corrected with, and the actions that write the record stand under the
 * fields of it. Every form of Plot is read this way — the credentials of an AI
 * Model Service, the invitation of a Collaborator, the Environment Variable of
 * a Repository, and the Delivery Run of a Delivery Source — so a field of one
 * form is the field of the next, glyphs and all.
 */
.form-body {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.form-field {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
}

.form-field-label,
.form-fields dt {
  color: var(--plot-ink-faint);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* The control a field is corrected with: the same box whether the field is
 * typed, chosen, or written over a few lines. */
.form-control {
  box-sizing: border-box;
  width: 100%;
  height: 1.75rem;
  padding: 0 0.5rem;
  border: 1px solid var(--plot-hairline-strong);
  border-radius: var(--plot-radius);
  background-color: var(--plot-surface);
  color: var(--plot-ink);
  font: inherit;
  font-size: 0.8125rem;
}

.form-control:hover {
  border-color: var(--plot-ink-faint);
}

.form-control:focus,
.form-control:focus-within {
  border-color: var(--plot-accent-edge);
  box-shadow: var(--plot-ring);
  outline: none;
}

.form-control::placeholder {
  color: var(--plot-ink-faint);
}

/* The field of a value the deployment keeps a secret: the box of a field of the
 * interface, with the control that reveals the value in it, so the value is
 * read as any other value of a form is read rather than as a field of the
 * browser's password manager. */
/* The choice of reading the environment of a Repository as the rows it is held
 * in or as the document it is: it is a mark of the Repository rather than an
 * action of it, so it is read as a switch of the head. */
.list-mode {
  flex: none;
  padding: 0 0.375rem;
  height: 1.75rem;
  border: 1px solid var(--plot-hairline-strong);
  border-radius: var(--plot-radius-sm);
  background-color: var(--plot-surface);
  color: var(--plot-ink-muted);
  font: inherit;
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  cursor: pointer;
}

.list-mode:hover {
  color: var(--plot-ink);
}

.list-mode[aria-pressed="true"] {
  border-color: var(--plot-accent-edge);
  color: var(--plot-ink);
}

/* The environment of a Repository as one document: the field is a field of the
 * interface rather than a page of its own, so it is drawn in the colours the
 * interface is read in, at the height of the rows it stands in place of. */
.plot-environment-editor {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.75rem 0.5rem;
}

.plot-environment-editor-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}

.plot-environment-editor-body {
  height: 22rem;
  overflow: auto;
  border: 1px solid var(--plot-hairline-strong);
  border-radius: var(--plot-radius);
  background-color: var(--plot-surface);
}

.plot-environment-editor-body .cm-editor {
  height: 100%;
  font-size: 0.8125rem;
  background-color: var(--plot-surface);
  color: var(--plot-ink);
}

.plot-environment-editor-body .cm-editor.cm-focused {
  outline: none;
}

.plot-environment-editor-body .cm-scroller {
  font-family: var(--plot-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  line-height: 1.5;
}

.plot-environment-editor-body .cm-content {
  padding: 0.5rem 0;
}

.plot-environment-editor-body .cm-gutters {
  border-right: 1px solid var(--plot-hairline);
  background-color: var(--plot-surface);
  color: var(--plot-ink-faint);
}

.plot-environment-editor-body .cm-activeLine {
  background-color: var(--plot-hover, rgba(0, 0, 0, 0.03));
}

.plot-environment-editor-body .cm-selectionBackground,
.plot-environment-editor-body .cm-content ::selection {
  background-color: var(--plot-selection, rgba(99, 102, 241, 0.18));
}

.plot-secret-box {
  position: relative;
  display: flex;
  align-items: center;
}

.plot-secret-input {
  padding-right: 2rem;
}

.plot-secret-trigger {
  position: absolute;
  right: 0.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: 0;
  border-radius: var(--plot-radius);
  background: none;
  color: var(--plot-ink-faint);
  cursor: pointer;
}

.plot-secret-trigger:hover {
  color: var(--plot-ink);
}

/* The mark of the control is a dot while the value is read and a ring while it
 * is masked, so the value is revealed by the control it is asked for with
 * rather than by an icon of its own. */
.plot-secret-eye {
  width: 0.5rem;
  height: 0.5rem;
  border: 1px solid currentColor;
  border-radius: 50%;
}

.plot-secret-trigger[data-state="visible"] .plot-secret-eye {
  background-color: currentColor;
}

textarea.form-control {
  height: auto;
  min-height: 4rem;
  padding: 0.375rem 0.5rem;
  line-height: 1.4;
}

.form-control-error {
  border-color: var(--plot-danger);
}


/* The header of a field that holds a value the verifier refuses is read in the
 * colour of the refusal, so the field is read as one to correct rather than as
 * one the action of the row will take. */
.form-field-label-invalid {
  color: var(--plot-danger);
}

/* The box of a name that is served below a Domain: the part a person names is
 * typed, and the Domain it is appended to is read beside it, so the field is one
 * control rather than a field and a label. */
.form-control-enclosed {
  display: flex;
  align-items: center;
  gap: 0.125rem;
  box-sizing: border-box;
  width: 100%;
  height: 1.75rem;
  padding: 0 0.5rem;
  border: 1px solid var(--plot-hairline-strong);
  border-radius: var(--plot-radius);
  background-color: var(--plot-surface);
}

.form-control-enclosed:hover {
  border-color: var(--plot-ink-faint);
}

.form-control-enclosed:focus-within {
  border-color: var(--plot-accent-edge);
  box-shadow: var(--plot-ring);
}

.form-control-enclosed-error {
  border-color: var(--plot-danger);
}

.form-control-enclosed-input {
  flex: 1;
  min-width: 0;
  height: 100%;
  padding: 0;
  border: 0;
  background-color: transparent;
  color: var(--plot-ink);
  font: inherit;
  font-size: 0.8125rem;
  outline: none;
}

.form-control-enclosed-input::placeholder {
  color: var(--plot-ink-faint);
}

.form-control-enclosed-input:disabled {
  color: var(--plot-ink-faint);
}

.form-control-suffix {
  flex: none;
  color: var(--plot-ink-faint);
  font-size: 0.8125rem;
  white-space: nowrap;
}

/* A field that is a choice rather than a value: the box is read beside what it
 * chooses rather than above it. */
.form-check {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  min-width: 0;
  white-space: nowrap;
  color: var(--plot-ink-muted);
  font-size: 0.8125rem;
  cursor: pointer;
}

.form-check input {
  width: 0.875rem;
  height: 0.875rem;
  margin: 0;
  accent-color: var(--plot-accent);
}

.form-error {
  color: var(--plot-danger);
  font-size: 0.75rem;
}

/* The fields of a record are read on the line they are corrected at rather than
 * stacked: the fields of a record of a list, and the fields of the form of it. */
.form-fields {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
  gap: 0.5rem 1rem;
  margin: 0 0 0.5rem;
}

.form-group {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

/* The fields of a form are read in two columns where they are short enough to
 * stand beside each other, and across the form where they are not. */
.form-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.75rem 1rem;
}

.form-grid > * {
  min-width: 0;
}

.form-grid-full {
  grid-column: 1 / -1;
}

/* The two branches a Deployment serves are read as two parts of one form: the
 * part that stages a delivery and the part that produces it stand side by side,
 * because they are the same fields of two roles rather than six fields of one.
 * The part is enclosed so the fields of a role are read together. */
.deploy-part {
  display: grid;
  gap: 0.75rem;
  align-content: start;
  min-width: 0;
  padding: 0.75rem 0.875rem 0.875rem;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius);
  background-color: var(--plot-surface-muted);
}

/* The head of a part reads the title of the role beside the choice that
 * activates the half, because the half a person does not activate is a half
 * whose fields are not read. */
.deploy-part-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}

.deploy-part-title {
  margin: 0;
  color: var(--plot-ink-muted);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* A branch runs on its own Machine, so the steps of one branch are read at the
 * branch rather than at the Deployment: the actions of a part sit under the three
 * fields of the role. */
/* The Machine of a branch is the compute of the provider, so the handle and the
 * address of the instance a launch made are read under the fields of the branch
 * rather than at the provider alone. */
.deploy-part-machine {
  margin: 0;
  color: var(--plot-ink-faint);
  font-family: var(--plot-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 0.75rem;
  overflow-wrap: anywhere;
}

/* The half of a Deployment that is not activated is read as the note that says
 * what the Deployment serves, so the part is not an empty box of fields. */
.deploy-part-note {
  margin: 0;
  color: var(--plot-ink-faint);
  font-size: 0.8125rem;
}

.deploy-part-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  padding-top: 0.25rem;
  border-top: 1px solid var(--plot-hairline);
}

/* The name of a variable is read at half the width of the form, and the choice
 * beside it keeps its own width: a form too narrow to hold both at that width
 * gives the name the width the choice leaves rather than pushing it out. */
.form-inline {
  display: grid;
  grid-template-columns: minmax(0, 50%) auto auto;
  align-items: end;
  justify-content: start;
  gap: 0.25rem 0.75rem;
}

.form-values {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.5rem;
}

.form-values[data-split="true"] {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

.form-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-top: 0.25rem;
}

/* The action that gives a record up stands apart from the actions that write
 * it: it leads the actions of the form, and the way out of the form and the
 * commit of it are read together at the end of the row. */
.form-actions .btn-danger {
  margin-right: auto;
}

.form-field-value,
.form-fields dd {
  margin: 0.125rem 0 0;
  overflow-wrap: anywhere;
  font-size: 0.875rem;
}

.form-fields code {
  font-size: 0.8125rem;
}

/* The state a record is at is read at the icon of it rather than typed: the
 * field of it stands beside the name of the record and carries the height of the
 * control beside it. */
.form-status {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  height: 1.75rem;
  font-size: 0.8125rem;
  font-weight: 600;
}

.form-status-icon {
  width: 1.0625rem;
  height: 1.0625rem;
  flex: none;
}

.form-status-verified {
  color: var(--plot-accent-ink);
}

.form-status-unverified {
  color: var(--plot-ink-muted);
}

/* A choice between the two values of a field is a switch rather than a select:
 * the values of the field are read beside each other, and the value the record
 * holds is the one the switch presents. */
.form-switch {
  display: inline-flex;
  box-sizing: border-box;
  height: 1.75rem;
  padding: 0.125rem;
  border: 1px solid var(--plot-hairline);
  border-radius: 999px;
  background-color: var(--plot-surface-sunken);
}

.form-switch-option {
  display: inline-flex;
  align-items: center;
  cursor: pointer;
}

.form-switch-option input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.form-switch-option span {
  padding: 0 0.625rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.375rem;
  color: var(--plot-ink-muted);
}

.form-switch-option input:checked + span {
  background-color: var(--plot-surface);
  box-shadow: var(--plot-shadow);
  color: var(--plot-ink);
}

/*
 * The providers of the Sign In and Sign Up interfaces, as quiet, bordered
 * buttons, so the accent stays with the primary action of a screen.
 */
.auth-actions {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  max-width: 22rem;
  margin-top: 0.5rem;
}

.provider-button {
  justify-content: center;
  height: 2.25rem;
  border: 1px solid var(--plot-hairline-strong);
  border-radius: var(--plot-radius);
  background-color: var(--plot-surface);
  color: var(--plot-ink);
  font-weight: 500;
  box-shadow: var(--plot-shadow);
}

.provider-button:hover {
  border-color: var(--plot-ink-faint);
  background-color: var(--plot-surface-muted);
}

.auth-hint {
  margin-top: 1rem;
  font-size: 0.875rem;
}

.list {
  padding: 0;
}

.list-row {
  border-bottom: 1px solid var(--plot-hairline);
}

.list-row:last-child {
  border-bottom: 0;
}

.alert {
  border-radius: var(--plot-radius-lg);
  border-color: var(--plot-hairline);
  box-shadow: var(--plot-shadow);
}

/* The status and empty states of a screen. */
.app-shell-main [role="status"],
.app-shell-main [role="alert"] {
  color: var(--plot-ink-muted);
}

/*
 * The Identity of the Top Level Navigation: the Sign In link a visitor sees,
 * and the Account Menu an active user sees. The Account Menu is the Account
 * Management interface, which the Pulldown technology presents as a menu.
 */
.identity-menu {
  position: relative;
}

/* The trigger of a pulldown is one fixed box whatever it presents: the Session
 * menu and the Account Menu stand beside each other as two buttons of the same
 * size, so the cell of the identity reads as two artefacts of one interface
 * rather than as an icon and an avatar. */
.identity-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.5rem;
  width: 4rem;
  height: 2.25rem;
  padding: 0 0.625rem;
  border-radius: var(--plot-radius);
  color: var(--plot-ink);
  font-size: 0.875rem;
  font-weight: 500;
  cursor: pointer;
  list-style: none;
  transition: background-color 120ms ease, box-shadow 120ms ease;
}

.identity-trigger::-webkit-details-marker {
  display: none;
}

.identity-trigger:hover {
  background-color: var(--plot-surface-sunken);
}

.identity-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 9999px;
  background-color: var(--plot-accent-soft);
  color: var(--plot-accent-ink);
  font-size: 0.8125rem;
  font-weight: 600;
}

.identity-caret {
  width: 0;
  height: 0;
  border-left: 0.25rem solid transparent;
  border-right: 0.25rem solid transparent;
  border-top: 0.3rem solid var(--plot-ink-faint);
  transition: transform 150ms ease;
}

.identity-menu[open] .identity-caret {
  transform: rotate(180deg);
}

.identity-dropdown {
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  z-index: 30;
  width: 16rem;
  padding: 0.5rem;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius-lg);
  background-color: var(--plot-surface);
  box-shadow: 0 8px 24px rgb(17 24 39 / 10%);
}

.identity-section + .identity-section {
  margin-top: 0.25rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--plot-hairline);
}

/* Whatever leads the menu leads it: a separator over nothing reads as a
 * section that failed to render. */
.identity-dropdown > :first-child {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

.identity-section-title {
  padding: 0.25rem 0.5rem;
  color: var(--plot-ink-faint);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.identity-list {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.identity-item {
  display: block;
  padding: 0.4rem 0.5rem;
  border-radius: var(--plot-radius);
  color: var(--plot-ink-muted);
  font-size: 0.875rem;
  text-decoration: none;
  transition: background-color 120ms ease, color 120ms ease;
}

.identity-item:hover {
  background-color: var(--plot-surface-sunken);
  color: var(--plot-ink);
}

.identity-item[aria-current="page"] {
  background-color: var(--plot-accent-soft);
  color: var(--plot-accent-ink);
  font-weight: 600;
}

.identity-collaborator {
  display: flex;
  flex-direction: column;
  padding: 0.4rem 0.5rem;
}

.identity-collaborator-name {
  color: var(--plot-ink);
  font-size: 0.875rem;
}

.identity-collaborator-email {
  color: var(--plot-ink-faint);
  font-size: 0.75rem;
}

.identity-footer {
  margin-top: 0.25rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--plot-hairline);
}

.identity-sign-out {
  display: block;
  padding: 0.4rem 0.5rem;
  border-radius: var(--plot-radius);
  color: var(--plot-danger);
  font-size: 0.875rem;
  font-weight: 500;
  text-decoration: none;
  transition: background-color 120ms ease;
}

.identity-sign-out:hover {
  background-color: var(--plot-surface-sunken);
}

/*
 * The Session menu of the Top Level Navigation: the Session button beside the
 * Identity artifact, the sessions running in the model, the members working in
 * the session the member works in, and the Session dialog the member manages
 * and stops the session they work in from.
 *
 * The menu is a pulldown of the same construction as the Account Menu, so it
 * draws on the identity classes and differs from the Account Menu in the icon
 * its trigger reads rather than in the menu it presents. The trigger is outlined
 * while a session runs in the model, so the members read that their team works
 * in one without opening the menu.
 *
 * The row of video screens of the session is held beside the Session menu
 * rather than in it. The row is laid out in reverse, because it grows from
 * right to left: the member the row is presented to is rightmost, so their
 * screen is the first the row holds and the members that join it work in it to
 * their left.
 */
.identity {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.session-trigger-icon {
  flex: none;
  width: 1.5rem;
  height: 1.5rem;
}

/* A session that runs in the model is marked with the outline of the Session
 * trigger rather than with a fill: the trigger is a button beside the avatar
 * rather than an artefact of its own, and the outline says that the button
 * holds something running without competing with the avatar for the eye. */
.session-menu-active .identity-trigger {
  color: var(--plot-accent-ink);
  box-shadow: inset 0 0 0 1px var(--plot-accent-edge);
}

/* The member the menu is presented to, in the list of members working in the
 * session they work in. */
.session-member-you {
  color: var(--plot-ink-faint);
  font-size: 0.75rem;
}

.session-videos {
  display: flex;
  align-items: center;
}

.session-videos-row {
  display: flex;
  flex-direction: row-reverse;
  align-items: center;
  gap: 0.375rem;
}

/* A screen of the row: a screen of a camera read square, in the height the top
 * bar leaves it. The top bar is 4.5rem tall, which is 4.1875rem of content
 * once its hairline is taken out, and the screen keeps 2px of the row above and
 * below it. */
.session-member {
  position: relative;
  height: 4.1875rem;
  aspect-ratio: 1 / 1;
  margin: 0;
  overflow: hidden;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius-sm);
  background-color: var(--plot-surface-sunken);
}

.session-video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background-color: var(--plot-surface-sunken);
}

/* The screen a member plays in is only shown while their camera is on, so the
 * switched-off camera the screen presents otherwise is the control alone. */
.session-video[hidden] {
  display: none;
}

/* The camera of the member the row is presented to behaves like the preview of
 * a phone camera: it is mirrored, so it reads like a mirror. Only the screen is
 * mirrored — the frames the encoder takes from the camera, and therefore what
 * the other members see, are not. */
.session-video-mirrored {
  transform: scaleX(-1);
}

/* The camera a member of the session presents when it is off: the screen shows
 * a switched-off camera rather than a blank one, the way the screen of the
 * member itself does until they turn it on. */
.session-member-camera-off {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--plot-ink-faint);
  background-color: var(--plot-surface-sunken);
  pointer-events: none;
}

.session-member-camera-off[hidden] {
  display: none;
}

/* The marks of a member's screen: a collaborator who works at a URL other than
 * the URL of this screen is marked with a yellow dot, a collaborator someone
 * follows is marked with a red ring, and the collaborator a member follows is
 * marked with a red arrow, which points at the screen they follow. The marks
 * describe the screen rather than control it, so they are drawn over the media
 * and take no pointer events. */
.session-member-dot {
  position: absolute;
  right: 0.25rem;
  bottom: 0.25rem;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background-color: var(--plot-attention);
  box-shadow: 0 0 0 1px rgb(17 24 39 / 35%);
  pointer-events: none;
}

.session-member-dot[hidden] {
  display: none;
}

/* The screen of a collaborator someone follows: the ring replaces the hairline
 * of the screen rather than adding a second border, so the row keeps the quiet
 * frame of the video. */
.session-member-led {
  border-color: var(--plot-danger);
  box-shadow: 0 0 0 1px color-mix(in oklab, var(--plot-danger) 30%, transparent);
}

/* The screen of a collaborator who follows someone: the arrow sits in the
 * bottom left corner, opposite the dot, and points at the screen they follow. */
.session-member-follows-left::after,
.session-member-follows-right::after {
  content: "";
  position: absolute;
  left: 0.25rem;
  bottom: 0.25rem;
  width: 0;
  height: 0;
  border-top: 0.21875rem solid transparent;
  border-bottom: 0.21875rem solid transparent;
  pointer-events: none;
}

.session-member-follows-left::after {
  border-right: 0.375rem solid var(--plot-danger);
}

.session-member-follows-right::after {
  border-left: 0.375rem solid var(--plot-danger);
}

.session-camera {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  background-color: transparent;
  color: var(--plot-ink-faint);
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}

.session-camera:hover {
  color: var(--plot-ink);
  background-color: color-mix(in oklab, var(--plot-ink) 12%, transparent);
}

/* The control is the switched-off camera the screen presents, so it disappears
 * with the video it starts: the video is turned off from the Account Menu. */
.session-camera[hidden] {
  display: none;
}

.session-camera-icon {
  width: 1.5rem;
  height: 1.5rem;
}

/* What the conference of the session has to say: nothing while the camera is
 * off or on, and what went wrong when it did. */
.session-status {
  margin: 0;
  color: var(--plot-danger);
  font-size: 0.75rem;
}

/* The Session menu offers actions of its own — starting, managing and leaving
 * a session — which are Buttons rather than links to a screen of the model,
 * and carry the icon of what they act on. */
.identity-action {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  border: 0;
  background-color: transparent;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.identity-action-icon {
  flex: none;
  width: 1rem;
  height: 1rem;
}

/* A session running in the model, which the members of the model join and
 * leave between: the state of the session, the members working in it, when it
 * started, and the actions the member takes on it. Every row of the section is
 * the same height, so the session the member starts reads as one of the
 * sessions rather than as another kind of item. */
.identity-session {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  height: 2.25rem;
  margin-bottom: 0.125rem;
  padding: 0 0.5rem;
  border-radius: var(--plot-radius);
  background-color: var(--plot-surface-sunken);
}

/* The session the member works in is marked with the check of the state and
 * the accent of the row; a session they may join is marked with a dot. */
.identity-session-state {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 1rem;
  height: 1rem;
}

.identity-session-state-icon {
  width: 1rem;
  height: 1rem;
  color: var(--plot-accent);
}

.identity-session-dot {
  width: 0.4375rem;
  height: 0.4375rem;
  border-radius: 9999px;
  background-color: var(--plot-ink-faint);
}

.identity-session-current {
  background-color: var(--plot-accent-soft);
}

/* The members working in the session and the moment it started, which the
 * icons name so the row carries no sentence of its own. */
.identity-session-count,
.identity-session-time {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  color: var(--plot-ink-muted);
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
}

.identity-session-time {
  margin-left: auto;
}

.identity-session-icon {
  flex: none;
  width: 0.875rem;
  height: 0.875rem;
  color: var(--plot-ink-faint);
}

/* The actions of a session row are the icons of the action rather than its
 * name: the arrow into a session joins it, the arrow out of it leaves it, the
 * arrows between sessions switch to it, and the pen ends the session the
 * member started and works in. A row carries one action rather than several:
 * the member that started the session they work in has the pen of its row
 * rather than a leave of it, and the sessions that run beside it offer no
 * switch. */
.identity-session .identity-item {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: 0;
  border-radius: var(--plot-radius-sm);
  background-color: transparent;
  font: inherit;
  cursor: pointer;
  transition: background-color 120ms ease;
}

.identity-session .identity-item:hover {
  background-color: var(--plot-surface);
}

.identity-session .identity-item:hover .identity-session-icon {
  color: var(--plot-ink);
}

/* The actions are the icons of the row rather than its words, so they are read
 * at the size of the icon that names them. */
.identity-session .identity-item .identity-session-icon {
  width: 1.125rem;
  height: 1.125rem;
}

/* The name of the action follows the pointer: the row reads as icons, and the
 * action an icon takes is named on hover and on keyboard focus. */
.identity-session .identity-item[data-label] {
  position: relative;
}

.identity-session .identity-item[data-label]::after {
  content: attr(data-label);
  position: absolute;
  right: 0;
  bottom: calc(100% + 0.25rem);
  z-index: 1;
  padding: 0.125rem 0.375rem;
  border-radius: var(--plot-radius-sm);
  background-color: var(--plot-ink);
  color: var(--plot-surface);
  font-size: 0.6875rem;
  font-weight: 500;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(2px);
  pointer-events: none;
  transition: opacity 100ms ease, transform 100ms ease;
}

.identity-session .identity-item[data-label]:hover::after,
.identity-session .identity-item[data-label]:focus-visible::after {
  opacity: 1;
  transform: translateY(0);
}

/* The New Session command closes the list of the sessions that run, and is the
 * height of the sessions it stands with. */
.identity-session-new {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  height: 2.25rem;
  padding: 0 0.5rem;
}

/* The Session dialog holds no form, so the actions lead it. */
.session-dialog .plot-dialog-actions {
  margin-top: 1.25rem;
}

/* The collaborators a planned session invites: the members of the model
 * beside the member who plans it. */
.session-invitees {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 0.125rem;
  min-height: 0;
  overflow-y: auto;
  margin: 0;
  padding: 0;
  border: 0;
}

.session-invitee {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.4375rem 0.5rem;
  border-radius: var(--plot-radius-sm);
  font-size: 0.875rem;
  cursor: pointer;
}

.session-invitee:hover {
  background-color: var(--plot-surface-sunken);
}

.session-invitee input {
  width: 1rem;
  height: 1rem;
}

.session-invitee-email {
  margin-left: auto;
  color: var(--plot-ink-faint);
  font-size: 0.8125rem;
}

/* The New Session dialog holds the two processes a session is started through
 * and the participants of both, so it is wider than a dialog that asks one
 * thing: the day and the timeslot of a planned session stand beside each other
 * without crowding the participants below them. It holds one size while a
 * member switches the tab they read, so the dialog does not jump under them.
 *
 * The display of the dialog is stated for the dialog that is open: a `<dialog>`
 * is hidden by the browser while it is closed, and a display declared for one
 * of them is the declaration that draws it, since a column of a closed dialog
 * drawn at the bottom of the page is a dialog nobody asked for. */
.session-dialog.new-session-dialog[open] {
  display: flex;
  flex-direction: column;
  width: 40rem;
  height: 30rem;
  /* The calendar of the day is drawn where the field it belongs to is, so it
   * is drawn over the dialog rather than clipped by it. */
  overflow: visible;
}

/* The tab a member reads fills the dialog, so the dialog holds the height it
 * is given rather than the height of the tab it presents. */
.new-session-dialog section {
  display: flex;
  flex: 1;
  min-height: 0;
}

.new-session-dialog .plot-dialog-form {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 1.25rem;
  min-height: 0;
}

.new-session-dialog .plot-dialog-actions {
  margin-top: auto;
}

/* The New Session dialog presents starting a session and planning one as two
 * tabs of one dialog, and the tab a member chose is the panel it presents. */
.new-session-tabs {
  display: flex;
  gap: 0.5rem;
  border-bottom: 1px solid var(--plot-hairline);
}

/* The dialog is a surface rather than a control, so holding the focus of a
 * dialog is no mark of a person having reached for anything. */
.session-dialog.new-session-dialog:focus {
  outline: none;
}

.new-session-tab:focus {
  outline: none;
}

.new-session-tab {
  padding: 0.5rem 0.875rem;
  border: 0;
  border-bottom: 2px solid transparent;
  background: none;
  color: var(--plot-ink-muted);
  font-size: 0.9375rem;
  font-weight: 500;
  cursor: pointer;
}

.new-session-tab:hover {
  color: var(--plot-ink);
}

.new-session-tab[aria-selected="true"] {
  border-bottom-color: var(--plot-accent);
  color: var(--plot-ink);
}

/* The day and the timeslot a session is planned for stand beside each other,
 * above the participants the tab invites. */
.session-when {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
  gap: 1rem;
}

/* The day and the timeslot of a session are controls of the dialog rather than
 * of the browser: the date picker and the dropdown of the timeslots draw with
 * the tokens of the interface. */
.session-when {
  --dp-background-color: var(--plot-surface);
  --dp-text-color: var(--plot-ink);
  --dp-primary-color: var(--plot-accent);
  --dp-primary-text-color: var(--plot-surface);
  --dp-secondary-color: var(--plot-ink-muted);
  --dp-hover-color: var(--plot-surface-sunken);
  --dp-hover-text-color: var(--plot-ink);
  --dp-hover-icon-color: var(--plot-ink);
  --dp-border-color: var(--plot-hairline-strong);
  --dp-border-color-hover: var(--plot-ink-faint);
  --dp-border-color-focus: var(--plot-accent);
  --dp-border-radius: var(--plot-radius-sm);
  --dp-disabled-color: var(--plot-surface-sunken);
  --dp-disabled-color-text: var(--plot-ink-faint);
  --dp-highlight-color: var(--plot-accent-soft);
  --dp-danger-color: var(--plot-danger);
  --dp-font-family: inherit;
  --dp-font-size: 0.8125rem;
  --dp-cell-size: 1.75rem;
  --dp-cell-padding: 0.25rem;
  --dp-button-height: 2rem;
  --dp-input-padding: 0.5rem 0.75rem;
  --dp-input-icon-padding: 2.5rem;
  --dp-input-not-clearable-padding: 0.75rem;
}

.session-when .dp--input-wrap {
  height: 2.5rem;
}

.session-when .dp--menu {
  font-size: 0.875rem;
}

/* The timeslot a session is planned in, which is a dropdown of the hours a
 * session is planned in rather than a select of the browser. */
.session-timeslot {
  position: relative;
}

.session-timeslot-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  width: 100%;
  height: 2.5rem;
  padding: 0 0.625rem;
  border: 1px solid var(--plot-hairline-strong);
  border-radius: var(--plot-radius-sm);
  background-color: var(--plot-surface);
  color: var(--plot-ink);
  font-size: 0.875rem;
}

.session-timeslot-trigger:hover {
  border-color: var(--plot-ink-faint);
}

.session-timeslot-caret {
  width: 0.875rem;
  height: 0.875rem;
  color: var(--plot-ink-faint);
}

.session-timeslot-menu {
  position: absolute;
  z-index: 20;
  top: calc(100% + 0.25rem);
  right: 0;
  left: 0;
  max-height: 14rem;
  overflow-y: auto;
  margin: 0;
  padding: 0.25rem;
  list-style: none;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius);
  background-color: var(--plot-surface);
  box-shadow: 0 12px 28px rgb(17 24 39 / 12%);
}

.session-timeslot-option {
  width: 100%;
  padding: 0.375rem 0.5rem;
  border: 0;
  border-radius: var(--plot-radius-sm);
  background: none;
  color: var(--plot-ink);
  font-size: 0.875rem;
  text-align: left;
  cursor: pointer;
}

.session-timeslot-option:hover {
  background-color: var(--plot-surface-sunken);
}

.session-timeslot-option-selected {
  color: var(--plot-accent-ink);
  font-weight: 600;
}

/* The title of a pane of the Model Management body. */
.pane-title {
  margin: 0 0 0.75rem;
  color: var(--plot-ink-faint);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* The status a pane presents in place of the content it holds none of. */
.pane-empty {
  margin: 0;
  padding: 1.5rem;
  border: 1px dashed var(--plot-hairline-strong);
  border-radius: var(--plot-radius);
  color: var(--plot-ink-muted);
  font-size: 0.875rem;
  text-align: center;
}

/* The Modelling Context Viewer leads the Build body as it leads Design. */
.build-body {
  gap: 0.5rem;
}

/* The Deploy body reads its interfaces as the Build body reads its own, so a
 * Deployment is a card of the page the section is read on. */
.deploy-body {
  gap: 0.5rem;
}

/*
 * The Delivery Run Configurator: the Delivery Runs of the selected Delivery
 * Source as a list a person works through, and the Delivery Run Panel of the
 * run they add or launch.
 *
 * The list is the surface the Model Lineage Browser is, because the two are
 * read the same way: a run is a row of a list rather than a form of its own, so
 * the list is one card of a fixed width — aligned to the left of the body of
 * the section rather than stretched across the workspace — and the row of a run
 * is a row of the browser, glyphs and all.
 */
.delivery-run-configurator {
  min-width: 0;
}

.delivery-run-configurator-body {
  max-width: var(--plot-browser-width);
}

/* The body of a list: the toolbar a record of it is added at, and the rows the
 * records of it are read as. */
.list-body {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  min-width: 0;
}

/* The toolbar of a list: the glyph a record is added with, which stands where a
 * header would, without one. */
.list-toolbar {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding: 0 0.125rem;
}

.list-add {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border: 1px solid var(--plot-hairline-strong);
  border-radius: var(--plot-radius-sm);
  background-color: var(--plot-surface);
  color: var(--plot-ink-muted);
  cursor: pointer;
}

.list-add svg {
  width: 1rem;
  height: 1rem;
}

.list-add:hover {
  border-color: var(--plot-accent-edge);
  background-color: var(--plot-accent-soft);
  color: var(--plot-accent);
}

.list-add:focus-visible {
  outline: none;
  box-shadow: var(--plot-ring);
}

.list-add[aria-expanded="true"] {
  border-color: var(--plot-accent-edge);
  background-color: var(--plot-accent-soft);
  color: var(--plot-accent-ink);
}

/* The rows of a list: each record is a surface of its own, because the record a
 * person opens holds the configuration of it under its head. The rows stand
 * apart, so the list holds the gap between them rather than a hairline. */
.list-rows {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* A record is a surface of its own: the row a person points at is its head, and
 * the configuration of the record is read under it while the row is open. The
 * surface is not a box that clips its content, because a menu of a field of an
 * open record stands over the records below it: the corners are the corners of
 * the head and of the configuration instead. */
.list-entry {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius-lg);
  background-color: var(--plot-surface);
  box-shadow: var(--plot-shadow);
}

/* The head of a record: the record as the list reads it — the fields of it the
 * list presents — and the marker that opens the configuration of it. The head
 * wraps the marks of the record under it when the workspace is too narrow to
 * hold them beside it, and it is rounded as the record is, so a record that is
 * collapsed is read as one surface. */
.list-entry-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 0.875rem;
  padding: 0.5rem 0.5rem 0.5rem 0.875rem;
  border-radius: var(--plot-radius-lg);
}

.list-entry-head:hover {
  background-color: var(--plot-surface-muted);
}

/* The head of an open record leads into the configuration of it rather than
 * standing on its own, so its foot is the edge the configuration starts at. */
.list-entry[data-expanded="true"] > .list-entry-head {
  border-bottom-right-radius: 0;
  border-bottom-left-radius: 0;
  background-color: var(--plot-accent-soft);
}

/* The row is one target: the fields of the record the list presents. */
.list-entry-summary {
  display: flex;
  flex: 1 1 auto;
  align-items: center;
  gap: 0.875rem;
  min-width: 0;
  padding: 0.375rem 0.25rem;
  border: 0;
  background-color: transparent;
  color: var(--plot-ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.list-entry-summary-static {
  cursor: default;
}

.list-entry-summary:focus-visible {
  outline: none;
  box-shadow: var(--plot-ring);
}

/*
 * The clock of a delivery is the time of the row it stands in, so the box the
 * component is mounted in takes no room of the row: the time the component draws
 * is the element of the row rather than a child of a box inside it.
 */
[data-name="ElapsedTimer"] {
  display: contents;
}

.delivery-run-time {
  flex: none;
  min-width: 6.5rem;
  color: var(--plot-ink-muted);
  font-size: 0.875rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
}

/* The marker of a row: the chevron of the Model Lineage Browser, which points
 * into the configuration of the record and down once it is open. */
.list-entry-toggle {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border: 0;
  border-radius: var(--plot-radius-sm);
  background-color: transparent;
  cursor: pointer;
}

.list-entry-toggle:hover {
  background-color: var(--plot-surface-sunken);
}

.list-entry-toggle:focus-visible {
  outline: none;
  box-shadow: var(--plot-ring);
}

.list-entry-chevron {
  flex: none;
  width: 0.4375rem;
  height: 0.4375rem;
  border-top: 1.5px solid var(--plot-ink-faint);
  border-right: 1.5px solid var(--plot-ink-faint);
  transform: rotate(45deg);
  transition: transform 120ms ease;
}

.list-entry[data-expanded="true"] .list-entry-chevron {
  transform: rotate(135deg);
}

/* The name a record is read by, and the marks of it that stand beside the name:
 * a record is a row of the list rather than a form of its own, so the marks of
 * it are read on the line of its name rather than under it. */
.list-entry-name {
  overflow: hidden;
  font-size: 0.875rem;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.list-entry-meta {
  overflow: hidden;
  font-size: 0.8125rem;
  color: var(--plot-ink-muted);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The configuration of a record: the fields of it read under the head of the
 * row while the row is open. */
.list-entry-body {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  padding: 1rem 1.25rem 1.25rem;
}

/* The records of a record are read inside it rather than as surfaces of their
 * own, so the row of a record is the hairline it is read between. */
.list-entry-body .list-entry {
  border-color: var(--plot-hairline);
  box-shadow: none;
}

.list-entry-body .list-entry-head:hover {
  background-color: var(--plot-surface-muted);
}

.list-entry-body > .pane-empty {
  padding: 0.75rem 0.875rem;
  text-align: left;
}

/*
 * The records of a list that is read as a table: the records of a Repository are
 * grouped by the type they are managed as, and each of them is a row of the
 * columns the list presents — the name it is held by, and the moment it last
 * changed — rather than a surface of its own.
 */
.list-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
}

.list-table-group {
  padding: 0.5rem 0.25rem 0.25rem;
  color: var(--plot-ink-faint);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-align: left;
  text-transform: uppercase;
}

.list-table-cell {
  padding: 0.5rem 0.25rem;
  border-top: 1px solid var(--plot-hairline);
  text-align: left;
  vertical-align: middle;
}

.list-table-row:hover .list-table-cell {
  background-color: var(--plot-surface-muted);
}

.list-table-row[data-expanded="true"] .list-table-cell {
  background-color: var(--plot-accent-soft);
}

.list-table-open {
  padding: 0;
  border: 0;
  background-color: transparent;
  color: var(--plot-ink);
  font: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
}

.list-table-open:focus-visible {
  outline: none;
  box-shadow: var(--plot-ring);
}

.list-table-date {
  color: var(--plot-ink-muted);
  font-size: 0.8125rem;
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

.list-table-action {
  width: 1%;
  text-align: right;
  white-space: nowrap;
}

.list-table-action .icon-button {
  vertical-align: middle;
}

.list-table-form {
  padding: 1rem 0.25rem 1.25rem;
  border-top: 1px solid var(--plot-hairline);
}

.delivery-run-progress {
  position: relative;
  flex: none;
  width: 9rem;
  height: 0.375rem;
  overflow: hidden;
  border-radius: 999px;
  background-color: var(--plot-surface-sunken);
}

/* The steps of a delivery are read as the segments of the bar: the track is
 * divided where the delivery passes from one step to the next. */
.delivery-run-progress::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(
    to right,
    transparent 0 calc(20% - 1px),
    var(--plot-surface) calc(20% - 1px) 20%
  );
}

.delivery-run-progress-fill {
  display: block;
  width: 0;
  height: 100%;
  border-radius: inherit;
  background-color: var(--plot-hairline-strong);
  transition:
    width 480ms cubic-bezier(0.22, 1, 0.36, 1),
    background-color 200ms ease;
}

/* A delivery the deployment is making moves: the fill carries a sheen that
 * travels along it, so a bar whose width is not changing still reads as the
 * work of the deployment rather than a delivery that stopped. */
.is-running .delivery-run-progress-fill {
  background-color: var(--plot-accent);
  background-image: linear-gradient(90deg, transparent, rgb(255 255 255 / 45%), transparent);
  background-repeat: no-repeat;
  background-size: 2.5rem 100%;
  animation: delivery-run-sheen 1.8s ease-in-out infinite;
}

.is-settled .delivery-run-progress-fill {
  background-color: var(--plot-ink-muted);
}

.is-merged .delivery-run-progress-fill {
  background-color: var(--plot-accent);
}

.is-failed .delivery-run-progress-fill {
  background-color: var(--plot-danger);
}

@keyframes delivery-run-sheen {
  from {
    background-position: -2.5rem 0;
  }

  to {
    background-position: calc(100% + 2.5rem) 0;
  }
}

/* The step of a delivery is read before the progress of it, so the word is held
 * at one width and the bar follows it. */
.delivery-run-status {
  flex: none;
  min-width: 6.5rem;
  color: var(--plot-ink-muted);
  font-size: 0.875rem;
  text-align: left;
}

.is-running .delivery-run-status {
  color: var(--plot-accent-ink);
}

.is-failed .delivery-run-status {
  color: var(--plot-danger);
}

.delivery-run-status.is-stopping {
  color: var(--plot-ink-faint);
}

.delivery-run-progress.is-stopping .delivery-run-progress-fill {
  background-color: var(--plot-ink-faint);
}

/* The Stop Button of a row stands beside the progress of the delivery of the
 * run rather than with the marks of the work of its agent, because it is the one
 * action of the row that ends the delivery rather than reading it. */
.delivery-run-stop-action {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border: 0;
  border-radius: var(--plot-radius-sm);
  background-color: transparent;
  color: var(--plot-ink-muted);
  cursor: pointer;
}

.delivery-run-stop-action svg {
  width: 1.125rem;
  height: 1.125rem;
}

.delivery-run-stop-action:hover {
  background-color: var(--plot-surface-sunken);
  color: var(--plot-danger);
}

.delivery-run-stop-action:focus-visible {
  outline: none;
  box-shadow: var(--plot-ring);
}

.delivery-run-stop-action:disabled {
  color: var(--plot-ink-faint);
  opacity: 0.4;
  cursor: default;
}

.delivery-run-stop-action:disabled:hover {
  background-color: transparent;
  color: var(--plot-ink-faint);
}

@media (prefers-reduced-motion: reduce) {
  .delivery-run-progress-fill {
    transition: none;
  }

  .is-running .delivery-run-progress-fill {
    animation: none;
  }

  /* A request being taken is still read as a mark of its own without the ring
   * that turns: the spinner is drawn in the accent of the link it stands in for,
   * so the reading of it does not depend on the motion. */
  .launcher-handoff-spinner {
    animation: none;
    border-top-color: currentColor;
    opacity: 0.55;
  }
}

/*
 * The Delivery Run Panel: two parts of one panel rather than two headings — the
 * configuration the launch of the run starts with, and the output of the agent
 * of the run. The two parts are fields of one grid, so the outputs are read as
 * fields of the panel rather than as a bar under it: the configuration takes the
 * first row and the output the second, and both end at the edge of the panel.
 */
.delivery-run-panel {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr)) auto;
  align-items: end;
  gap: 0.75rem 0.625rem;
  padding: 0.875rem;
  border-top: 1px solid var(--plot-hairline);
  border-radius: 0 0 var(--plot-radius-lg) var(--plot-radius-lg);
  background-color: var(--plot-surface-muted);
  animation: delivery-run-panel-open 140ms ease-out;
}

@keyframes delivery-run-panel-open {
  from {
    opacity: 0;
    transform: translateY(-2px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@media (max-width: 40rem) {
  .delivery-run-panel {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .delivery-run-launch {
    grid-column: 1 / -1;
  }
}

/* A field of the panel: the name the choice is read by, and the choice itself. */
/*
 * The choice of a field: a menu of the page rather than a native `<select>`,
 * because a choice is read by the name of the record it selects. The box of the
 * field is the box of a text field, the menu stands over the fields below it,
 * and the caret is the one the stylesheet draws.
 *
 * The names of the choice are the names of the component rather than the names
 * a stylesheet of the framework holds: a choice named after a control of the
 * framework is a control the framework draws as well.
 */
.plot-select {
  position: relative;
  display: block;
  width: 100%;
  min-width: 0;
}

.plot-select-open {
  z-index: 20;
}

.plot-select-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  box-sizing: border-box;
  width: 100%;
  height: 1.75rem;
  padding: 0 0.5rem;
  border: 1px solid var(--plot-hairline-strong);
  border-radius: var(--plot-radius);
  background-color: var(--plot-surface);
  color: var(--plot-ink);
  font: inherit;
  font-size: 0.8125rem;
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
}

.plot-select-trigger:hover {
  border-color: var(--plot-ink-faint);
}

.plot-select-open > .plot-select-trigger {
  border-color: var(--plot-accent-edge);
  box-shadow: var(--plot-ring);
}

.plot-select-trigger:focus-visible {
  outline: none;
  box-shadow: var(--plot-ring);
}

.plot-select-value {
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The choice a field holds is enclosed rather than read as the prompt of a field
 * that holds none: the value is marked as the value the field was answered with,
 * which is what a person reads back rather than the placeholder of an empty
 * field. */
.plot-select-chosen > .plot-select-trigger {
  border-color: transparent;
  background-color: var(--plot-surface-sunken);
}

/* A field a person does not choose yet is the field of a choice that depends on
 * another one: it is read rather than changed, so it is muted rather than
 * removed, and the menu of it stays shut. */
.plot-select-disabled > .plot-select-trigger {
  border-color: var(--plot-hairline);
  background-color: var(--plot-surface-muted);
  color: var(--plot-ink-faint);
  cursor: not-allowed;
}

.plot-select-disabled > .plot-select-trigger::after {
  opacity: 0.35;
}

.plot-select-disabled > .plot-select-trigger:hover {
  border-color: var(--plot-hairline);
}

/* The caret the menu is opened with is drawn by the stylesheet rather than
 * carried by the markup, so the box of a field presents exactly one. */
.plot-select-trigger::after {
  content: "";
  flex: none;
  width: 0.75rem;
  height: 0.75rem;
  background-color: var(--plot-ink-faint);
  -webkit-mask-image: var(--plot-caret);
  mask-image: var(--plot-caret);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
  transition: transform 120ms ease;
}

.plot-select-open > .plot-select-trigger::after {
  transform: rotate(180deg);
}

/* The choice a field holds is read at the box of the field rather than typed, so
 * the input the form carries it in is not read. */
.plot-select-input {
  display: none;
}

.plot-select-menu {
  position: absolute;
  top: calc(100% + 0.25rem);
  left: 0;
  z-index: 1;
  box-sizing: border-box;
  min-width: 100%;
  max-width: 22rem;
  max-height: 16rem;
  margin: 0;
  padding: 0.25rem;
  overflow-y: auto;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius);
  background-color: var(--plot-surface);
  box-shadow: 0 10px 28px rgb(17 24 39 / 14%);
  list-style: none;
}

.plot-select-menu[hidden] {
  display: none;
}

.plot-select-option {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  box-sizing: border-box;
  width: 100%;
  padding: 0.3125rem 0.5rem;
  border: 0;
  border-radius: var(--plot-radius);
  background-color: transparent;
  color: var(--plot-ink);
  font: inherit;
  font-size: 0.8125rem;
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
}

.plot-select-option:hover {
  background-color: var(--plot-surface-sunken);
}

.plot-select-option[aria-selected="true"] {
  background-color: var(--plot-accent-soft);
  color: var(--plot-accent-ink);
}

.plot-select-label {
  overflow: hidden;
  text-overflow: ellipsis;
}

.plot-select-hint {
  overflow: hidden;
  color: var(--plot-ink-faint);
  font-size: 0.75rem;
  text-overflow: ellipsis;
}

.plot-select-option[aria-selected="true"] .plot-select-hint {
  color: var(--plot-accent-edge);
}

/*
 * The Preview of a Delivery Run: a box of the panel rather than a choice of it,
 * because it is a mark the agent is asked to deliver rather than a value the
 * delivery is configured with. The box is read beside the name of the mark, and
 * the control is the height of the choice beside it, so the field reads as the
 * field of the panel it stands in.
 */
.delivery-run-preview {
  cursor: pointer;
}

.delivery-run-preview-control {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  box-sizing: border-box;
  height: 1.75rem;
  color: var(--plot-ink);
  font-size: 0.8125rem;
}

.delivery-run-preview .checkbox {
  margin: 0;
  cursor: inherit;
}

.delivery-run-preview-label {
  line-height: 1.75rem;
}

/* The Launch Button of a panel: the action the configuration is taken with. */
.delivery-run-launch {
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
}

/* The Launch Button of a panel: the rocket the delivery of the run is started
 * with, drawn at the size of the Button that adds a run to the list rather than
 * as a name of its own. The Button is the action the panel is for, so it is
 * drawn in the accent while an action of the row is not. */
.delivery-run-launch-action {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border: 1px solid var(--plot-accent-edge);
  border-radius: var(--plot-radius-sm);
  background-color: var(--plot-accent-soft);
  color: var(--plot-accent-ink);
  font: inherit;
  cursor: pointer;
}

.delivery-run-launch-action svg {
  width: 1rem;
  height: 1rem;
}

.delivery-run-launch-action:hover {
  border-color: var(--plot-accent);
  background-color: var(--plot-accent-edge);
  color: var(--plot-surface);
}

.delivery-run-launch-action:focus-visible {
  outline: none;
  box-shadow: var(--plot-ring);
}

.delivery-run-launch-action:disabled {
  border-color: var(--plot-hairline-strong);
  background-color: transparent;
  color: var(--plot-ink-faint);
  cursor: default;
}

/*
 * The result of a Delivery Run: the Pull Request the delivery is reviewed in,
 * and what the delivery cost, read under the configuration of the run once the
 * Pull Request of it is ready. The result is the footer of the panel rather
 * than a section of its own, so it is told apart from the configuration by the
 * hairline of the panel rather than by a heading.
 */
.delivery-run-result {
  display: flex;
  grid-column: 1 / -1;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.5rem 1.25rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--plot-hairline);
}

.delivery-run-result-pr {
  display: flex;
  flex: 1 1 14rem;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
  color: var(--plot-ink);
  text-decoration: none;
}

.delivery-run-result-pr:hover .delivery-run-result-url {
  text-decoration: underline;
}

.delivery-run-result-pr:focus-visible {
  outline: none;
  box-shadow: var(--plot-ring);
}

.delivery-run-result-url {
  overflow: hidden;
  color: var(--plot-accent-ink);
  font-size: 0.8125rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.delivery-run-result-costs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
  margin: 0;
}

.delivery-run-result-cost {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
}

.delivery-run-result-value {
  margin: 0;
  color: var(--plot-ink);
  font-size: 0.8125rem;
  font-variant-numeric: tabular-nums;
}

/* The time of a row the delivery of which is being made is the clock of the
 * delivery rather than the time it was launched, so it is drawn as a clock. */
.delivery-run-time.is-elapsed {
  color: var(--plot-accent-ink);
  font-variant-numeric: tabular-nums;
}

/*
 * The output of a Delivery Run: the marks of the work of its agent, held in the
 * head of the row beside the progress of the delivery of the run, so the
 * delivery is read and taken without opening the configuration of it.
 */
.delivery-run-output {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 0.125rem;
  margin-left: auto;
}

.delivery-run-output-action {
  position: relative;
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border: 0;
  border-radius: var(--plot-radius-sm);
  background-color: transparent;
  color: var(--plot-ink-muted);
  text-decoration: none;
  cursor: pointer;
}

.delivery-run-output-action svg {
  width: 1.125rem;
  height: 1.125rem;
}

.delivery-run-output-action:hover {
  background-color: var(--plot-surface-sunken);
  color: var(--plot-accent);
}

.delivery-run-output-action:focus-visible {
  outline: none;
  box-shadow: var(--plot-ring);
}

/*
 * The handoff of a link to the Plot Launcher: the browser hands the request to
 * the launcher rather than following the link, and it reports nothing of what it
 * did with it, so the mark of the link is read as a request being taken from the
 * click on it. The spinner stands where the mark is rather than beside it, so a
 * row of marks does not move while a person waits for the launcher, and it is
 * drawn in the colour of the mark it stands in for.
 */
.launcher-handoff-spinner {
  display: none;
  width: 0.875rem;
  height: 0.875rem;
  border: 1.5px solid currentColor;
  border-top-color: transparent;
  border-radius: 9999px;
  animation: var(--animate-spin);
}

.delivery-run-output-action.is-handing-off,
.delivery-run-output-action.is-handing-off:hover {
  color: var(--plot-accent);
  cursor: progress;
}

/* The mark of the link is kept in the layout rather than taken out of it, so the
 * link keeps the box the spinner stands in. */
.delivery-run-output-action.is-handing-off > svg {
  visibility: hidden;
}

.delivery-run-output-action.is-handing-off > .launcher-handoff-spinner {
  display: block;
  position: absolute;
}

/*
 * The settings of a Delivery Run: the gear at the end of the marks of the run,
 * which presents the actions that are of the run rather than of the delivery it
 * is at — the run is archived when a Pull Request delivers it, and deleted when
 * it delivered none. The settings are read rather than presented while the
 * delivery of the run is being made.
 */
.delivery-run-settings {
  position: relative;
  flex: none;
}

.delivery-run-settings-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: var(--plot-radius-sm);
  color: var(--plot-ink-muted);
  cursor: pointer;
  list-style: none;
}

.delivery-run-settings-trigger::-webkit-details-marker {
  display: none;
}

/* The gear is drawn to the edge of its box rather than inside it as the marks of
 * a run are, so it is drawn a size smaller to read as one of them. */
.delivery-run-settings > svg,
.delivery-run-settings-trigger svg {
  width: 0.9375rem;
  height: 0.9375rem;
}

.delivery-run-settings-trigger:hover,
.delivery-run-settings[open] > .delivery-run-settings-trigger {
  background-color: var(--plot-surface-sunken);
  color: var(--plot-accent);
}

.delivery-run-settings-trigger:focus-visible {
  outline: none;
  box-shadow: var(--plot-ring);
}

.delivery-run-settings.is-inactive {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border: 0;
  background-color: transparent;
  color: var(--plot-ink-faint);
  opacity: 0.4;
  cursor: default;
}

.delivery-run-settings-menu {
  position: absolute;
  z-index: 30;
  top: calc(100% + 0.25rem);
  right: 0;
  display: flex;
  flex-direction: column;
  width: max-content;
  padding: 0.5rem;
  border: 1px solid var(--plot-hairline-strong);
  border-radius: var(--plot-radius);
  background-color: var(--plot-surface);
  box-shadow: 0 8px 24px rgb(17 24 39 / 10%);
}

.delivery-run-settings-action {
  align-self: flex-start;
  white-space: nowrap;
  padding: 0.25rem 0.75rem;
  border: 1px solid var(--plot-hairline-strong);
  border-radius: var(--plot-radius-sm);
  background-color: var(--plot-surface);
  color: var(--plot-ink);
  font: inherit;
  font-size: 0.8125rem;
  cursor: pointer;
}

.delivery-run-settings-action:hover {
  border-color: var(--plot-accent-edge);
  background-color: var(--plot-accent-soft);
  color: var(--plot-accent-ink);
}

.delivery-run-settings-action:focus-visible {
  outline: none;
  box-shadow: var(--plot-ring);
}

/* The views a delivery is modelled in are the links of the settings, and the
 * action the run is taken with is held apart from them: a person opens the
 * delivery in a view rather than taking the run, so the two are read as two
 * groups of the menu. */
.delivery-run-settings-group {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--plot-hairline);
}

.delivery-run-settings-group + .delivery-run-settings-action {
  margin-top: 0.5rem;
}

/* A mark a run does not hold yet is presented as the glyph of an action that is
 * not taken, rather than left out of the row: a person reads what the delivery
 * of the run reaches from the row itself. */
.delivery-run-output-action.is-inactive {
  color: var(--plot-ink-faint);
  opacity: 0.4;
  cursor: default;
}

.delivery-run-output-action.is-inactive:hover {
  background-color: transparent;
  color: var(--plot-ink-faint);
}

.delivery-run-output-action:disabled {
  color: var(--plot-ink-faint);
  opacity: 0.4;
  cursor: default;
}

.delivery-run-output-action:disabled:hover {
  background-color: transparent;
  color: var(--plot-ink-faint);
}

/*
 * The Deliveries overview: the deliveries of a model, newest launch first, as
 * the panels of the runs the panel of a Delivery Run presents.
 */
/* The deliveries of a model are read at the width a build is read at: the list
 * of the runs is the card the Model Lineage Browser and the Delivery Run
 * Configurator are, aligned to the left of the body of the section rather than
 * stretched across the workspace. */
.deliveries-overview {
  min-width: 0;
  max-width: var(--plot-browser-width);
}

/* The runs of a model are bundled under the Delivery Source each of them
 * delivers, so the deliveries of a source are read together rather than one run
 * after another: the bundle is a heading of its own above the panels of its
 * runs, and the bundles stand apart from each other. */
.delivery-source-group {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.delivery-source-group + .delivery-source-group {
  margin-top: 1.5rem;
}

.delivery-source-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0 0.25rem;
}

/* The title of a bundle is the Modelling Context of the source: the same
 * context a screen reads beside it, so the lineage of a source is read one way
 * in the interface. The context keeps the width the head leaves it rather than
 * the width of its chain, so a lineage that runs long wraps instead of pushing
 * the count of the runs off the head. */
.delivery-source-head .modelling-context-viewer {
  flex: 1 1 auto;
  min-width: 0;
}

/* A source the model no longer places is read under a name of its own, because
 * the chain of elements that led to it is no part of the model. */
.delivery-source-unnamed {
  color: var(--plot-ink);
  font-size: 0.875rem;
  font-weight: 600;
}

/* The number of runs a source is delivered in: the bundle is read as how many
 * deliveries the source holds before the runs themselves are read. */
.delivery-source-count {
  flex: none;
  color: var(--plot-ink-faint);
  font-size: 0.75rem;
}

/*
 * The Pull Request of a Delivery Run and the link that opens it in the code
 * editor are links of the same Pull Request: they are held beside each other
 * and wrap together rather than the address of the Pull Request hiding the
 * editor link of it.
 */
.delivery-run-links {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.25rem 0.75rem;
  overflow: visible;
  white-space: normal;
}

.delivery-run-pull-request {
  overflow-wrap: anywhere;
}

.delivery-run-editor {
  white-space: nowrap;
}

/*
 * The Plateau Repository configurator: the Repository the Plateau holds and
 * the Configure Button that opens the selection of the Repositories the
 * accesses of the account reach.
 */
.plateau-repository-configurator {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.plateau-repository-configurator .plateau-repository {
  flex-wrap: wrap;
  margin-left: 0;
}

.plateau-repository {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  gap: 0.5rem;
  margin-left: auto;
}

.plateau-repository-state {
  margin: 0;
  min-width: 0;
}

.plateau-repository-name {
  display: block;
  max-width: 18rem;
  overflow: hidden;
  font-family: var(--plot-font-mono, ui-monospace, SFMono-Regular, monospace);
  font-size: 0.8125rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.plateau-repository-accesses {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin: 1.25rem 0 0;
  padding: 0;
  list-style: none;
}

.plateau-repository-access {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  width: 100%;
  text-align: left;
}

.plateau-repository-access-service {
  min-width: 0;
  overflow-wrap: anywhere;
}

/*
 * The account the access is of, and the access the Repository the Plateau
 * holds is reached through — so a person choosing between the accesses an
 * account configured reads the choice the Plateau holds rather than guessing
 * it.
 */
.plateau-repository-access-name,
.plateau-repository-access-current {
  flex-shrink: 0;
  color: var(--plot-ink-faint);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/*
 * The Repositories the access a person chose reaches, which the Plateau is
 * configured with once a person confirms the choice, and the Repository the
 * access does not reach yet, which a person names and creates through it.
 */
.plateau-repository-select {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 1.25rem;
}

.plateau-repository-choices {
  flex: 1 1 auto;
  min-width: 0;
}

.plateau-repository-form {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  margin-top: 1.25rem;
}

.plateau-repository-name-row {
  display: flex;
  align-items: flex-end;
  gap: 0.5rem;
}

.plateau-repository-name-row .plateau-repository-field {
  flex: 1 1 auto;
}

.plateau-repository-visibility {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.875rem;
}

/*
 * The Settings: AI Models interface: the AI Model Services the AI Model
 * Management function manages as the services a person activates, the state
 * the account holds each of them in, and the Verify on demand Button.
 */
/*
 * The Settings interfaces: one spec for the interface of every setting a model
 * holds. A setting is read as the name of it, the action that adds to it where
 * it has one, and the sentence that says what it is, over the list of what it
 * holds — the User settings, the AI Models, the Repositories, the Collaborators
 * and the Agents are read alike, so a setting is a place of the settings rather
 * than an interface of its own. The sections are named after the setting they
 * present, while the spec they are read at is this one.
 */
.user-settings,
.ai-models-settings,
.repositories-settings,
.collaborators-settings,
.agent-settings {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  padding-block: 1rem;
}

.user-settings-header,
.ai-models-settings-header,
.repositories-settings-header,
.collaborators-settings-header,
.agent-settings-header {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

/* The name of a setting beside the action that adds to it: the action is held
 * to the end of the row, so the name is read from the edge the setting is read
 * from whatever the action is. */
.user-settings-heading,
.repositories-settings-heading,
.collaborators-settings-heading,
.agent-settings-heading {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

.user-settings-title,
.ai-models-settings-title,
.repositories-settings-title,
.collaborators-settings-title,
.agent-settings-title {
  font-size: 1.125rem;
  font-weight: 600;
  letter-spacing: -0.011em;
}

.user-settings-intro,
.ai-models-settings-intro,
.repositories-settings-intro,
.collaborators-settings-intro,
.agent-settings-intro {
  margin-top: 0.25rem;
  color: var(--plot-ink-muted);
  font-size: 0.875rem;
}

/* A setting that holds nothing yet: the line it says so in. */
.user-settings-empty,
.repositories-empty,
.collaborators-empty {
  color: var(--plot-ink-faint);
  font-size: 0.875rem;
}

/*
 * The models of the account in the User settings: the model a person opens is
 * a row of the list, and the model the screen is of is the row held current
 * rather than a link, because it is the model the person already works in.
 */
.model-switcher-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.model-switcher {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius);
  background-color: var(--plot-surface-muted);
}

.model-switcher-active {
  border-color: var(--plot-accent-edge);
  background-color: var(--plot-accent-soft);
}

.model-switcher-model {
  min-width: 0;
  color: var(--plot-ink);
  font-size: 0.875rem;
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.model-switcher-model:hover {
  color: var(--plot-accent-ink);
  text-decoration: underline;
}

.model-switcher-model[aria-current="page"] {
  color: var(--plot-accent-ink);
  font-weight: 600;
}

.model-switcher-current {
  flex-shrink: 0;
  margin-left: auto;
  color: var(--plot-ink-faint);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/*
 * The Settings: AI Models interface: the AI Model Services the AI Model
 * Management function manages as the services a person activates, the state
 * the account holds each of them in, and the Verify on demand Button.
 */

.ai-model-service-list {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.ai-model-service {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 1rem;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius-lg);
  background-color: var(--plot-surface);
}

.ai-model-service-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

.ai-model-service-name {
  font-size: 0.9375rem;
  font-weight: 600;
}

.ai-model-service-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-left: auto;
}

.ai-model-service-note {
  margin: 0;
  color: var(--plot-ink-muted);
  font-size: 0.8125rem;
}

.ai-model-verification {
  margin: 0;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius);
  font-size: 0.8125rem;
}

.ai-model-verification-ok {
  border-color: color-mix(in oklab, var(--plot-accent) 35%, var(--plot-hairline));
  background-color: var(--plot-accent-soft);
  color: var(--plot-accent-ink);
}

.ai-model-verification-error {
  border-color: color-mix(in oklab, var(--plot-danger) 35%, var(--plot-hairline));
  color: var(--plot-danger);
}

.ai-model-status {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.ai-model-status-configured {
  color: var(--plot-accent-ink);
}

.ai-model-status-missing {
  color: var(--plot-ink-faint);
}

.ai-model-credentials-form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.75rem;
}

.ai-model-remove {
  align-self: flex-start;
}

/*
 * The Activation dialog of an AI Model Service: the popup the Activate Button
 * of a service opens, which takes the API Key the account presents to it.
 *
 * It is a `<dialog>` element, so the page behind it is inert and the Escape
 * Key dismisses it without this interface holding any of that itself. A
 * `<dialog>` shows nothing until it is asked to be modal, which the
 * ServiceActivationDialog Hook does. The dialog is put in the middle of the
 * viewport by its own auto margins, which the reset the components draw from
 * takes away from every element, so they are set back here.
 */
.plot-dialog {
  margin: auto;
  width: 26rem;
  max-width: calc(100vw - 3rem);
  max-height: calc(100dvh - 3rem);
  padding: 1.5rem;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius-lg);
  background-color: var(--plot-surface);
  color: var(--plot-ink);
  box-shadow: 0 16px 40px rgb(17 24 39 / 22%);
}

.plot-dialog::backdrop {
  background-color: rgb(17 24 39 / 35%);
}

.plot-dialog-title {
  font-size: 1rem;
  font-weight: 600;
}

.plot-dialog-intro {
  margin-top: 0.25rem;
  color: var(--plot-ink-muted);
  font-size: 0.875rem;
}

.plot-dialog-form {
  flex-direction: column;
  align-items: stretch;
  margin-top: 1.25rem;
}

.plot-dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
  margin-top: 0.25rem;
}

/*
 * The Settings: Repositories interface: the Repositories the account configured
 * for the Repository Services, the process a Repository is added through, and
 * the repositories an access reaches.
 */
.repository-service-form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.75rem;
  padding: 1rem;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius-lg);
  background-color: var(--plot-surface);
}

.repository-input {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
}

.repository-input-label {
  color: var(--plot-ink-faint);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.repository-service-list {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.repository-service {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 1rem;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius-lg);
  background-color: var(--plot-surface);
}

.repository-service-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

.repository-service-name {
  font-size: 0.9375rem;
  font-weight: 600;
}

.repository-service-actions {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  gap: 0.5rem;
  margin-left: auto;
}

/* The account an access is of, which the provider reported as the account's own
 * URL, so it is presented in mono. */
.repository-account {
  margin: 0;
  min-width: 0;
  color: var(--plot-ink-muted);
  font-family: var(--plot-font-mono, ui-monospace, SFMono-Regular, monospace);
  font-size: 0.8125rem;
  overflow-wrap: anywhere;
}

/* The name of a Repository is presented on the line of the Repository rather
 * than below it, so it is kept to the one line and elided where it exceeds it. */
.repository-account-inline {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The Repository Services a Repository is added through: one choice per
 * service the Repository Services realize. */
.repository-service-choices {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.repository-add {
  flex-shrink: 0;
}

.repository-add-service {
  white-space: nowrap;
}

/* The confirmation of a Removal: the credentials of a Repository are given up
 * for good, so the action is presented as the destructive one it is. */
.repository-remove-confirm {
  border-color: color-mix(in oklab, var(--plot-danger) 45%, var(--plot-hairline));
  color: var(--plot-danger);
}

/*
 * The Settings: Collaborators interface: the members that collaborate on the
 * model beside the invitations a person has been offered, and the Invite
 * Collaborator dialog that takes the email address and the message of an
 * invitation.
 */
.collaborators-add {
  flex-shrink: 0;
}

/* The collaborators of the model: a member it holds, or a person who has been
 * offered a collaboration and has not taken it up yet. */
.collaborator-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.collaborator {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius);
  background-color: var(--plot-surface-muted);
}

.collaborator-name {
  flex-shrink: 0;
  font-size: 0.875rem;
  font-weight: 600;
}

.collaborator-email {
  min-width: 0;
  color: var(--plot-ink-muted);
  font-size: 0.8125rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* An invitation is a collaboration a person has been offered rather than one
 * they hold, so the email it names is presented as the offer it is. */
.collaborator-invitation .collaborator-email {
  color: var(--plot-ink);
}

.collaborator-status {
  flex-shrink: 0;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* The state an invitation is held in: one that is pending stands as an offer
 * the person holds, and one that failed is a delivery that did not reach
 * them. */
.collaborator-status-pending {
  color: var(--plot-ink-faint);
}

.collaborator-status-failed {
  color: var(--plot-danger);
}

.collaborator-actions {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  gap: 0.5rem;
  margin-left: auto;
}

/* The Invite Collaborator dialog: the email address the person is invited by
 * and the message the invitation is offered with. */
.collaborator-invite-form {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

/* The confirmation of a revocation: the invitation is given up for good, so
 * the action is presented as the destructive one it is. */
.collaborator-revoke-confirm {
  border-color: color-mix(in oklab, var(--plot-danger) 45%, var(--plot-hairline));
  color: var(--plot-danger);
}

/*
 * The Settings: Environment interface: the Repository a person selects and the
 * Environment Variables it aggregates, which a person manages per Repository.
 */
.environment-settings {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  padding-block: 1rem;
}

.environment-settings-header {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.environment-settings-heading {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

.environment-settings-title {
  font-size: 1.125rem;
  font-weight: 600;
  letter-spacing: -0.011em;
}

/* The Repository whose Environment Variables are presented: the Repositories
 * of the account are the selector of the one that is presented. */
.environment-repository-select {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.environment-repository-choices {
  min-width: 14rem;
  max-width: 100%;
}

/* The Environment Variables a Repository aggregates: the name a variable is
 * read by and the Secret the value it holds is presented as. */
.environment-variable-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.environment-variable {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius);
  background-color: var(--plot-surface-muted);
}

.environment-variable-name {
  flex-shrink: 0;
  font-family: var(--plot-font-mono, ui-monospace, SFMono-Regular, monospace);
  font-size: 0.8125rem;
  font-weight: 600;
}

.environment-variable-value {
  min-width: 0;
  color: var(--plot-ink-muted);
  font-family: var(--plot-font-mono, ui-monospace, SFMono-Regular, monospace);
  font-size: 0.8125rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.environment-variable-actions {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  gap: 0.5rem;
  margin-left: auto;
}

.environment-add {
  flex-shrink: 0;
}

/* The confirmation of a Removal: the Environment Variable is removed from the
 * Repository for good, so the action is presented as the destructive one it
 * is. */
.environment-remove-confirm {
  border-color: color-mix(in oklab, var(--plot-danger) 45%, var(--plot-hairline));
  color: var(--plot-danger);
}

.environment-empty {
  color: var(--plot-ink-faint);
  font-size: 0.875rem;
}

/*
 * The Help Panel: the Chat UI of the Plot Help component, docked above the
 * footer, over the bottom of the Sidebar Layout. The panel is anchored to the
 * bottom of the viewport rather than to the box the screen is read in: the
 * screen is the part of the shell that scrolls, so a panel positioned against
 * the bottom of it is carried off the bottom of the viewport by a screen taller
 * than the viewport. The footer is the strip the shell reads at the bottom of
 * the viewport, so the panel is held at the top edge of it. The body the panel
 * expands slides up from there, and the transcript scrolls in the height the
 * panel gives it rather than stretching it.
 */
.help-panel {
  position: fixed;
  /* The panel is docked on the sidebar column: its right edge holds the right
   * edge of the column and its left edge holds the margin the shell gives a
   * panel, so the panel is the column widened by the padding the column is
   * held at. */
  left: 0.5rem;
  bottom: var(--plot-shell-footer-height);
  z-index: 15;
  display: flex;
  flex-direction: column;
  width: min(calc(clamp(1rem, 3vw, 2rem) + 14.5rem), calc(100% - 1rem));
  max-width: 100%;
  overflow: hidden;
  border: 1px solid var(--plot-hairline);
  border-bottom: none;
  border-radius: var(--plot-radius-lg) var(--plot-radius-lg) 0 0;
  background-color: var(--plot-surface);
  box-shadow: 0 -0.75rem 2rem color-mix(in oklab, var(--plot-ink) 10%, transparent);
}

.help-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.375rem 0.375rem 0.375rem 0.875rem;
}

.help-panel-title {
  margin: 0;
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.help-panel-toggle {
  color: var(--plot-ink-muted);
}

/* The triangle of the Collapse toggle Button: drawn with a border rather than
 * named, because the icon sheet of the deployment defines a fixed set of icons
 * and the triangle of a panel toggle is one no icon of it is. */
.help-panel-caret {
  display: inline-block;
  width: 0;
  height: 0;
  border-top: 0.3125rem solid currentColor;
  border-right: 0.25rem solid transparent;
  border-left: 0.25rem solid transparent;
  transition: transform 200ms ease;
}

.help-panel-collapsed .help-panel-caret {
  transform: rotate(180deg);
}

/* The body the Collapse toggle Button expands and collapses: the panel is
 * anchored to the bottom, so the body growing is the panel sliding up over the
 * sidebar it is docked on. The body holds the height the conversation is read
 * in, so the transcript it holds is the part of the panel that scrolls and the
 * field a message is written in is held below it. */
.help-panel-body {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  height: min(45vh, 26rem);
  padding: 0.75rem;
  border-top: 1px solid var(--plot-hairline);
  transition:
    height 200ms ease,
    padding 200ms ease;
}

.help-panel-collapsed .help-panel-body {
  height: 0;
  padding-top: 0;
  padding-bottom: 0;
  border-top-color: transparent;
}

/* The transcript is the part of the panel that scrolls. The conversation reads
 * from the bottom: the message it opens with is held down to the field the next
 * message is written in, so the space a short conversation leaves is above that
 * message and a message that arrives pushes the conversation up rather than
 * leaving the space under it. */
.help-chat-transcript {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 0.375rem;
  min-height: 0;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  list-style: none;
}

.help-chat-message:first-child {
  margin-top: auto;
}

/* A message is the sentence it holds, read from the left of the panel: the
 * speaker of it is the tint it is held in rather than a heading above it, and
 * the bubble holds the padding the letters need and no more. */
.help-chat-message {
  padding: 0.25rem 0.5rem;
  border-radius: var(--plot-radius);
}

.help-chat-message-user {
  background-color: var(--plot-accent-soft);
}

.help-chat-message-assistant {
  border: 1px solid var(--plot-hairline);
  background-color: var(--plot-surface-muted);
}

.help-chat-content {
  margin: 0;
  font-size: 0.8125rem;
  line-height: 1.5;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* The changes the assistant suggested, read as the buttons they are chosen
 * with: the icon of a suggestion is the glyph the Modelling UI draws what it
 * changes with — the same glyph the lineage browser and the context bar draw an
 * element with — and the two ends of a relationship are drawn side by side. */
.help-chat-suggestions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
  margin: 0.375rem 0 0;
  padding: 0;
  list-style: none;
}

.help-chat-suggestion {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  max-width: 100%;
  padding: 0.25rem 0.5rem 0.25rem 0.375rem;
  border: 1px solid var(--plot-hairline-strong);
  border-radius: 1rem;
  background-color: var(--plot-surface);
  color: var(--plot-ink);
  font-family: inherit;
  font-size: 0.75rem;
  line-height: 1.25;
  cursor: pointer;
  transition:
    border-color 150ms ease,
    background-color 150ms ease;
}

.help-chat-suggestion:hover:enabled {
  border-color: var(--plot-accent);
  background-color: var(--plot-accent-soft);
}

.help-chat-suggestion:focus-visible {
  outline: none;
  box-shadow: var(--plot-ring);
}

.help-chat-suggestion-icons {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 0.125rem;
}

.help-chat-suggestion-icon {
  display: inline-flex;
  width: 1rem;
  height: 1rem;
}

.help-chat-suggestion-icon svg {
  width: 100%;
  height: 100%;
}

.help-chat-suggestion-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The relationships a suggestion inserts the element with, read behind the name
 * of it: the element is suggested as the part of the model it is, so the person
 * reads what it is related to before inserting it. */
.help-chat-suggestion-detail {
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  color: var(--plot-ink-muted);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.help-chat-suggestion-action {
  flex: none;
  color: var(--plot-ink-muted);
}

/* A suggestion the person inserted is no suggestion to insert again: it reads
 * as what the model now holds rather than as what it could hold. */
.help-chat-suggestion-inserted {
  border-color: transparent;
  background-color: var(--plot-surface-muted);
  color: var(--plot-ink-muted);
  cursor: default;
}

.help-chat-suggestion-inserted .help-chat-suggestion-action {
  color: var(--plot-accent);
}

.help-chat-asking {
  margin: 0;
  color: var(--plot-ink-muted);
  font-size: 0.8125rem;
}

/* The form the next message is written in: the divider above the Composer is
 * what separates the message being written from the conversation it continues. */
.help-chat-form {
  display: flex;
  flex: none;
  padding-top: 0.75rem;
  border-top: 1px solid var(--plot-hairline);
}

/*
 * The Composer: the field a message is written in and the Send Button inside
 * it, held as one rounded box at the foot of the panel. The box is what a
 * person writes into — the field itself draws no box of its own — so the
 * button reads as part of the control rather than as the step after it.
 */
.help-chat-composer {
  display: flex;
  align-items: flex-end;
  gap: 0.375rem;
  width: 100%;
  padding: 0.375rem 0.375rem 0.375rem 0.625rem;
  border: 1px solid var(--plot-hairline-strong);
  border-radius: 1.25rem;
  background-color: var(--plot-surface);
  transition:
    border-color 150ms ease,
    box-shadow 150ms ease;
}

/* The box a person writes into is the one that is marked as written in, rather
 * than the borderless field inside it. */
.help-chat-composer:focus-within {
  border-color: var(--plot-accent);
  box-shadow: var(--plot-ring);
}

/*
 * The field a message is written in: one line when the message begins, and as
 * many lines as the message needs after that — the height the Composer hook
 * measures. A message longer than the height the box stops growing at is read
 * in the field scrolling rather than stretching the panel.
 */
.help-chat-input {
  flex: 1 1 auto;
  min-width: 0;
  max-height: 6rem;
  padding: 0.25rem 0;
  overflow-y: auto;
  border: none;
  background-color: transparent;
  color: var(--plot-ink);
  font-family: inherit;
  font-size: 0.8125rem;
  line-height: 1.5;
  resize: none;
  outline: none;
}

/* The Send Button of the Composer: the round button inside the box, holding the
 * arrow the message is sent with. It is disabled while Plot Help is answering
 * the message before it. */
.help-chat-send {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border: none;
  border-radius: 50%;
  background-color: var(--plot-accent);
  color: var(--plot-surface);
  cursor: pointer;
  transition: background-color 150ms ease;
}

.help-chat-send:disabled {
  background-color: var(--plot-hairline-strong);
  cursor: default;
}

.help-chat-send svg {
  width: 1rem;
  height: 1rem;
}

/*
 * The Settings: Agents interface: the AI Agents a model configures and the AI
 * Agent software each of them is realized by, which a person manages for the
 * model.
 */
/* The AI Agents a model configures: the name an agent is configured under and
 * the AI Agent software it is realized by. */
.agent-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.agent {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius);
  background-color: var(--plot-surface-muted);
}

.agent-identity {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  min-width: 0;
}

.agent-name {
  font-weight: 600;
  font-size: 0.875rem;
}

.agent-software {
  color: var(--plot-ink-muted);
  font-family: var(--plot-font-mono, ui-monospace, SFMono-Regular, monospace);
  font-size: 0.75rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.agent-actions {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  gap: 0.5rem;
  margin-left: auto;
}

.agent-add {
  flex-shrink: 0;
}

/* The confirmation of a Removal: the agent is removed from the model for good,
 * so the action is presented as the destructive one it is. */
.agent-remove-confirm {
  border-color: color-mix(in oklab, var(--plot-danger) 45%, var(--plot-hairline));
  color: var(--plot-danger);
}

.agent-empty {
  color: var(--plot-ink-faint);
  font-size: 0.875rem;
}

/*
 * The Agent Skills of the account: the name a skill is read by and the
 * description of the work it is for, which the Manage Agent Skills process of
 * the AI Agent Management function manages.
 */
.agent-skills {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--plot-hairline);
}

.agent-skills-header {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.agent-skills-heading {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

.agent-skills-title {
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: -0.011em;
}

.agent-skills-intro {
  max-width: 42rem;
  color: var(--plot-ink-muted);
  font-size: 0.8125rem;
  line-height: 1.5;
}

.agent-skill-list {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.agent-skill {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius);
  background-color: var(--plot-surface-muted);
}

.agent-skill-identity {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  min-width: 0;
}

.agent-skill-name {
  font-weight: 600;
  font-size: 0.875rem;
}

.agent-skill-description {
  color: var(--plot-ink-muted);
  font-size: 0.8125rem;
  line-height: 1.4;
}

.agent-skill-actions {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  gap: 0.5rem;
  margin-left: auto;
}

.agent-skill-add {
  flex-shrink: 0;
}

/* The confirmation of a Removal: the Agent Skill is removed from the account
 * for good, so the action is presented as the destructive one it is. */
.agent-skill-remove-confirm {
  border-color: color-mix(in oklab, var(--plot-danger) 45%, var(--plot-hairline));
  color: var(--plot-danger);
}

.agent-skills-empty {
  color: var(--plot-ink-faint);
  font-size: 0.875rem;
}

/*
 * The Video conference panel: the Video conference panel interface of the
 * Video conferencing function, docked at the top right of the workspace. The
 * panel presents the conference the members of the model hold beside the
 * session they work in, so it holds the actions that start and stop the
 * conference and join and leave it, over the stage of the members that hold
 * it.
 */
.video-conference-panel {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  z-index: 14;
  display: flex;
  flex-direction: column;
  width: min(24rem, calc(100% - 1rem));
  max-height: calc(100% - 1rem);
  overflow: hidden;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius-lg);
  background-color: var(--plot-surface);
  box-shadow: 0 0.75rem 2rem color-mix(in oklab, var(--plot-ink) 10%, transparent);
}

.video-conference-header {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.75rem;
}

.video-conference-title {
  margin: 0;
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.video-conference-status {
  margin: 0;
  color: var(--plot-ink-muted);
  font-size: 0.8125rem;
}

.video-conference-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* The stage holds the video of every member of the conference: the videos are
 * laid out as a column that scrolls, so a conference of several members reads
 * in the height the panel is given rather than stretching it. */
.video-conference-stage {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  overflow-y: auto;
  padding: 0 0.75rem 0.75rem;
}

.video-conference-member {
  position: relative;
  border-radius: var(--plot-radius-md);
  overflow: hidden;
  background-color: var(--plot-surface-sunken);
}

.video-conference-video {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  background-color: var(--plot-surface-sunken);
}

.video-conference-name {
  position: absolute;
  left: 0.5rem;
  bottom: 0.5rem;
  padding: 0.125rem 0.375rem;
  border-radius: var(--plot-radius-sm);
  background-color: color-mix(in oklab, var(--plot-ink) 60%, transparent);
  color: var(--plot-surface);
  font-size: 0.75rem;
}

/*
 * The Log Viewer: the events of the agent of a Delivery Run, read of the log
 * the Agent Machine the run was launched on wrote. The newest event leads the
 * log, so the events a page appends are presented above the ones already read
 * and the viewer keeps the top of the log in view: it is a surface of its own
 * below the deliveries it is read from rather than a page the person navigates
 * to.
 */
.log-viewer {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  margin-top: 1rem;
  padding: 1rem;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius-lg);
  background-color: var(--plot-surface);
}

.log-viewer-header {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.5rem;
}

.log-viewer-identity {
  min-width: 0;
}

.log-viewer-source {
  margin: 0;
  overflow: hidden;
  color: var(--plot-ink-muted);
  font-size: 0.875rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.log-viewer-controls {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.log-viewer-state {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.15rem 0.5rem;
  border: 1px solid var(--plot-hairline);
  border-radius: 999px;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.log-viewer-state::before {
  width: 0.4rem;
  height: 0.4rem;
  border-radius: 999px;
  background-color: currentcolor;
  content: "";
}

.log-viewer-state-live {
  border-color: color-mix(in oklab, var(--plot-accent) 35%, var(--plot-hairline));
  background-color: var(--plot-accent-soft);
  color: var(--plot-accent-ink);
}

.log-viewer-state-ended,
.log-viewer-state-waiting {
  color: var(--plot-ink-faint);
}

.log-viewer-error {
  margin: 0;
  padding: 0.5rem 0.75rem;
  border: 1px solid color-mix(in oklab, var(--plot-danger) 35%, var(--plot-hairline));
  border-radius: var(--plot-radius);
  background-color: color-mix(in oklab, var(--plot-danger) 5%, transparent);
  color: var(--plot-danger);
  font-size: 0.875rem;
}

.log-viewer-loading {
  margin: 0;
  color: var(--plot-ink-faint);
  font-size: 0.8125rem;
}

.agent-log-events {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  height: min(30rem, 60vh);
  margin: 0;
  padding: 0 0.25rem 0 0;
  overflow-y: auto;
  list-style: none;
  scrollbar-gutter: stable;
}

.agent-log-event {
  display: grid;
  grid-template-columns: 0.5rem minmax(0, 1fr);
  gap: 0.5rem;
  padding: 0.5rem 0.65rem;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius);
  background-color: var(--plot-surface-muted);
}

.agent-log-event-marker {
  width: 0.4rem;
  height: 0.4rem;
  margin-top: 0.45rem;
  border-radius: 999px;
  background-color: var(--plot-ink-faint);
}

.agent-log-event-content {
  min-width: 0;
}

.agent-log-event-heading {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem;
  margin: 0;
}

.agent-log-event-label {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.agent-log-event-time {
  color: var(--plot-ink-faint);
  font-size: 0.6875rem;
  font-variant-numeric: tabular-nums;
}

/* The work of a turn the log presents is set apart from the label of the event:
 * the reasoning of the agent is the quoted thinking of it, and a tool is the
 * call the turn made — the file it wrote or the command it ran — which is read
 * as the mark of the call rather than as the text of the turn. */
.agent-log-event-body,
.agent-log-event-error {
  margin: 0.35rem 0 0;
  padding-left: 0.55rem;
  border-left: 2px solid var(--plot-hairline-strong);
  color: var(--plot-ink-muted);
  font-size: 0.8125rem;
  line-height: 1.5;
  overflow-wrap: anywhere;
  white-space: pre-wrap;
}

.agent-log-event-reasoning .agent-log-event-body {
  font-style: italic;
}

.agent-log-event-tool .agent-log-event-body {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.75rem;
}

/* A tool the agent called that failed is the work of the turn that did not
 * happen, so it is drawn as a failure rather than as another call. */
.agent-log-event-failed {
  color: var(--plot-danger);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.agent-log-event-error {
  border-left-color: color-mix(in oklab, var(--plot-danger) 45%, var(--plot-hairline));
  color: var(--plot-danger);
}

.agent-log-event-reasoning .agent-log-event-marker {
  background-color: var(--plot-accent);
}

.agent-log-event-tool .agent-log-event-marker {
  background-color: var(--plot-ink-faint);
  border-radius: 1px;
}

@media (max-width: 40rem) {
  .log-viewer {
    padding: 0.75rem;
  }

  .agent-log-events {
    height: 50vh;
  }
}

/* The Agent Log is read over the interface it is of rather than in place of
 * it: a delivery is still selected and configured behind the log, and the log
 * is closed when a person is done with it. */
.agent-log-dialog {
  width: min(72rem, calc(100vw - 3rem));
  padding: 0;
  overflow: auto;
}

.agent-log-dialog .log-viewer {
  margin-top: 0;
  border: 0;
}

.agent-log-dialog .agent-log-events {
  height: min(28rem, 55vh);
}

/*
 * The Deploy UI of the Plot Deploy component.
 *
 * The Deployments of a model are read the way the Delivery Runs of the Start
 * Build interface are read, of the list and form a record is read and corrected
 * with rather than of a listing of its own. What the component names itself is
 * the marks of its records: the status a Deployment, a Domain, or a Machine
 * holds, the challenge a Domain is verified with, and the warning of a record
 * that is removed.
 */
.deploy-status {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.1875rem 0.5rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
  white-space: nowrap;
}

.deploy-status::before {
  content: "";
  width: 0.4375rem;
  height: 0.4375rem;
  border-radius: 999px;
  background-color: currentcolor;
}

.deploy-status-idle {
  background-color: transparent;
  color: var(--plot-ink-faint);
}

/* The challenge a Domain is verified with is read as the record the person
 * publishes: one part of the record per line, named on the left and carried in
 * the monospace the value is copied from. */
.deploy-challenge {
  display: grid;
  gap: 0.375rem;
  margin: 0;
  padding: 0.625rem 0.75rem;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius);
  background-color: var(--plot-surface-muted);
}

.deploy-challenge-head {
  margin-bottom: 0.125rem;
  font-size: 0.8125rem;
  color: var(--plot-ink-muted);
}

/* The records of a Deployment are read a branch at a time: the names of one
 * branch are one record each, so the branch the record serves stands above the
 * rows of it rather than repeating in every row. */
.deploy-record {
  display: grid;
  gap: 0.375rem;
  padding-top: 0.375rem;
}

.deploy-record + .deploy-record {
  border-top: 1px solid var(--plot-hairline);
}

.deploy-record-branch {
  color: var(--plot-ink-faint);
  font-size: 0.75rem;
}

.deploy-record-branch code {
  font-family: var(--plot-font-mono, ui-monospace, SFMono-Regular, monospace);
}

.deploy-record-row {
  display: grid;
  grid-template-columns: 3.5rem minmax(0, 1fr);
  align-items: baseline;
  gap: 0.75rem;
}

.deploy-record-row dt {
  color: var(--plot-ink-faint);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.deploy-record-row dd {
  margin: 0;
  font-size: 0.8125rem;
  overflow-wrap: anywhere;
}

.deploy-record-row code {
  font-family: var(--plot-font-mono, ui-monospace, SFMono-Regular, monospace);
  font-size: 0.8125rem;
}

/* The record a row carries is copied from beside it rather than selected by
 * hand, so the record and the control that copies it are one row. */
.deploy-record-value {
  display: flex;
  align-items: center;
  gap: 0.375rem;
}

/* The copy control of a record a person publishes elsewhere: the glyph of the
 * copy stands beside the record, and the mark of the copy it made stands in its
 * place for a moment rather than beside it. */
.copy-control {
  position: relative;
  display: inline-flex;
  flex: none;
  align-items: center;
}

.copy-button {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: 0;
  border-radius: var(--plot-radius-sm);
  background-color: transparent;
  color: var(--plot-ink-faint);
  cursor: pointer;
}

.copy-button svg {
  width: 1rem;
  height: 1rem;
}

.copy-button:hover {
  background-color: var(--plot-surface-sunken);
  color: var(--plot-accent);
}

.copy-button:focus-visible {
  outline: none;
  box-shadow: var(--plot-ring);
}

.copy-button-copied {
  color: var(--plot-accent);
}

/* The copy a control made is read by the screen reader of the page rather than
 * written beside the record: the record stands the width of the row, and a word
 * that arrived beside it would move it. */
.copy-status {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.deploy-note {
  font-size: 0.8125rem;
  color: var(--plot-ink-muted);
}

/* The read of the record a Domain is verified with: the spinner of the read and
 * the attempts it has left, read where the Validate action is. */
.deploy-progress {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-right: auto;
  margin-left: 0.75rem;
  font-size: 0.8125rem;
  color: var(--plot-ink-muted);
}

.deploy-spinner {
  flex: none;
  width: 0.75rem;
  height: 0.75rem;
  border: 1.5px solid var(--plot-hairline-strong);
  border-top-color: var(--plot-accent);
  border-radius: 999px;
  animation: deploy-spin 700ms linear infinite;
}

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

@media (prefers-reduced-motion: reduce) {
  .deploy-spinner {
    animation-duration: 2s;
  }
}
