/* 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;
  --plot-accent: #4f46e5;
  --plot-accent-soft: #eef0ff;
  --plot-accent-ink: #3730a3;
  --plot-danger: #b91c1c;

  --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 width of an ordinary page: the column the main screen is centred in,
   * and the width of the card a screen that asks one thing of the visitor
   * presents it in. */
  --plot-page-width: 56rem;
  --plot-card-width: 24rem;

  /* 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: 3.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);
}

.app-shell-brand {
  display: inline-flex;
  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 keeps the width of the Sidebar Layout of a
 * model screen, so the Model Navigation after it stands at the width of that
 * sidebar, over the body of the section it names. */
.app-shell-brand-cell {
  display: flex;
  flex: 0 0 15rem;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
  padding-right: 1rem;
}

/* The name of the model the screen is about, after the Plot logo. It gives
 * way to the cell it is held in rather than pushing the Model Navigation off
 * the width the cell keeps. */
.app-shell-context {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 1rem;
  font-weight: 500;
  color: var(--plot-ink-muted);
}

/* The navigation the top bar holds, and the identity beside it: the
 * navigation stands where the brand cell leaves it, and the identity is held
 * at the far end of the bar. */
.app-shell-navigation {
  display: flex;
  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.
 */
.app-shell-workspace .app-shell-main {
  padding: 0.75rem clamp(0.75rem, 2vw, 1.25rem) 1rem;
}

/*
 * 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);
}

/*
 * The Model Navigation: the sections of a model, read as a Pulldown menu in
 * the top bar. It is held at the width of the Sidebar Layout beside it, so the
 * menu stands over the body of the section it names.
 */
.model-navigation {
  display: inline-flex;
  align-items: center;
  gap: 0;
}

.model-navigation-menu {
  position: relative;
}

/* The section the screen shows, read as the title of the body below it. It is
 * the trigger of the section menu, which the caret that leads it names as a
 * menu rather than a heading that cannot be read further. It is read in the
 * size and weight of the Plot name beside it, and held at the width of a menu
 * so the whole menu drops from a title that is read as one. */
.model-navigation-trigger {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 12rem;
  padding: 0;
  border: 0;
  background: none;
  color: var(--plot-ink);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: -0.011em;
  cursor: pointer;
  list-style: none;
  transition: color 120ms ease;
}

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

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

.model-navigation-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;
}

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

.model-navigation-list {
  position: absolute;
  top: calc(100% + 0.5rem);
  left: 0;
  z-index: 30;
  min-width: 14rem;
  margin: 0;
  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%);
  list-style: none;
}

.model-navigation-item {
  display: block;
  padding: 0.5rem 0.75rem;
  border-radius: var(--plot-radius);
  color: var(--plot-ink-muted);
  font-size: 1rem;
  font-weight: 500;
  text-decoration: none;
  transition:
    background-color 120ms ease,
    color 120ms ease;
}

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

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

/*
 * 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.
 */
.model-management-layout,
.modelling-ui-region {
  display: flex;
  flex: 1 1 auto;
  align-items: stretch;
  gap: 1.25rem;
  min-height: 0;
}

.model-management-body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 1.25rem;
  min-width: 0;
}

/*
 * The Sidebar Layout. The Collapse toggle Button collapses it horizontally:
 * the sidebar keeps its rail and hides its folders and views.
 */
.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,
.sidebar-collapsed .sidebar-empty {
  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 a square the size of the arrow it is read by.
 */
.sidebar-collapse-toggle {
  flex: none;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  color: var(--plot-ink-faint);
}

.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 the row
 * it is over is read as the row it would be filed in: a drop is the file, so
 * the row it lands in is marked rather than the view it picks up. */
.sidebar-label-dragging {
  opacity: 0.5;
}

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

.sidebar-tree-drop {
  box-shadow: inset 0 0 0 2px 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-label {
  display: none;
}

/* The Add view Button is read in the shape of the Collapse toggle Button of the
 * footer: a small square the size of the arrow it is read by, held at the same
 * margin the footer is read at. */
.sidebar-add-view {
  flex: none;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  color: var(--plot-ink-faint);
}

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

.sidebar-label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  /* 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. */
  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. */
  padding: 0.4rem 0.5rem;
  border: 0;
  border-radius: var(--plot-radius);
  background: none;
  color: var(--plot-ink);
  font-size: 0.875rem;
  text-align: left;
  cursor: pointer;
  transition: background-color 120ms ease;
}

.sidebar-label: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-label-selected,
.sidebar-label-selected:hover {
  background-color: var(--plot-accent-soft);
  color: var(--plot-accent-ink);
}

/* 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 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. */
.sidebar-caret-disabled {
  color: var(--plot-hairline-strong);
}

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

/* A caret that is not offered is not turned either: an item that holds nothing
 * under it is read closed, rather than as the item it is not — an item that
 * unfolds. It is read after the turn, so the caret of an item that unfolds
 * nothing is the caret it is whatever the item is held open or shut. */
.sidebar-label[aria-expanded="true"] .sidebar-caret-disabled {
  transform: none;
}

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

.sidebar-empty {
  margin-top: 0.75rem;
  color: var(--plot-ink-faint);
  font-size: 0.8125rem;
}

.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. */
.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: 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;
}

.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 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.5rem;
  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 canvas below it holds
 * last, read as the chain that leads to the element. It is a header of the
 * canvas rather than a surface of its own, so it takes the height it asks
 * for and leaves the rest to the canvas.
 */
.modelling-context-viewer {
  flex: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.8125rem;
  line-height: 1.4;
}

.modelling-context-path {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem;
  list-style: none;
  margin: 0;
  padding: 0;
  color: var(--plot-ink-muted);
}

.modelling-context-item {
  display: flex;
  align-items: center;
  gap: 0.375rem;
}

.modelling-context-item + .modelling-context-item::before {
  content: "/";
  color: var(--plot-ink-faint);
}

.modelling-context-item[aria-current="page"] {
  color: var(--plot-ink);
  font-weight: 600;
}

/*
 * 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%;
}

/*
 * 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 held
   * at: 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 daisyUI components, quietened to the same voice as the rest: hairline
 * borders, flat surfaces, one accent.
 */
.btn {
  border-radius: var(--plot-radius);
  font-weight: 500;
  box-shadow: var(--plot-shadow);
}

.btn-ghost,
.btn-primary {
  box-shadow: none;
}

.btn-sm {
  font-size: 0.8125rem;
}

.input,
.select,
.textarea {
  border-color: var(--plot-hairline-strong);
  border-radius: var(--plot-radius);
  background-color: var(--plot-surface);
}

.input:focus,
.input:focus-within,
.select:focus,
.textarea:focus {
  border-color: var(--plot-accent);
  box-shadow: var(--plot-ring);
  outline: none;
}

.label {
  color: var(--plot-ink-muted);
  font-size: 0.8125rem;
  font-weight: 500;
}

/*
 * 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;
  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;
}

.identity-trigger {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  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;
}

.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.5rem;
  height: 1.5rem;
  border-radius: 9999px;
  background-color: var(--plot-accent-soft);
  color: var(--plot-accent-ink);
  font-size: 0.75rem;
  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 interface of the Account Menu: the row of video screens of the
 * session the member works in, the Session section of the menu, and the
 * Session dialog the member starts and stops a session from.
 *
 * 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-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: the width of a screen of a camera, in the height the
 * top bar leaves it. The top bar is 4rem tall, which is 3.5625rem of content
 * once its hairline is taken out, and the screen keeps 3px of the row above and
 * below it. */
.session-member {
  position: relative;
  height: 3.5625rem;
  aspect-ratio: 16 / 9;
  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;
}

.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 section offers an action of its own — starting a session — which
 * is a Button rather than a link to a screen of the model. */
.identity-action {
  width: 100%;
  border: 0;
  background-color: transparent;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.identity-nested {
  margin-top: 0.25rem;
}

.identity-nested-trigger {
  display: block;
  padding: 0.4rem 0.5rem;
  border-radius: var(--plot-radius);
  color: var(--plot-ink-muted);
  font-size: 0.75rem;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
  transition: background-color 120ms ease, color 120ms ease;
}

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

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

/* A session running in the model, which the members of the model join and
 * leave between: the members working in it, and the action they take on it. */
.identity-session {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  margin-bottom: 0.125rem;
  padding: 0.25rem 0.5rem;
  border-radius: var(--plot-radius);
  background-color: var(--plot-surface-sunken);
}

.identity-session-note {
  color: var(--plot-ink-faint);
  font-size: 0.6875rem;
}

.identity-session .identity-item {
  padding: 0.2rem 0;
  border: 0;
  background-color: transparent;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

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

/*
 * The Agenda Layout of the Model Agenda interface: the Strategy Browser
 * Layout beside the Plateau Planning Layout. The browser leads, because the
 * Single Click Event in it selects the element the planner renders; a narrow
 * workspace stacks them, so the browser stays the full width it needs.
 */
.agenda-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: start;
  gap: 1.5rem;
  min-height: 0;
}

@media (max-width: 64rem) {
  .agenda-layout {
    grid-template-columns: minmax(0, 1fr);
  }
}

.agenda-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;
}

.agenda-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 Strategy Browser Layout: the subgraph of the Strategy Elements of the
 * model. The browser is a box the size of the graph it lays out, so a graph
 * wider than the workspace scrolls sideways instead of shrinking its
 * elements.
 */
.strategy-browser-layout {
  min-width: 0;
}

.strategy-browser {
  position: relative;
  max-width: 100%;
  overflow: auto;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius-lg);
  background-color: var(--plot-surface);
}

.strategy-browser-edges {
  position: absolute;
  top: 0;
  left: 0;
}

.strategy-browser-edges line {
  stroke: var(--plot-hairline-strong);
  stroke-width: 1.5;
}

.strategy-browser-node {
  position: absolute;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.125rem;
  padding: 0.5rem 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;
  text-align: left;
  cursor: pointer;
  transition:
    border-color 120ms ease,
    box-shadow 120ms ease,
    background-color 120ms ease;
}

.strategy-browser-node:hover {
  border-color: var(--plot-accent);
}

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

.strategy-browser-node[aria-pressed="true"] {
  border-color: var(--plot-accent);
  background-color: var(--plot-accent-soft);
  box-shadow: var(--plot-ring);
}

.strategy-browser-node-name {
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.2;
}

.strategy-browser-node-type {
  color: var(--plot-ink-faint);
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/*
 * The Plateau Planning Layout: the plan of the selected Strategy Element, as
 * the name of each Plateau beside the Date Scheduler that schedules it and the
 * Edit Button that moves to the Model Design section of the Plateau. The plan
 * is headed by the Date Scale of the axis its Date Sliders are drawn on, so
 * the rows read as the weeks they are planned over.
 */
.plateau-planner-layout {
  min-width: 0;
}

.plateau-planner {
  --plateau-planner-name-column: 12rem;
  --plateau-planner-edit-column: 3rem;
  --thumb: 0.875rem;

  padding: 1rem;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius-lg);
  background-color: var(--plot-surface);
}

/*
 * The three columns of a plan: the name of a Plateau, the Date Slider of it,
 * and the Edit Button that moves to its design. The head row of the plan holds
 * the Date Scale of the axis in the column of the Date Sliders and nothing in
 * the columns of the names and of the Edit Buttons, so the scale reads as the
 * header of the sliders it is above.
 *
 * The head holds a border the rows hold too, so the columns of the scale and
 * of the sliders are the same width. Every row is a grid of its own, so the
 * columns of a plan are sized rather than fitted to what a row holds: a fitted
 * column would be the width of the widest Plateau of one row, and the Date
 * Sliders of one plan would not be drawn on the same track.
 */
.plateau-planner-head,
.plateau-planner-item {
  display: grid;
  grid-template-columns:
    var(--plateau-planner-name-column) minmax(0, 1fr)
    var(--plateau-planner-edit-column);
  gap: 0.75rem;
  padding: 0 0.75rem;
}

.plateau-planner-head {
  align-items: center;
  min-height: 1.5rem;
  margin-bottom: 0.25rem;
  border: 1px solid transparent;
}

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

.plateau-planner-item {
  align-items: center;
  padding-block: 0.5rem;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius);
  background-color: var(--plot-surface-muted);
}

.plateau-planner-name {
  margin: 0;
  overflow: hidden;
  font-size: 0.8125rem;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/*
 * The Edit Button of a Plateau of a plan: it moves to the Model Design section
 * the Plateau designs in, so the plan of an element reads beside the design of
 * the Plateau that realizes it.
 */
.plateau-planner-edit {
  justify-self: center;
}

/*
 * The Date Scale of a plan: the weeks of the axis the Date Sliders of the plan
 * are drawn on, each named by the Monday it starts on, and the day the plan is
 * read on.
 *
 * A week is placed by the day it starts on rather than as an equal share of
 * the scale, so the weeks of the scale fall on the days the handles of the
 * sliders are placed at. For the same reason the scale is inset by half a
 * handle: a handle sits on the day it holds at the centre of its own width.
 *
 * The weeks are named on the first line of the scale and the day the plan is
 * read on is marked on the second, because the plan is read in the week the
 * axis starts on: a dot on the line of the names would cover the first of them.
 */
.date-scale {
  position: relative;
  height: 1.75rem;
  margin-inline: calc(var(--thumb) / 2);
  border-right: 1px solid var(--plot-hairline);
}

.date-scale-week {
  position: absolute;
  top: 0;
  bottom: 0;
  display: flex;
  align-items: flex-start;
  padding-left: 0.25rem;
  border-left: 1px solid var(--plot-hairline);
}

.date-scale-label {
  color: var(--plot-ink-faint);
  font-size: 0.6875rem;
  font-variant-numeric: tabular-nums;
  line-height: 1.25rem;
  white-space: nowrap;
}

.date-scale-today {
  position: absolute;
  bottom: 0.25rem;
  width: 0.375rem;
  height: 0.375rem;
  border-radius: 50%;
  background-color: var(--plot-accent);
  transform: translate(-50%, 50%);
}

/*
 * The Add Plateau form of the Plateau Planning Layout: the name of the Plateau
 * the person adds to the plan of the selected Strategy Element.
 */
.plateau-planner-add {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.75rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--plot-hairline);
}

.plateau-planner-add input {
  flex: 1;
  min-width: 0;
}

/*
 * The Date Scheduler Layout: the Date Slider of a Plateau. The Date Slider is
 * one slider, whose two handles — the Start Date and the End Date of the
 * Plateau Element — share the axis of the plan.
 *
 * The track draws the rail and the span the two handles hold between them,
 * and `--start`/`--end` are the percentage each handle sits at, so the span
 * runs from one handle centre to the other. The Date Slider Hook moves a
 * handle as it is dragged, and takes the percentage the server renders again
 * on every patch.
 */
.date-scheduler-layout {
  min-width: 0;
}

.date-slider {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}

.date-slider-track {
  --thumb: 0.875rem;

  position: relative;
  height: 1.25rem;
}

.date-slider-rail {
  position: absolute;
  top: 50%;
  right: calc(var(--thumb) / 2);
  left: calc(var(--thumb) / 2);
  height: 0.25rem;
  border-radius: 999px;
  background-color: var(--plot-hairline-strong);
  transform: translateY(-50%);
}

.date-slider-span {
  position: absolute;
  top: 50%;
  left: calc(var(--thumb) / 2 + (100% - var(--thumb)) * var(--start) / 100);
  right: calc(var(--thumb) / 2 + (100% - var(--thumb)) * (100 - var(--end)) / 100);
  height: 0.25rem;
  border-radius: 999px;
  background-color: var(--plot-accent);
  transform: translateY(-50%);
}

.date-slider-handle {
  position: absolute;
  top: 50%;
  left: calc(var(--thumb) / 2 + (100% - var(--thumb)) * var(--x) / 100);
  width: var(--thumb);
  height: var(--thumb);
  border: 2px solid var(--plot-surface);
  border-radius: 50%;
  background-color: var(--plot-accent);
  box-shadow: 0 0 0 1px var(--plot-hairline-strong);
  transform: translate(-50%, -50%);
  cursor: grab;
  touch-action: none;
}

.date-slider-handle[data-endpoint="start"] {
  --x: var(--start);
}

.date-slider-handle[data-endpoint="end"] {
  --x: var(--end);
}

.date-slider-handle:active {
  cursor: grabbing;
}

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

.date-scheduler-unscheduled {
  margin: 0;
  color: var(--plot-ink-muted);
  font-size: 0.8125rem;
}

/*
 * The Build Layout of the Model Build interface: the Delivery Source
 * Selector Layout beside the Delivery Run Configurator Layout. The selector
 * leads, because the Single Click Event in it selects the source the
 * configurator loads; a narrow workspace stacks them, so the selector stays
 * the full width it needs.
 */
.build-layout {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
  align-items: start;
  gap: 1.5rem;
  min-height: 0;
}

@media (max-width: 64rem) {
  .build-layout {
    grid-template-columns: minmax(0, 1fr);
  }
}

.delivery-source-selector,
.delivery-run-configurator {
  min-width: 0;
}

.delivery-source-list {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-height: 32rem;
  margin: 0;
  padding: 1rem;
  overflow-y: auto;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius-lg);
  background-color: var(--plot-surface);
  list-style: none;
}

.delivery-source-group {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}

.delivery-source-plateau {
  margin: 0;
  color: var(--plot-ink-faint);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.delivery-source-items {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

/*
 * The tree of a Plateau: a node of the lineage below the Plateau holds the
 * nodes below it, so a tree reads as the way the Plateau composes its
 * Delivery Sources rather than as one level of them. The children of a node
 * are indented and ruled against the node they hang from.
 */
.delivery-source-node {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.delivery-source-children {
  padding-inline-start: 0.75rem;
  border-inline-start: 1px solid var(--plot-hairline);
}

/*
 * The name of a node of the tree that is no Work Package or Deliverable: it
 * holds the Delivery Sources below it without being one, so it reads as the
 * group of them rather than as a source a person selects.
 */
.delivery-source-node-name {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  margin: 0;
  padding: 0.25rem 0.75rem;
  color: var(--plot-ink-muted);
  font-size: 0.8125rem;
}

/*
 * The Delivery Source item: the Work Package or Deliverable a Delivery Run
 * delivers. A single click on it is the Single Click Event the selector
 * reports, so it reads like the node of the Strategy Browser.
 */
.delivery-source-item {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  width: 100%;
  padding: 0.5rem 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;
  text-align: left;
  cursor: pointer;
  transition:
    border-color 120ms ease,
    box-shadow 120ms ease,
    background-color 120ms ease;
}

.delivery-source-item:hover {
  border-color: var(--plot-accent);
}

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

.delivery-source-item[aria-pressed="true"] {
  border-color: var(--plot-accent);
  background-color: var(--plot-accent-soft);
  box-shadow: var(--plot-ring);
}

.delivery-source-item-name {
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.2;
}

.delivery-source-item-type {
  color: var(--plot-ink-faint);
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/*
 * The error a Delivery Source the model does not place exactly once is read
 * by: the source is not a button, because the visual state a Delivery Run
 * delivers is the single view node that places it, so it reads as the source
 * that cannot be selected rather than as one a person selects.
 */
.delivery-source-item-error {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  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-sm);
  color: var(--plot-danger);
}

.delivery-source-item-error-message {
  font-size: 0.75rem;
  line-height: 1.3;
}

/*
 * The Delivery Run Configurator Layout: the run of the selected Delivery
 * Source, and the form of a new Delivery Run with it.
 */
.delivery-run-configurator-body {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.delivery-run-source {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius);
  background-color: var(--plot-surface-muted);
}

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

.delivery-run-source-name {
  font-size: 0.9375rem;
  font-weight: 600;
}

.delivery-run-source-plateau {
  color: var(--plot-ink-faint);
  font-size: 0.75rem;
}

/*
 * The Deliveries overview: the deliveries of a model, newest launch first.
 * It presents the Delivery Runs the Delivery Run Configurator configures.
 */
.deliveries-overview {
  min-width: 0;
}

.deliveries-overview-header {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.deliveries-overview-intro {
  margin: 0;
  color: var(--plot-ink-muted);
  font-size: 0.875rem;
}

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

.delivery-run-item {
  padding: 0.75rem;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius);
  background-color: var(--plot-surface);
}

.delivery-run-fields {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
  gap: 0.5rem 1rem;
  margin: 0;
}

.delivery-run-field {
  min-width: 0;
}

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

.delivery-run-field-value {
  margin: 0;
  overflow: hidden;
  font-size: 0.875rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/*
 * The Launch Agent Button of a Delivery Run: the action of the run, which
 * launches the run whether or not a launch of it is already held, because a
 * launch outlives the click that started it.
 */
.delivery-run-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.75rem;
}

/*
 * The Delete Button of a Delivery Run is reached from the delivery it presents,
 * so it is held at the end of the row rather than beside the fields of the run.
 */
.delivery-run-delete {
  margin-left: auto;
}

/* A run whose build is running is deleted once the build of it ended rather
 * than under it, so the button of it is presented as one that is not taken
 * now. */
.delivery-run-delete:disabled {
  color: var(--plot-ink-faint);
  cursor: default;
  opacity: 0.6;
}

/* The confirmation of a Deletion: the Delivery Run is removed from the
 * deployment for good, so the action is presented as the destructive one it
 * is. */
.delivery-run-delete-confirm {
  border-color: color-mix(in oklab, var(--plot-danger) 45%, var(--plot-hairline));
  color: var(--plot-danger);
}

/* The Delivery Run a Deletion Confirmation names: the Delivery Source it
 * delivers and the step of the delivery it is at. */
.delivery-run-delete-run {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  margin: 0;
}

.delivery-run-delete-source {
  font-size: 0.875rem;
  font-weight: 600;
}

.delivery-run-delete-status {
  color: var(--plot-ink-faint);
  font-size: 0.75rem;
}

.delivery-run-form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  gap: 0.75rem;
  padding: 1rem;
  border: 1px solid var(--plot-hairline);
  border-radius: var(--plot-radius-lg);
  background-color: var(--plot-surface);
}

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

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

.delivery-run-form .btn {
  grid-column: 1 / -1;
  justify-self: start;
}

/*
 * The Plateau Repository of the Delivery Source header: the state the Plateau
 * holds as a compact status beside the Configure Button that opens the
 * selection of the Repositories the accesses of the account reach.
 */
.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;
}

.plateau-repository-access-name {
  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-field {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
}

.plateau-repository-field .input {
  width: 100%;
}

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

.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.
 */
.ai-models-settings {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  padding-block: 1rem;
}

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

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

.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-input {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
}

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

.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.
 */
.repositories-settings {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  padding-block: 1rem;
}

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

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

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

.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);
}

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

/*
 * 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-settings {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  padding-block: 1rem;
}

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

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

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

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

.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;
}

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

/* 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;
}

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

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

/* 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;
}

.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.
 */
.agent-settings {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  padding-block: 1rem;
}

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

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

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

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

/* 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;
}
