/* Reusable UI pieces: buttons, cards, tabs, menus, tables and feedback. */

/* ---- Buttons ---- */
.icon-btn {
  display: inline-grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--ink-2);
}

.icon-btn:hover {
  background: var(--hover);
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 36px;
  padding-inline: 20px;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--surface);
  color: var(--blue);
  font-weight: 500;
}

.btn:hover {
  background: var(--blue-wash);
  text-decoration: none;
}

.btn--primary {
  border-color: var(--blue);
  background: var(--blue);
  color: #fff;
}

.btn--primary:hover {
  background: var(--blue-strong);
}

.link-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: 36px;
  padding: 0 8px;
  border: 0;
  border-radius: 4px;
  background: none;
  color: var(--blue);
  font-weight: 500;
  white-space: nowrap;
}

.link-btn:hover {
  background: var(--blue-wash);
  text-decoration: none;
}

.avatar {
  display: inline-grid;
  place-items: center;
  width: 32px;
  height: 32px;
  margin-left: 4px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: #5e35b1;
  color: #fff;
  font-weight: 500;
}

.avatar--sm {
  width: 28px;
  height: 28px;
  margin: 0;
  background: var(--blue-wash);
  color: var(--blue);
  font-size: 12px;
}

/* ---- Cards ---- */
.card {
  display: flex;
  flex-direction: column;
  min-width: 0;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

/*
 * A form filling a page needs no frame either: the rules between its sections and the bar at the
 * bottom say where it begins and ends. Inside a side panel the sheet is the frame, so only the page
 * loses the padding that went with the border.
 */
.card--plain {
  border: 0;
  border-radius: 0;
  background: none;
}

.content__inner .card--plain > .settings-section,
.content__inner .card--plain > .card__footer {
  padding-inline: 0;
}

.content__inner .card--plain > .form-error {
  margin-inline: 0;
}

/*
 * A list of rows needs no frame around it: the header rule and the row lines carry the structure, so
 * the table meets the page instead of sitting in a box.
 */
.card--table {
  border: 0;
  border-radius: 0;
  background: none;
}

/* Nothing frames the page, so what sits above the table lines up with the table's own first column. */
.card--table > .tabs,
.card--table > [role="tabpanel"] > .card__intro {
  margin-inline: 0;
  padding-inline: 0;
}

/* The first tab's own padding would push its name in past the first column heading. */
.card--table > .tabs > .tab:first-child {
  padding-left: 4px;
}

/* Filters and Columns sitting at the top of the table have nothing above them inside it, so they
   draw no line: whatever comes before the table, such as the tab strip, already has one. */
.card--table .card__bleed > .data-table__actions:first-child {
  border-top: 0;
}

/* With no frame to sit inside, the line under the open tab marks out its name and nothing more. */
.card--table > .tabs > .tab::after {
  right: 20px;
  left: 20px;
}

.card--table > .tabs > .tab:first-child::after {
  left: 4px;
}

/* The search and filters sit above the table with nothing but space between. */
.card--table > .toolbar {
  padding: 4px 0 12px;
  border-bottom: 0;
}

/* Cells line up with the page rather than with a frame that is no longer there. */
.card--table .data-table th:first-child,
.card--table .data-table td:first-child {
  padding-left: 4px;
}

.card--table .data-table th:last-child,
.card--table .data-table td:last-child {
  padding-right: 4px;
}

/* A row lights up past the text, so the highlight doesn't stop short at the first column. */
.card--table .data-table tbody tr:hover td:first-child {
  border-top-left-radius: var(--radius);
  border-bottom-left-radius: var(--radius);
}

.card--table .data-table tbody tr:hover td:last-child {
  border-top-right-radius: var(--radius);
  border-bottom-right-radius: var(--radius);
}

/* Page numbers under the table, with no box around them. */
.card--table > .card__bleed > .data-table__actions {
  padding-inline: 4px;
}

.card__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
  padding: 16px 20px 8px;
}

.card__title {
  margin: 0;
  font-size: 16px;
  font-weight: 500;
  line-height: 24px;
}

.card__subtitle {
  margin: 2px 0 0;
  color: var(--ink-2);
  font-size: 13px;
  line-height: 18px;
}

.card__body {
  flex: 1;
  padding: 8px 20px 16px;
}

.card__bleed {
  flex: 1;
}

.card__footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 16px;
  min-height: 52px;
  padding: 8px 12px 8px 20px;
  border-top: 1px solid var(--line);
}

.card__footer--end {
  justify-content: flex-end;
}

/* No rule above the buttons, where the card is one short section and the line would divide nothing. */
.card__footer--plain {
  border-top: 0;
}

.card__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-left: auto;
}

[data-range-scope] {
  transition: opacity 0.15s ease;
}

.is-refreshing [data-range-scope] {
  opacity: 0.5;
}

/* ---- Home layout ---- */
.home-grid {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(300px, 1fr);
  gap: 24px;
  align-items: start;
}

.section-title {
  margin: 32px 0 16px;
  font-size: 18px;
  font-weight: 400;
  line-height: 24px;
}

.insight-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 24px;
  align-items: start;
}

@media (max-width: 1200px) {
  .home-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media (max-width: 440px) {
  .insight-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ---- KPI tabs ---- */
.kpi-tabs {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  border-bottom: 1px solid var(--line);
}

.kpi-tab {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  min-width: 0;
  padding: 16px 20px 14px;
  border: 0;
  border-right: 1px solid var(--line);
  background: var(--surface-alt);
  text-align: left;
}

.kpi-tab:last-child {
  border-right: 0;
}

.kpi-tab:hover {
  background: var(--field);
}

.kpi-tab[aria-selected="true"] {
  background: var(--surface);
}

.kpi-tab[aria-selected="true"]::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 3px;
  background: var(--blue);
}

.kpi-tab:focus-visible {
  outline-offset: -2px;
}

.kpi-tab__label {
  color: var(--ink-2);
}

.kpi-tab__value {
  font-size: 28px;
  line-height: 36px;
  white-space: nowrap;
}

.kpi-tab__delta {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  min-height: 20px;
  font-size: 13px;
  font-weight: 500;
}

[data-tone="good"] {
  color: var(--good);
}

[data-tone="bad"] {
  color: var(--bad);
}

[data-tone="flat"] {
  color: var(--neutral);
}

.overview-card__body {
  padding: 20px 20px 12px;
}

@media (max-width: 640px) {
  .kpi-tabs {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .kpi-tab:nth-child(2n) {
    border-right: 0;
  }

  .kpi-tab:nth-child(-n + 2) {
    border-bottom: 1px solid var(--line);
  }

  .kpi-tab {
    padding-inline: 16px;
  }

  .kpi-tab__value {
    font-size: 24px;
    line-height: 32px;
  }
}

/* ---- Realtime card ---- */
.realtime-card__value {
  margin: 0 0 12px;
  font-size: 48px;
  font-weight: 400;
  line-height: 56px;
}

.realtime-card__axis {
  display: flex;
  justify-content: space-between;
  margin: 6px 0 12px;
  color: var(--ink-3);
  font-size: 12px;
}

.realtime-card__table {
  margin-inline: -20px;
}

/* ---- Date range picker ---- */
.date-range {
  position: relative;
}

.date-range__button {
  display: flex;
  align-items: center;
  gap: 12px;
  height: 40px;
  padding: 0 8px 0 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

.date-range__button:hover {
  background: var(--surface-alt);
}

.date-range__preset {
  color: var(--ink-2);
}

.date-range__dates {
  font-weight: 500;
  white-space: nowrap;
}

.date-range__menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  z-index: 45;
  min-width: 280px;
  padding-block: 8px;
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-raised);
}

.date-range__option {
  display: grid;
  grid-template-columns: 24px 1fr;
  column-gap: 12px;
  width: 100%;
  padding: 8px 20px 8px 12px;
  border: 0;
  background: none;
  text-align: left;
}

.date-range__option:hover {
  background: var(--hover);
}

.date-range__option:focus-visible {
  outline-offset: -2px;
}

.date-range__check {
  grid-row: span 2;
  align-self: center;
  color: var(--blue);
  font-size: 20px;
  font-variation-settings: "FILL" 0, "wght" 700, "GRAD" 0, "opsz" 20;
  visibility: hidden;
}

.date-range__option[aria-checked="true"] .date-range__check {
  visibility: visible;
}

.date-range__option[aria-checked="true"] .date-range__option-label {
  font-weight: 500;
}

.date-range__option-dates {
  grid-column: 2;
  color: var(--ink-3);
  font-size: 12px;
  line-height: 16px;
}

@media (max-width: 560px) {
  .date-range__preset {
    display: none;
  }
}

/* ---- Tables ---- */
.table-wrap {
  overflow-x: auto;
}

/* A table's own toolbar, filter row and pager. */
/* Filters sit at the right of the page's search row, or above the table when there is none. */
.data-table__actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
}

.card__bleed > .data-table__actions {
  justify-content: flex-end;
  padding: 8px 16px;
  border-top: 1px solid var(--grid);
}

.btn--small {
  height: 32px;
  padding-inline: 12px;
  font-size: 13px;
}

.btn--small .ms {
  font-size: 18px;
}

.btn.is-on {
  border-color: var(--blue-track);
  background: var(--blue-wash);
}

.data-table__sort {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

.data-table__sort:hover {
  color: var(--ink);
}

.num .data-table__sort {
  flex-direction: row-reverse;
}

.data-table__arrow {
  font-size: 16px;
  opacity: 0;
}

.data-table__sort:hover .data-table__arrow {
  opacity: 0.5;
}

.data-table__arrow.is-sorted {
  color: var(--blue);
  opacity: 1;
}

.data-table__filters th {
  padding: 6px 12px 10px;
  border-bottom: 1px solid var(--line);
}

.data-table__columns-wrap {
  position: relative;
}

.data-table__columns {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  z-index: 40;
  display: grid;
  min-width: 200px;
  padding: 8px 0;
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-raised);
}

.data-table__column {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 16px;
  cursor: pointer;
}

.data-table__column:hover {
  background: var(--hover);
}

.data-table__filter {
  width: 100%;
  min-width: 96px;
  height: 32px;
  padding-inline: 8px;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 13px;
}

.data-table__filter:focus-visible {
  border-color: var(--blue);
  outline: none;
}

.data-table__pager {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 20px;
  padding: 10px 16px;
  border-top: 1px solid var(--line);
  color: var(--ink-2);
  font-size: 13px;
}

.data-table__count {
  flex: 1;
  white-space: nowrap;
}

.data-table__per-page {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.data-table__size {
  height: 32px;
  padding-inline: 6px;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 13px;
}

.data-table__steps {
  display: inline-flex;
  align-items: center;
  gap: 2px;
}

.data-table__page {
  padding-inline: 8px;
  white-space: nowrap;
}

.data-table__step {
  width: 32px;
  height: 32px;
}

.data-table__step .ms {
  font-size: 20px;
}

.data-table__step:disabled {
  opacity: 0.38;
}

.data-table__step:disabled:hover {
  background: none;
}

@media (max-width: 640px) {
  .data-table__count {
    flex: 1 0 100%;
  }
}

.data-table {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}

/* A row lights up under the pointer, the same way a scope item does. */
.data-table tbody tr:hover {
  background: var(--hover);
}

/* Nothing to point at: the "nothing yet" line and the bars shown while a table loads. */
.data-table tbody tr:has(.data-table__empty):hover,
.data-table tbody tr:has(.skeleton):hover {
  background: none;
}

.data-table th {
  padding: 10px 16px;
  border-bottom: 1px solid var(--line);
  color: var(--ink-2);
  font-size: 12px;
  font-weight: 500;
  text-align: left;
  white-space: nowrap;
}

.data-table td {
  padding: 10px 16px;
  border-bottom: 1px solid var(--grid);
  vertical-align: middle;
}

.data-table tr:last-child td {
  border-bottom: 0;
}

.data-table th:first-child,
.data-table td:first-child {
  padding-left: 20px;
}

.data-table th:last-child,
.data-table td:last-child {
  padding-right: 20px;
}

.data-table .num {
  text-align: right;
  white-space: nowrap;
}

.data-table__empty {
  color: var(--ink-2);
  text-align: center;
}

.bar-cell {
  display: grid;
  gap: 6px;
  min-width: 140px;
}

.bar-cell__track {
  height: 4px;
  overflow: hidden;
  border-radius: 2px;
  background: var(--blue-track);
}

.bar-cell__fill {
  display: block;
  width: var(--share, 0%);
  height: 100%;
  border-radius: 2px;
  background: var(--blue);
}

.person-cell {
  display: flex;
  align-items: center;
  gap: 12px;
}

.person-cell__name {
  display: block;
}

.person-cell__role {
  display: block;
  color: var(--ink-2);
  font-size: 12px;
  line-height: 16px;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 13px;
  white-space: nowrap;
}

/* A status on a tinted pill, beside a heading. */
.chip--badge {
  padding: 3px 10px 3px 6px;
  border-radius: 999px;
  background: var(--field);
  font-weight: 500;
  line-height: 18px;
}

.chip--badge[data-tone="good"] {
  background: var(--good-wash);
}

.chip--badge[data-tone="bad"] {
  background: var(--bad-wash);
}

.chip--badge .ms {
  font-variation-settings: "FILL" 1;
}

/* ---- Feedback ---- */
.empty-state {
  display: grid;
  justify-items: center;
  max-width: 560px;
  margin: 48px auto;
  padding: 40px 32px;
  text-align: center;
}

.empty-state__icon {
  color: var(--ink-3);
  font-size: 40px;
}

.empty-state__title {
  margin: 16px 0 8px;
  font-size: 20px;
  font-weight: 400;
  line-height: 28px;
}

.empty-state__text {
  max-width: 44ch;
  margin: 0 auto 24px;
  color: var(--ink-2);
}

.toast {
  position: fixed;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 24px);
  left: 50%;
  z-index: 60;
  width: max-content;
  max-width: min(560px, calc(100vw - 32px));
  padding: 14px 16px;
  border-radius: 4px;
  background: #323232;
  color: #fff;
  box-shadow: var(--shadow-raised);
  opacity: 0;
  transform: translate(-50%, 8px);
  visibility: hidden;
  transition: opacity 0.15s ease, transform 0.15s ease, visibility 0s linear 0.15s;
}

.toast.is-visible {
  opacity: 1;
  transform: translate(-50%, 0);
  visibility: visible;
  transition: opacity 0.15s ease, transform 0.15s ease;
}

.row-actions__item {
  display: flex;
  justify-content: flex-start;
  align-items: center;
  gap: 12px;
  padding: 10px 20px;
  border: 0;
  background: none;
  color: var(--ink);
  font-size: 14px;
  text-align: left;
  cursor: pointer;
}

.row-actions__item:hover {
  background: var(--field);
}

.row-actions__item .ms {
  color: var(--ink-2);
  font-size: 20px;
}

/* ---- One three-dot button per table row, holding that row's actions ---- */
.row-actions {
  position: relative;
  display: inline-block;
}

.row-actions__button {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--ink-2);
  cursor: pointer;
}

.row-actions__button:hover {
  background: var(--field);
  color: var(--ink);
}

.row-actions__menu {
  position: fixed;
  z-index: 40;
  display: grid;
  min-width: 200px;
  padding: 8px 0;
  border-radius: 8px;
  background: var(--surface);
  box-shadow: var(--shadow-raised);
}

.row-actions__item--danger,
.row-actions__item--danger .ms {
  color: var(--danger);
}

/* ---- Rows that can be dragged into a new order ---- */
.sortable-cell {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}

.sortable-cell__handle {
  margin-top: 2px;
  color: var(--ink-3);
  cursor: grab;
}

.sortable-cell__spacer {
  width: 24px;
}

tr[data-sortable] {
  cursor: grab;
}

tr[data-sortable]:hover {
  background: var(--surface-alt);
}

tr.is-dragging {
  opacity: 0.5;
  background: var(--blue-wash);
}

/* ---- Placeholders shown while a page waits for its data ---- */
.skeleton {
  display: block;
  height: 14px;
  border-radius: 4px;
  background: linear-gradient(90deg, var(--grid) 25%, var(--field) 37%, var(--grid) 63%);
  background-size: 400% 100%;
  animation: skeleton-sheen 1.4s ease infinite;
}

.skeleton-card {
  display: grid;
  gap: 16px;
  padding: 24px;
}

@keyframes skeleton-sheen {
  from { background-position: 100% 50%; }
  to { background-position: 0 50%; }
}

@media (prefers-reduced-motion: reduce) {
  .skeleton {
    background: var(--grid);
    animation: none;
  }
}

/* ---- Choosing the services an organization offers ---- */
.field-group {
  margin-top: 8px;
}

.field-group__title {
  margin: 0;
  font-weight: 500;
}

.field-group__text {
  margin: 2px 0 12px;
  color: var(--ink-2);
  font-size: 13px;
  line-height: 18px;
}

.service-picker {
  display: grid;
  gap: 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 12px;
}

.service-picker__head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 8px;
  border-bottom: 1px solid var(--grid);
}

.service-picker__head .ms {
  color: var(--ink-2);
}

.service-picker__search {
  flex: 1;
  height: 40px;
  border: 0;
  outline: none;
  background: none;
  color: var(--ink);
  font-size: 14px;
}

.service-picker__chosen {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.service-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 8px 4px 12px;
  border: 0;
  border-radius: 999px;
  background: var(--blue-wash);
  color: var(--blue);
  font-size: 13px;
  cursor: pointer;
}

.service-chip:hover {
  background: var(--blue-track);
}

.service-picker__list {
  display: grid;
  gap: 16px;
  max-height: 320px;
  padding: 4px;
  overflow-y: auto;
}

.service-picker__group-name {
  margin: 0 0 4px;
  color: var(--ink-2);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.service-picker__option .field__helper {
  padding: 0 0 4px;
}

.service-picker__option label {
  display: flex;
  align-items: center;
  gap: 8px;
}

.service-picker__own {
  padding: 0 8px;
  border-radius: 999px;
  background: var(--field);
  color: var(--ink-2);
  font-size: 11px;
}

.service-picker__summary,
.service-picker__empty {
  margin: 0;
  color: var(--ink-2);
  font-size: 13px;
}

/* ---- A block that repeats on a form, such as one contact or one address ---- */
.repeatable {
  display: grid;
  gap: 4px;
  margin-bottom: 12px;
  padding: 12px 16px 4px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

.repeatable__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 4px;
}

.repeatable__title {
  margin: 0;
  color: var(--ink-2);
  font-size: 13px;
  font-weight: 500;
}

/* A short type picker beside the value it describes. */
.form-row--type-first {
  grid-template-columns: minmax(130px, 1fr) minmax(0, 2fr);
}

/* ---- What was picked, shown as a card instead of a text box ---- */
.picked-card {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 16px;
  padding: 12px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

/*
 * Among form fields, a card has no helper line under it, so the notched label of the next field would
 * sit on its bottom edge. This is the room that line would have taken.
 */
.settings-section__fields > .picked-card,
.settings-section__fields > .check,
.settings-section__fields .form-stack > .picked-card {
  margin-bottom: 12px;
}

.picked-card__logo {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
}

/* A suggestion with a picture: the picture to the left of the name and the line under it. */
.combobox__option:has(.combobox__image) {
  grid-template-columns: 32px minmax(0, 1fr);
  column-gap: 12px;
  align-items: center;
}

.combobox__image {
  grid-row: span 2;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  object-fit: cover;
}

.picked-card__icon {
  display: grid;
  flex: none;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--blue-wash);
  color: var(--blue);
}

/* When the card gets narrow, its buttons drop under the text rather than squeezing it. */
.picked-card__text {
  flex: 1 1 160px;
  min-width: 0;
}

.picked-card__name {
  margin: 0;
  font-weight: 500;
}

.picked-card__meta {
  margin: 2px 0 0;
  color: var(--ink-2);
  font-size: 13px;
  overflow-wrap: anywhere;
}

.picked-card > .btn,
.picked-card__actions {
  margin-left: auto;
}

.picked-card__actions {
  display: flex;
  flex: none;
  gap: 4px;
}

/* ---- A box that suggests as you type ---- */
.combobox {
  position: relative;
}

.combobox__list {
  position: absolute;
  top: calc(100% - 20px);
  left: 0;
  right: 0;
  z-index: 40;
  display: grid;
  max-height: 280px;
  padding: 8px 0;
  overflow-y: auto;
  border-radius: 8px;
  background: var(--surface);
  box-shadow: var(--shadow-raised);
}

.combobox__option {
  display: grid;
  gap: 2px;
  padding: 10px 16px;
  border: 0;
  background: none;
  color: var(--ink);
  font-size: 14px;
  text-align: left;
  cursor: pointer;
}

.combobox__option:hover,
.combobox__option:focus-visible {
  background: var(--field);
}

/* The "add new" link under the suggestions, set apart from them by a rule. */
.combobox__footer {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  padding: 12px 16px 4px;
  border: 0;
  border-top: 1px solid var(--grid);
  background: none;
  color: var(--blue);
  font-size: 14px;
  font-weight: 500;
  text-align: left;
  cursor: pointer;
}

.combobox__footer:hover span:last-child,
.combobox__footer:focus-visible span:last-child {
  text-decoration: underline;
}

.combobox__meta,
.combobox__empty {
  color: var(--ink-2);
  font-size: 12px;
}

.combobox__empty {
  margin: 0;
  padding: 8px 16px;
}

/* ---- Attaching files ---- */
.dropzone {
  display: grid;
  justify-items: center;
  gap: 4px;
  padding: 24px;
  border: 1px dashed var(--ink-3);
  border-radius: var(--radius);
  color: var(--ink-2);
  text-align: center;
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}

.dropzone:hover,
.dropzone.is-dragging {
  border-color: var(--blue);
  background: var(--blue-wash);
  color: var(--ink);
}

.dropzone .ms {
  font-size: 28px;
}

.dropzone__hint {
  font-size: 12px;
}

/* Attached files as 140px tiles: a preview that opens the file, then its name and Remove. */
.file-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 140px));
  gap: 12px;
  margin-top: 12px;
}

.file-list__empty {
  grid-column: 1 / -1;
  margin: 0;
  color: var(--ink-2);
  font-size: 13px;
}

.file-tile {
  display: flex;
  flex-direction: column;
  min-width: 0;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

.file-tile__preview {
  position: relative;
  display: grid;
  place-items: center;
  width: 100%;
  aspect-ratio: 4 / 3;
  padding: 0;
  overflow: hidden;
  border: 0;
  border-bottom: 1px solid var(--grid);
  background: var(--surface-alt);
  cursor: pointer;
}

.file-tile__preview:hover {
  background: var(--field);
}

.file-tile__preview:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: -2px;
}

.file-tile__image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.file-tile__icon {
  color: var(--ink-3);
  font-size: 40px;
}

.file-tile__preview--pdf .file-tile__icon {
  color: var(--bad);
}

/* A file chosen for a project that hasn't been saved yet. */
.file-tile__badge {
  position: absolute;
  bottom: 6px;
  left: 6px;
  padding: 1px 8px;
  border-radius: 999px;
  background: rgb(32 33 36 / 72%);
  color: #fff;
  font-size: 11px;
  line-height: 18px;
}

.file-tile__foot {
  display: grid;
  gap: 2px;
  padding: 8px 10px 10px;
}

.file-tile__name {
  justify-self: start;
  max-width: 100%;
  padding: 0;
  overflow: hidden;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  font-size: 13px;
  line-height: 18px;
  text-align: left;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
}

.file-tile__name:hover {
  text-decoration: underline;
}

.file-tile__remove {
  justify-self: start;
  padding: 0;
  border: 0;
  background: none;
  color: var(--bad);
  font-size: 12px;
  font-weight: 500;
  line-height: 18px;
}

.file-tile__remove:hover {
  text-decoration: underline;
}

/* Two to a row on a phone, sharing the width. */
@media (max-width: 440px) {
  .file-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ---- Scope items: a summary line, then accordion rows that open to their services ---- */
/* One column that can shrink below its content, so a wide services table scrolls inside its own box. */
.scope {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
}

.scope > .scope__head {
  justify-content: flex-end;
}

.scope__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 16px;
  padding: 16px 20px;
}

.scope__summary {
  margin: 0;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

.accordion-list {
  border-top: 1px solid var(--line);
}

.accordion {
  border-bottom: 1px solid var(--grid);
}

.accordion:last-child {
  border-bottom: 0;
}

.accordion__summary {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 64px;
  padding: 10px 12px;
  list-style: none;
  cursor: pointer;
}

.accordion__summary::-webkit-details-marker {
  display: none;
}

.accordion__summary:hover {
  background: var(--hover);
}

.accordion__summary:focus-visible {
  outline-offset: -2px;
}

.accordion__chevron {
  flex: none;
  color: var(--ink-2);
  transform: rotate(-90deg);
  transition: transform 0.15s ease;
}

.accordion[open] > .accordion__summary .accordion__chevron {
  transform: rotate(0deg);
}

.accordion__text {
  display: grid;
  flex: 1;
  gap: 2px;
  min-width: 0;
}

.accordion__title {
  font-size: 15px;
  font-weight: 500;
  overflow-wrap: anywhere;
}

.accordion__meta {
  color: var(--ink-2);
  font-size: 13px;
}

.accordion__meta:empty {
  display: none;
}

.accordion__aside {
  display: flex;
  flex: none;
  align-items: baseline;
  gap: 16px;
  font-variant-numeric: tabular-nums;
}

.accordion__count {
  color: var(--ink-2);
  font-size: 13px;
}

.accordion__total {
  min-width: 96px;
  font-weight: 500;
  text-align: right;
}

/*
 * The totals under the scope items, on the right. Amounts line up with each row's own total above
 * them: the same 12px edge, the same 36px slot for a ⋮ menu, the same gap before it.
 */
.scope__totals {
  display: flex;
  justify-content: flex-end;
  padding: 8px 12px 12px;
  border-top: 1px solid var(--line);
  background: var(--surface-alt);
}

.totals {
  width: min(100%, 460px);
  margin: 0;
}

.totals__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto 36px;
  align-items: center;
  column-gap: 16px;
  min-height: 44px;
  border-top: 1px solid var(--grid);
}

.totals__row:first-child {
  border-top: 0;
}

.totals__row dt {
  min-width: 0;
  color: var(--ink-2);
  overflow-wrap: anywhere;
}

.totals__row dd {
  margin: 0;
}

.totals__amount {
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

.totals__add {
  margin-right: -8px;
}

.totals__row--grand {
  min-height: 52px;
  border-top: 2px solid var(--line);
}

.totals__row--grand dt,
.totals__row--grand .totals__amount {
  color: var(--ink);
  font-size: 16px;
  font-weight: 600;
}

/* A choice of two or three, side by side, like the discount's percent or amount. */
.segmented {
  display: inline-flex;
  justify-self: start;
  overflow: hidden;
  /* Fields keep their distance with the helper line under them; a switch has none, so it keeps its
     own, or the next field's label sits right against it. */
  margin-bottom: 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.segmented__option {
  position: relative;
  cursor: pointer;
}

.segmented__option + .segmented__option {
  border-left: 1px solid var(--line);
}

.segmented__option input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.segmented__option span {
  display: block;
  padding: 8px 16px;
  color: var(--ink-2);
  font-weight: 500;
}

.segmented__option:hover span {
  background: var(--hover);
}

.segmented__option input:checked + span {
  background: var(--blue-wash);
  color: var(--blue);
}

.segmented__option input:focus-visible + span {
  outline: 2px solid var(--blue);
  outline-offset: -2px;
}

.accordion__body {
  padding-bottom: 12px;
  background: var(--surface-alt);
  border-top: 1px solid var(--grid);
}

.accordion__empty {
  margin: 0;
  padding: 16px 20px 4px 48px;
  color: var(--ink-2);
}

.scope-table th {
  background: var(--surface-alt);
}

.scope-table td:first-child,
.scope-table th:first-child {
  padding-left: 48px;
}

.scope-table td {
  background: var(--surface);
}

.scope-table tfoot td {
  border-top: 1px solid var(--line);
  border-bottom: 0;
  background: var(--surface-alt);
  color: var(--ink-2);
  font-weight: 500;
}

.scope-table__name {
  display: block;
}

/* A service the work order this job came on no longer covers: kept on the list, out of the total. */
.scope-table tr.is-withdrawn td {
  color: var(--ink-3, var(--ink-2));
}

.scope-table tr.is-withdrawn .scope-table__name {
  text-decoration: line-through;
}

.scope-table__total {
  font-weight: 500;
}

.scope-table tfoot .scope-table__total {
  color: var(--ink);
}

/* Attachments sit under the services, after Add service. */
.scope__files {
  display: grid;
  gap: 4px;
  padding: 16px 20px 0 48px;
}

.scope__files-label {
  margin: 0;
  color: var(--ink-2);
  font-size: 13px;
  font-weight: 500;
}

.scope__files .file-list {
  margin-top: 0;
}

@media (max-width: 640px) {
  .accordion__summary {
    flex-wrap: wrap;
  }

  .accordion__aside {
    width: 100%;
    justify-content: space-between;
    padding-left: 36px;
  }

  /* The menu stays beside the title; the count and total take the next line. */
  .accordion__actions {
    order: 1;
  }

  .accordion__summary > .accordion__aside {
    order: 2;
  }

  .scope__totals {
    padding-left: 20px;
  }

  .scope-table td:first-child,
  .scope-table th:first-child,
  .accordion__empty,
  .scope__files {
    padding-left: 20px;
  }
}

/* ---- Scope item form: service rows, their pricing, and a running total ---- */
.picked-line {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 56px;
  margin-bottom: 20px;
  padding: 8px 8px 8px 16px;
  border-radius: var(--radius);
  background: var(--blue-wash);
  color: var(--blue);
}

.picked-line__text {
  display: grid;
  flex: 1;
  min-width: 0;
}

.picked-line__name {
  color: var(--ink);
  font-weight: 500;
}

.scope-editor__attachments {
  display: grid;
  gap: 8px;
}

.scope-editor__label {
  margin: 0;
  color: var(--ink-2);
  font-size: 13px;
  font-weight: 500;
}

/* ---- Editing scope items in the list: menus, a service opened in place, and Add service ---- */
/*
 * Each row keeps a 36px slot for its ⋮ button at the right, 12px in from the card's edge, even when
 * there's no button, so the totals in the header, the services table and the grand total line up.
 */
.accordion__actions {
  display: flex;
  flex: none;
  width: 36px;
  margin-left: 4px;
}

.scope-editor__line-total {
  margin: 0 0 8px;
  color: var(--ink-2);
  font-size: 13px;
  font-weight: 500;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.scope-editor__line-total:empty {
  display: none;
}

/* A section's heading with its own button on the right, across the whole width. */
.settings-section__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 16px;
  grid-column: 1 / -1;
}

.settings-section__fields--wide {
  grid-column: 1 / -1;
}

.scope-editor__total {
  margin: 0;
  text-align: right;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

/* ---- Team invitations: cards to accept or decline, and the count on the menu ---- */
.invitation-cards {
  display: grid;
  gap: 12px;
}

.invitation-card {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px 20px;
  padding: 20px;
  border-color: var(--blue-track);
  background: var(--surface);
  box-shadow: inset 4px 0 0 var(--blue);
}

.invitation-card__text {
  display: grid;
  flex: 1;
  gap: 2px;
  min-width: 220px;
}

.invitation-card__eyebrow {
  margin: 0;
  color: var(--blue);
  font-size: 13px;
  font-weight: 500;
}

.invitation-card__title {
  margin: 0;
  font-size: 20px;
  font-weight: 400;
  line-height: 28px;
}

.invitation-card__summary {
  margin: 0;
}

.invitation-card__when {
  margin: 4px 0 0;
  color: var(--ink-2);
  font-size: 13px;
}

.invitation-card__actions {
  display: flex;
  gap: 8px;
  margin-left: auto;
}

/* ---- Dashboard widgets: what is sitting on a job, gathered where everybody looks ---- */

/*
 * Three cards side by side where there is room, stacking as the page narrows. Each is sized by
 * what it holds rather than stretched to match its neighbours, because a widget with one row and
 * one with ten are both telling the truth and neither should pad itself out to agree.
 */
.dashboard-widgets {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 16px;
  align-items: start;
}

.widget__header {
  align-items: center;
  border-bottom: 1px solid var(--line);
  padding-bottom: 12px;
}

.widget__title {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

/* The count is the answer; the rows below it are only the examples. */
.widget__count {
  flex: none;
  min-width: 24px;
  padding: 0 7px;
  border-radius: 11px;
  background: var(--field);
  color: var(--ink-2);
  font-size: 13px;
  font-weight: 500;
  line-height: 22px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.widget__body {
  padding-top: 4px;
}

.widget__rows {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
}

.widget__row {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 8px 0;
  border-bottom: 1px solid var(--line);
}

.widget__row:last-child {
  border-bottom: 0;
}

/* The whole row is the target: a dashboard is scanned and clicked at speed. */
.widget__link {
  display: grid;
  flex: 1;
  gap: 2px;
  min-width: 0;
  color: inherit;
  text-decoration: none;
}

.widget__link:hover .widget__row-title {
  text-decoration: underline;
}

.widget__row-title {
  color: var(--blue);
  font-size: 14px;
  line-height: 20px;
  /* A question can run long, and a row that grew to fit one would break the rhythm of the rest. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.widget__row-meta,
.widget__row-aside {
  color: var(--ink-2);
  font-size: 13px;
  line-height: 18px;
}

.widget__row-meta {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.widget__row-aside {
  flex: none;
  text-align: right;
}

/* Nothing waiting is the answer somebody came for, so it is said rather than left blank. */
.widget__empty,
.widget__more {
  margin: 0;
  color: var(--ink-2);
  font-size: 13px;
}

.widget__more {
  padding-top: 8px;
}

.status-with-note {
  display: grid;
  justify-items: start;
  gap: 4px;
}

.nav-item {
  position: relative;
}

.nav-badge {
  position: absolute;
  top: 6px;
  left: 28px;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 9px;
  background: var(--bad);
  color: #ffffff;
  font-size: 11px;
  font-weight: 500;
  line-height: 18px;
  text-align: center;
}

/* How much has happened somewhere that this person hasn't read: a job in the list, or one of its
   tabs. It reads the same as the numbers in the menu, but sits in the flow beside what it counts. */
.count-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 9px;
  background: var(--bad);
  color: #ffffff;
  font-size: 11px;
  font-weight: 500;
  line-height: 18px;
}

/* A cell that leads with a link and carries something small beside it. */
.table-lead {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

/* Scope items with the services on them: the services sit under the item they belong to. The panel
   the form is in does the scrolling, so the tree is never a small scrolling box inside it. */
.checkset__options.checkset__options--tree {
  gap: 4px;
  max-height: none;
  overflow: visible;
}

.checkset__branch {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 8px 0;
  border-top: 1px solid var(--grid);
}

.checkset__branch:first-child {
  border-top: 0;
}

.checkset__twigs {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-left: 28px;
}

/* Money that is worth reading as good or bad news: what a work order leaves, or costs. */
.money--good {
  color: var(--good);
}

.money--bad {
  color: var(--bad);
}

/* What the table comes to, under its rows. */
.data-table tfoot td,
.data-table tfoot th {
  padding: 12px 16px;
  border-top: 2px solid var(--grid);
  border-bottom: 0;
  font-weight: 500;
}

.data-table__total {
  color: var(--ink-2);
  text-align: left;
  white-space: nowrap;
}

/* ---- The bell in the header and its dropdown ---- */
.app-bar__bell {
  position: relative;
  flex: none;
}

.app-bar__badge {
  position: absolute;
  top: 2px;
  right: 2px;
  min-width: 18px;
  padding: 0 5px;
  border: 2px solid var(--surface);
  border-radius: 999px;
  background: var(--bad);
  color: #fff;
  font-size: 11px;
  font-weight: 500;
  line-height: 16px;
  text-align: center;
}

.notifications {
  position: fixed;
  top: calc(var(--app-bar-h) - 4px);
  right: 12px;
  z-index: 50;
  width: min(380px, calc(100vw - 24px));
  max-height: calc(100vh - var(--app-bar-h) - 24px);
  overflow: hidden auto;
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-raised);
}

.notifications__head {
  position: sticky;
  top: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 12px 12px 16px;
  border-bottom: 1px solid var(--grid);
  background: var(--surface);
}

.notifications__title {
  flex: 1;
  margin: 0;
  font-size: 15px;
  font-weight: 500;
}

.notifications__items {
  margin: 0;
  padding: 0;
  list-style: none;
}

.notifications__item {
  display: flex;
  gap: 12px;
  width: 100%;
  padding: 12px 16px;
  border: 0;
  border-bottom: 1px solid var(--grid);
  background: none;
  text-align: left;
}

.notifications__item:hover {
  background: var(--hover);
}

.notifications__item.is-unread {
  background: var(--blue-wash);
}

.notifications__item.is-unread:hover {
  background: var(--blue-track);
}

.notifications__icon {
  flex: none;
  color: var(--ink-2);
  font-size: 20px;
}

.notifications__item.is-unread .notifications__icon {
  color: var(--blue);
}

.notifications__text {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.notifications__meta {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  color: var(--ink-2);
  font-size: 12px;
  line-height: 16px;
}

.notifications__name {
  font-weight: 500;
  overflow-wrap: anywhere;
}

.notifications__detail,
.notifications__who {
  color: var(--ink-2);
  font-size: 13px;
  line-height: 18px;
  overflow-wrap: anywhere;
}

/* The job it is about, which the line leads to. */
.notifications__job {
  color: var(--ink);
  font-size: 12px;
  line-height: 18px;
  overflow-wrap: anywhere;
}

.notifications__empty {
  display: grid;
  justify-items: center;
  gap: 8px;
  padding: 32px 20px;
  color: var(--ink-2);
  text-align: center;
}

.notifications__empty .ms {
  color: var(--ink-3);
  font-size: 32px;
}

.notifications__empty p {
  margin: 0;
  font-size: 13px;
}

/* ---- A project's page: status and name, the customer beside the job's details, then tabs ---- */
.project-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 24px;
}

.project-head__text {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 14px;
  min-width: 0;
}

.project-head__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* The page's own buttons stand out: Edit filled, More tinted, both a little taller. */
.project-head__actions .btn {
  height: 40px;
  padding-inline: 18px 20px;
  font-size: 15px;
}

.project-head__actions .more-actions__button {
  border-color: var(--blue-track);
  background: var(--blue-wash);
}

.project-head__actions .more-actions__button:hover,
.project-head__actions .more-actions__button[aria-expanded="true"] {
  background: var(--blue-track);
}

.project-head__title {
  margin: 0;
  font-size: 28px;
  font-weight: 500;
  line-height: 36px;
  letter-spacing: -0.01em;
  overflow-wrap: anywhere;
}

/* The Overview: the job's details down the left, what the job is beside them. */
.project-facts {
  display: grid;
  gap: 24px 48px;
  align-items: start;
  padding: 24px;
}

.project-facts__list {
  display: grid;
  gap: 10px;
  margin: 0;
}

/* Label and value on one line, the labels lined up down the column. */
.project-facts__item {
  display: grid;
  grid-template-columns: 116px minmax(0, 1fr);
  gap: 16px;
  align-items: baseline;
  min-width: 0;
}

.project-facts__label {
  margin: 0;
  color: var(--ink-2);
  font-size: 13px;
  line-height: 20px;
}

.project-facts__value {
  margin: 0;
  line-height: 20px;
  overflow-wrap: anywhere;
}


@media (max-width: 900px) {
  .project-facts {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ---- Inviting several people: a row per person, email and role side by side ---- */
.team-invite__row {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 2fr) 40px;
  align-items: start;
  column-gap: 12px;
}

.team-invite__remove {
  margin-top: 8px;
}

.team-invite__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 16px;
}

.team-invite__count {
  margin: 0;
  color: var(--ink-2);
  font-weight: 500;
}

.team-invite__roles {
  margin: 8px 0 0;
}

/* On a phone each person stacks email over role, with Remove beside the email and a rule between people. */
@media (max-width: 560px) {
  .team-invite__row {
    grid-template-columns: minmax(0, 1fr) 40px;
  }

  .team-invite__row .field--select {
    grid-column: 1;
  }

  .team-invite__remove {
    grid-row: 1;
    grid-column: 2;
  }

  .team-invite__row + .team-invite__row {
    padding-top: 12px;
    border-top: 1px solid var(--grid);
  }
}

/* The people on a job, with any invitations under them. */
.project-team {
  display: grid;
}

/* The buttons sit just above the table, not in a band of their own. */
.project-team .scope > .scope__head {
  justify-content: flex-end;
}

.scope__head {
  padding: 12px 16px 8px;
}

.project-team__invitations {
  margin: 20px;
}

.table-strong {
  font-weight: 500;
}

/* ---- How what is raised travels: a role per row, each sending to the one above ---- */

.chain-table {
  width: 100%;
}

.chain-table__row td {
  vertical-align: middle;
}

.chain-table__role {
  display: block;
  font-weight: 500;
}

/* A role taken out of the chain is still on the job; it just is not a step on the way. */
.chain-table__role--out {
  color: var(--ink-3);
}

.chain-table__row--out {
  background: var(--surface-alt);
}

.chain-table__people {
  display: block;
  color: var(--ink-3);
  font-size: 12px;
}

/* Writing a rule: who raises it, then where it goes, one under the other. */
.chain-add__form {
  display: grid;
  gap: 12px;
}

.chain-table__none {
  color: var(--ink-3);
  font-style: italic;
}

/*
 * Having no rules is said inside the table, so the columns stay on screen to be read: what a rule
 * is made of is half the explanation of why one is needed.
 */
.chain-table__empty {
  padding-block: 20px;
  color: var(--ink-2);
}

/*
 * The way to add a rule rides in the table's action column, above the Remove buttons it belongs
 * beside. Trimmed so the header row keeps a row's height rather than growing to a button's.
 */
.chain-table th.num {
  padding-block: 4px;
}

.chain-table__add {
  height: 32px;
  font-size: 13px;
}

/* Putting a role into the chain that nobody is on yet, above the list it joins. */
.chain-add {
  display: flex;
  align-items: center;
  gap: 8px;
}

.chain-add__label {
  color: var(--ink-2);
  font-size: 13px;
}

@media (width <= 600px) {
  .chain-add {
    flex-wrap: wrap;
  }
}

/* ---- The project team step, one block per role the job needs ---- */

.team-step {
  display: grid;
  gap: 16px;
}

.team-step__empty {
  margin: 0 0 12px;
  color: var(--ink-2);
}

.team-role {
  display: grid;
  gap: 12px;
  padding: 16px;
  border: 1px solid var(--line);
  border-radius: 8px;
}

.team-role__head {
  display: flex;
  align-items: start;
  justify-content: space-between;
  gap: 16px;
}

.team-role__name {
  margin: 0;
  font-weight: 500;
}

/* Only there while the seat is empty, which is what the step is asking somebody to fix. */
.team-role__state {
  margin: 2px 0 0;
  color: var(--ink-3);
  font-size: 13px;
}

.team-role__people {
  display: grid;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.team-role__people:empty {
  display: none;
}

.team-role__person {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 8px 8px 12px;
  border-radius: 6px;
  background: var(--surface-alt);
}

.team-role__person-who {
  display: grid;
  gap: 1px;
  min-width: 0;
}

/* Takes them off this seat only, so it sits quietly beside the name rather than reading as a delete. */
.team-role__drop {
  flex: none;
  color: var(--ink-2);
}

.team-role__person-mail {
  color: var(--ink-2);
  font-size: 13px;
}

/* ---- Work orders ---- */

/* A repeated block with nothing drawn around it. */
.repeatable--plain {
  margin-bottom: 4px;
  padding: 0;
  border: 0;
  background: none;
}

/* One stakeholder on the project form: the box to find them, with a way to drop the row. */
.stakeholder-row__pick {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  gap: 8px;
}

.stakeholder-row__pick .icon-btn {
  margin-top: 8px;
}

/* The customer's box stands alone, with nothing to drop beside it. */
[data-slot="customer-pick"] {
  grid-template-columns: minmax(0, 1fr);
}

/* Their card's buttons, at its right edge, shown once the row is under the pointer. */
.stakeholder-row__actions {
  display: flex;
  align-items: center;
  gap: 2px;
  margin-left: auto;
  opacity: 0;
  transition: opacity 120ms ease;
}

.stakeholder-row:hover .stakeholder-row__actions,
.stakeholder-row:focus-within .stakeholder-row__actions {
  opacity: 1;
}

.stakeholder-row__actions .icon-btn {
  width: 32px;
  height: 32px;
}

.icon-btn--danger:hover {
  color: var(--bad);
}

.stakeholder-row__card {
  padding: 10px 14px;
}

.stakeholder-row__line {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  color: var(--ink-2);
  font-size: 13px;
  line-height: 20px;
}

.stakeholder-row__card .picked-card__name {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* What the server said about one stakeholder row, under its card. */
.field__helper--row {
  margin: 0;
  color: var(--bad);
}

.repeatable.is-invalid {
  border-color: var(--bad);
}

/* A plain row has no border of its own, so its card carries the mark instead. */
.repeatable--plain.is-invalid .picked-card {
  border-color: var(--bad);
}

/* The Stakeholders tab: everyone on the job as a card, with what they are on it. */
.stakeholder-list {
  display: grid;
  gap: 12px;
  padding: 20px;
}

.stakeholder-list__head {
  display: flex;
  justify-content: flex-end;
}

/* Each card keeps its buttons until the pointer is on it, as the project form does. */
.stakeholder-card .stakeholder-row__actions {
  align-self: center;
}

/*
 * On a form, a saved contact or address is a card among fields rather than a row in a list, so its
 * Edit and Remove stay in plain sight instead of waiting for the pointer.
 */
.contact-card .stakeholder-row__actions,
.address-card .stakeholder-row__actions {
  align-self: center;
  opacity: 1;
}

/*
 * A project written the way the job is quoted: what it is at the top, who it is for, then what it is
 * made of, priced line by line, with the totals under them. The blocks are plain rules rather than
 * boxes, so the whole thing reads as one sheet.
 */
.invoice__head {
  display: grid;
  /* The number and status take only what they need, so the fields have the rest of the sheet. */
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 16px 48px;
  align-items: start;
  padding: 8px 0 24px;
  border-bottom: 1px solid var(--line);
}

/* Nothing is numbered yet on a new project, so the fields run the whole width. */
.invoice__head--plain {
  grid-template-columns: minmax(0, 1fr);
}

.invoice__head--plain .invoice__meta {
  display: none;
}

.invoice__head-fields {
  display: grid;
  gap: 8px;
}

.invoice__meta {
  display: grid;
  gap: 8px;
  justify-items: end;
  text-align: right;
}

.invoice__meta .field {
  width: 200px;
  text-align: left;
}

.invoice__number {
  margin: 0;
  font-size: 20px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}


.invoice__block {
  display: grid;
  gap: 12px;
  padding: 24px 0;
  border-bottom: 1px solid var(--grid);
}

.invoice__block:last-of-type {
  border-bottom: 0;
}

.invoice__block-head {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 24px;
  align-items: start;
  justify-content: space-between;
}

.invoice__label {
  margin: 0;
  font-size: 16px;
  font-weight: 500;
}

.invoice__hint {
  margin: 2px 0 0;
  max-width: 70ch;
  color: var(--ink-2);
  font-size: 13px;
}

/* Everything typed or picked runs the width of the sheet, as the priced lines do. */
.invoice__entry {
  min-width: 0;
}

.invoice__note {
  margin: 0;
  color: var(--ink-2);
  font-size: 13px;
}

/*
 * The steps a form is made in, above it: both of them from the start, the one you are on marked, and
 * a finished one taking you back to it. The rule between them carries the eye from one to the next.
 */
.stepper {
  display: flex;
  align-items: center;
  margin: 0;
  padding: 0 0 20px;
  list-style: none;
}

/* Every step but the last takes an equal share, so the marks are evenly spaced. */
.stepper__step {
  display: flex;
  flex: 1;
  align-items: center;
  min-width: 0;
}

.stepper__step:last-child {
  flex: 0 0 auto;
}

/* The rule that runs from one step to the next, filling whatever is left between them. */
.stepper__step::after {
  content: "";
  flex: 1;
  height: 1px;
  margin-inline: 12px;
  background: var(--line);
}

.stepper__step:last-child::after {
  content: none;
}

.stepper__button {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 14px 6px 6px;
  border: 0;
  border-radius: 999px;
  background: none;
  color: var(--ink-3);
  font: inherit;
  font-size: 14px;
  cursor: pointer;
}

.stepper__button:hover {
  background: var(--hover);
}

.stepper__mark {
  display: grid;
  place-content: center;
  width: 28px;
  height: 28px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 13px;
}

.stepper__step.is-current .stepper__button {
  color: var(--ink);
  font-weight: 500;
}

.stepper__step.is-current .stepper__mark {
  border-color: var(--blue);
  background: var(--blue);
  color: #fff;
}

/* A step already filled in wears a tick, and goes back to it. */
.stepper__step.is-done .stepper__button {
  color: var(--ink-2);
}

.stepper__tick {
  display: none;
  font-size: 18px;
}

.stepper__step.is-done .stepper__mark {
  border-color: var(--blue);
  color: var(--blue);
}

.stepper__step.is-done .stepper__number {
  display: none;
}

.stepper__step.is-done .stepper__tick {
  display: block;
}

/* Which step of making a project this is, and what it takes to finish it. */
.wizard-note {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px 16px;
  border: 1px solid var(--blue);
  border-radius: var(--radius);
  background: var(--blue-wash);
  color: var(--ink);
}

.wizard-note .ms {
  color: var(--blue);
}

.wizard-note__title {
  margin: 0;
  font-size: 14px;
  font-weight: 500;
}

.wizard-note__line {
  margin: 2px 0 0;
  color: var(--ink-2);
  font-size: 13px;
}

/* What someone is on a job, as a badge beside their name. */
.stakeholder-card__role {
  align-self: center;
  padding: 2px 10px;
  border-radius: 999px;
  background: var(--blue-wash);
  color: var(--blue);
  font-size: 12px;
  font-weight: 500;
  white-space: nowrap;
}

/* The Documents tab: the project's own files, then everything on the job. */
.project-files {
  display: grid;
  gap: 28px;
  padding: 20px;
}

.project-files__title {
  margin: 0 0 2px;
  font-size: 16px;
  font-weight: 500;
}

.project-files__text {
  margin: 0 0 12px;
  color: var(--ink-2);
  font-size: 14px;
}

/* Where a file is kept, under its name on the tile. */
.file-tile__note {
  overflow: hidden;
  color: var(--ink-2);
  font-size: 12px;
  line-height: 16px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.file-tile__link {
  color: var(--blue);
}

/* The organization picked, with room above the price field's floating label. */
.work-order-partner-card {
  margin-bottom: 8px;
}

.work-order-count {
  color: var(--ink-2);
  font-weight: 400;
}

/* The scope items and their service lines to pick from. */
.line-tree {
  display: grid;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}

.line-tree:empty {
  display: none;
}

.line-tree__group + .line-tree__group {
  border-top: 1px solid var(--grid);
}

.line-tree__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 4px 8px 4px 4px;
  background: var(--surface-alt);
}

.line-tree__toggle {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 10px;
  min-width: 0;
  padding: 8px;
  border: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.line-tree__toggle .ms {
  transition: transform 150ms ease;
}

.line-tree__toggle[aria-expanded="false"] .ms {
  transform: rotate(-90deg);
}

.line-tree__title {
  font-weight: 500;
}

.line-tree__number {
  min-width: 2.2em;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

.line-tree__meta {
  color: var(--ink-2);
  font-size: 13px;
}

.line-tree__line {
  display: grid;
  grid-template-columns: 18px auto minmax(0, 1fr) auto auto auto;
  grid-template-areas:
    "check number name held price offer"
    ". . meta meta meta offer";
  align-items: center;
  gap: 2px 12px;
  padding: 10px 16px 10px 44px;
  border-top: 1px solid var(--grid);
  cursor: pointer;
}

.line-tree__line input { grid-area: check; }
.line-tree__line .line-tree__number { grid-area: number; }
.line-tree__line .line-tree__name { grid-area: name; }
.line-tree__line .line-tree__meta { grid-area: meta; }
.line-tree__line .line-tree__held { grid-area: held; }
.line-tree__line .line-tree__price { grid-area: price; }
.line-tree__line .line-tree__offer { grid-area: offer; }

.line-tree__line:hover {
  background: var(--hover);
}

.line-tree__line .line-tree__meta:empty,
.line-tree__line .line-tree__held:empty,
.line-tree__line .line-tree__price:empty {
  display: none;
}

/* A service's estimate, lined up on the right. */
.line-tree__price {
  min-width: 96px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* The price offered for a picked service, beside its estimate. */
.line-tree__offer {
  width: 150px;
  cursor: auto;
}

/* A small money box: a price in a row of a list or a dialog, with its complaint under it. */
.price-box .field__input {
  height: 40px;
  padding: 0 12px 0 28px;
  text-align: right;
}

.price-box .field__prefix {
  top: 8px;
  left: 12px;
}

.price-box .field__helper:empty {
  display: none;
}

/* What the picked services come to, under the list. */
.line-tree__total {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  margin: 0;
  padding: 12px 16px;
  border-radius: var(--radius);
  background: var(--surface-alt);
  font-weight: 500;
}

.line-tree__total-amount {
  font-variant-numeric: tabular-nums;
}

/* A line already on an open work order: shown, so the picture is whole, but out of reach. */
.line-tree__line.is-held {
  cursor: default;
  color: var(--ink-3);
}

.line-tree__line.is-held:hover {
  background: none;
}

.line-tree__held {
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--field);
  color: var(--ink-2);
  font-size: 12px;
  white-space: nowrap;
}

/* One work order. */
/* A work order's page: the work on the left, the conversation held beside it and scrolling on its own. */
.work-order-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(420px, 500px);
  gap: 24px;
  align-items: start;
}

/* The conversation sits against the right edge of the page, with the work itself on the left. The
   left column takes the space between them, and what it holds keeps the width it reads best at
   rather than stretching across the window. */
.work-order-layout > .work-order {
  max-width: 960px;
}

.work-order-chat {
  position: sticky;
  top: calc(var(--app-bar-h) + 20px);
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - var(--app-bar-h) - 40px);
}

.work-order-chat .timeline {
  flex: 1 1 auto;
  min-height: 160px;
  overflow-y: auto;
}

@media (max-width: 1100px) {
  .work-order-layout {
    grid-template-columns: minmax(0, 1fr);
  }

  .work-order-chat {
    position: static;
    max-height: none;
  }

  .work-order-chat .timeline {
    max-height: 60vh;
  }
}

.work-order__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
}

.work-order__number {
  margin: 0 0 2px;
  color: var(--ink-2);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

.work-order__turn {
  margin: 0 20px 12px;
}

.work-order__danger {
  display: flex;
  gap: 4px;
  margin-right: auto;
}

.work-order__lines {
  display: grid;
}

/*
 * The services card reads as a table when there are two prices to a line: the headings, the prices
 * on every row and the totals underneath all take their width from one place, so the money lines up
 * down the card however the names wrap.
 */
.work-order {
  --work-order-price: 108px;
}

.work-order__columns {
  display: grid;
  grid-template-columns: minmax(0, 1fr) repeat(3, var(--work-order-price));
  gap: 12px;
  padding: 0 20px 8px 40px;
  color: var(--ink-2);
  font-size: 13px;
}

.work-order__columns span + span {
  text-align: right;
}

.work-order__group {
  padding: 12px 20px;
  border-top: 1px solid var(--grid);
}

.work-order__item {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 12px;
  margin: 0 0 6px;
}

.work-order__item-title {
  font-weight: 500;
}

.work-order__item-meta {
  color: var(--ink-2);
  font-size: 13px;
}

.work-order__services {
  display: grid;
  gap: 6px;
  margin: 0;
  padding: 0 0 0 20px;
}

.work-order__services li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 2px 12px;
}

.work-order__services li.is-pair {
  grid-template-columns: minmax(0, 1fr) repeat(3, var(--work-order-price));
}

/* Under the name, whether or not there is a price beside it. */
.work-order__services li .table-secondary {
  grid-column: 1;
}

.work-order__service-price {
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/*
 * What can be done with the work order sits at the foot of the services it is about, and stays
 * against the bottom of the screen while there is more card than screen — the buttons are there to
 * press without reading to the end of a long list first. A card that clips its corners is a scroller
 * of its own, and nothing inside one can be stuck to anything, so this card doesn't.
 */
.work-order__card {
  overflow: visible;
}

.work-order__dock {
  position: sticky;
  bottom: 0;
  z-index: 2;
  border-radius: 0 0 var(--radius) var(--radius);
  background: var(--surface);
}

/* The foot of the services card, and the only row in it that isn't a service. */
.work-order__total {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 12px;
  margin: 0;
  padding: 12px 20px 16px 40px;
  border-top: 1px solid var(--grid);
  font-weight: 500;
}

.work-order__total.is-pair {
  grid-template-columns: minmax(0, 1fr) repeat(3, var(--work-order-price));
  align-items: start;
}

.work-order__total .line-tree__total-amount {
  text-align: right;
}

.work-order__files {
  padding: 0 20px 20px;
}

/* A work order's conversation: its history and its messages, oldest first. */
.timeline {
  display: grid;
  gap: 12px;
  margin: 0;
  padding: 16px 20px;
  list-style: none;
  border-top: 1px solid var(--grid);
}

.timeline__empty {
  color: var(--ink-2);
}

/* Something that happened to the work order: a quiet line, not a message. */
.timeline__event {
  display: grid;
  grid-template-columns: 28px minmax(0, 1fr);
  gap: 8px;
  align-items: start;
  padding: 4px 0;
}

.timeline__icon {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--surface-alt);
  color: var(--ink-2);
  font-size: 16px;
}

.timeline__text {
  display: grid;
  gap: 2px;
  padding-top: 4px;
}

.timeline__what,
.timeline__terms,
.timeline__note,
.timeline__when {
  margin: 0;
}

.timeline__what {
  color: var(--ink-2);
}

.timeline__terms {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 10px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

.timeline__current {
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--blue-wash);
  color: var(--blue);
  font-size: 12px;
  font-weight: 500;
}

.timeline__note {
  white-space: pre-line;
}

/* A dialog that asks for more than one thing: a reason, and the files that show it. */
.dialog-form {
  display: grid;
  gap: 16px;
}

/* What was sent with something that happened, such as a marked-up drawing sent back with a rejection. */
.timeline__files {
  display: grid;
  gap: 2px;
  margin: 2px 0 0;
  padding: 0;
  list-style: none;
}

.timeline__files .link--plain {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}

.timeline__when {
  color: var(--ink-3);
  font-size: 12px;
}

/* A message: the other side's on the left, your own on the right. */
.timeline__message {
  display: flex;
}

.timeline__message--mine {
  justify-content: flex-end;
}

.bubble {
  display: grid;
  gap: 4px;
  max-width: min(560px, 85%);
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-radius: 12px 12px 12px 4px;
  background: var(--surface);
}

.timeline__message--mine .bubble {
  border-radius: 12px 12px 4px 12px;
}

.bubble__who {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 2px 8px;
  margin: 0;
}

.bubble__name {
  font-weight: 500;
}

.bubble__org {
  color: var(--ink-2);
  font-size: 12px;
}

.bubble__body {
  margin: 0;
  white-space: pre-line;
  overflow-wrap: anywhere;
}

.bubble__when {
  margin: 0;
  color: var(--ink-3);
  font-size: 12px;
}

/* Where to write the next message. */
.composer {
  display: grid;
  gap: 8px;
  padding: 16px 20px 20px;
  border-top: 1px solid var(--grid);
}

.composer__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.composer__attach {
  position: relative;
  cursor: pointer;
}

/* The file picker itself stays out of sight; its label is the button. */
.composer__attach input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.composer__attach:focus-within {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

.composer__files {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.composer__file {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: 100%;
  padding: 4px 4px 4px 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface-alt);
  font-size: 13px;
}

.composer__file-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/*
 * A box docked to the foot of the window, so the next message is written in the same place however
 * far down the conversation you have read. It is one line until it is used: what goes with a
 * message — the files, what sending it does — appears once there is a message being written, and
 * goes away again when there isn't.
 */
.composer--dock {
  position: fixed;
  right: 0;
  bottom: 0;
  left: var(--rail-w);
  z-index: 30;
  display: block;
  padding: 0;
  border-top: 1px solid var(--line);
  background: var(--surface);
  box-shadow: 0 -2px 8px rgb(60 64 67 / 12%);
}

.composer__inner {
  display: grid;
  gap: 8px;
  padding: 12px 32px calc(12px + env(safe-area-inset-bottom, 0px));
}

.composer--dock textarea.field__input {
  height: 88px;
  padding: 10px 14px;
  overflow-y: auto;
  resize: none;
}

/* Nothing is said under the box until something is wrong with what is in it. */
.composer--dock .field__helper:empty {
  display: none;
}

/* What goes with the message: attaching on the left, sending on the right. */
.composer__controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.composer__controls .btn--primary {
  margin-left: auto;
}



@media (max-width: 960px) {
  .composer--dock {
    left: 0;
  }

  .composer__inner {
    padding-inline: 16px;
  }
}

/* ---- One question: the whole conversation about it, down the page ---- */
.rfi-page {
  display: grid;
  gap: 12px;
  align-content: start;
}

/* A line under the page's name saying what it is about: a phrase, not a list of fields. */
.page-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 2px 8px;
  margin: 0;
  color: var(--ink-2);
  font-size: 13px;
  line-height: 20px;
}

.page-meta__dot {
  color: var(--ink-3);
}

.rfi-thread {
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.rfi-thread .timeline {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

/* What the question is and what can be done with it, together at the right of the heading. */
.rfi-thread .card__header {
  align-items: center;
}

.rfi-thread__right {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
}

.rfi-thread__marks {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

/* Where the question stands, between the heading and the conversation. */
.rfi-thread__note {
  margin: 0 20px 12px;
}

/*
 * Every message sits in the same column, whoever wrote it: the name on it says whose it is, and the
 * tint says whether it came from here. Across the full width of the page, a bubble stops at a width
 * that still reads as a line of text.
 */
/* Every message is the same width, so the times down the right edge line up as a column. */
.rfi-thread .bubble {
  width: min(760px, 100%);
  max-width: none;
}

.rfi-thread .timeline__message--mine {
  justify-content: flex-start;
}

/* When it was said sits against the right edge of the message, on the line with who said it. */
.rfi-thread .bubble__who {
  flex-wrap: nowrap;
  gap: 8px;
}

.rfi-thread .bubble__who .bubble__name,
.rfi-thread .bubble__who .bubble__org {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.rfi-thread .bubble__who .bubble__when {
  flex: none;
  margin-left: auto;
  padding-left: 8px;
}

.rfi-thread .timeline__message--mine .bubble {
  border-radius: 12px 12px 12px 4px;
}

/* Messages on a work order that this person hasn't read yet, in a list. */
.unread-chip {
  display: inline-block;
  margin-top: 4px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--blue);
  color: #fff;
  font-size: 12px;
  font-weight: 500;
}

/* What something is, with its icon, in a table cell. */
.table-kind {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.table-kind .ms {
  color: var(--ink-2);
}

/* A link that opens something in place rather than going somewhere. */
.table-link--button {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  cursor: pointer;
}

.table-link--button:hover {
  text-decoration: underline;
}

/* The services of an offer, each with its price, in the counter offer dialog. */
.offer-prices {
  display: grid;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.offer-prices__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 440px);
  align-items: start;
  gap: 12px;
}

.offer-prices__name {
  display: grid;
  gap: 2px;
  padding-top: 14px;
}

/* How the line is priced, then whichever boxes that choice asks for, along one line. */
.offer-prices__fields {
  display: flex;
  align-items: start;
  gap: 8px;
}

.offer-prices__type {
  flex: 0 0 150px;
  min-width: 0;
}

.offer-prices__type .field__input {
  height: 40px;
}

.offer-prices__type .field__icon {
  top: 8px;
}

.offer-prices__pricing {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  flex: 1 1 0;
  gap: 8px;
  min-width: 0;
}

.offer-prices__pricing:has(.price-box--hours) {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}

/* Narrow enough and the line breaks: the name over its fields, the choice over its figures. */
@media (width <= 700px) {
  .offer-prices__row {
    grid-template-columns: minmax(0, 1fr);
  }

  .offer-prices__name {
    padding-top: 0;
  }

  .offer-prices__fields {
    flex-wrap: wrap;
  }

  .offer-prices__type {
    flex-basis: 100%;
  }
}

.offer-prices__total {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  margin: 0 0 12px;
  padding-top: 8px;
  border-top: 1px solid var(--line);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

@media (max-width: 640px) {
  .line-tree__line {
    padding-left: 16px;
    grid-template-columns: 18px auto minmax(0, 1fr) auto auto;
    grid-template-areas:
      "check number name held price"
      ". . meta meta meta"
      ". . offer offer offer";
  }
}

/* ---- Who a job tells about what ---- */

/* The words and the buttons share one row: the explanation leads, the buttons sit at the end. */
.comms__head {
  align-items: flex-start;
  flex-wrap: nowrap;
}

.comms__text {
  margin: 0;
  flex: 1 1 auto;
  min-width: 0;
  max-width: 82ch;
  color: var(--ink-2);
  font-size: 13px;
}

.comms__note {
  margin: 0;
  padding: 0 20px 20px;
  max-width: 82ch;
  color: var(--ink-2);
  font-size: 13px;
}

/* Narrow enough and the buttons drop under the words rather than squeezing them. */
@media (max-width: 900px) {
  .comms__head {
    flex-wrap: wrap;
  }
}

/* A document in a table row: its icon, or its own picture once that has loaded, then its name. */
.file-cell {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}

.file-cell__icon {
  position: relative;
  flex: none;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  overflow: hidden;
  border-radius: 6px;
  background: var(--surface-2);
}

.file-cell__icon .file-tile__icon {
  font-size: 20px;
}

.file-cell__icon--pdf .file-tile__icon {
  color: var(--bad);
}

/* A toolbar's main action sits at its right, after the table's own Filters and Columns. */
.scope__head-end {
  order: 1;
}

/* A line under a card's title, saying what the card is showing or why it is empty. */
.card__subtitle {
  margin: 4px 0 0;
  font-size: 13px;
  color: var(--ink-2);
}

/* The hours on one work order: what each line has taken, then who spent them and when. */
.work-order__time-line {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding: 12px 20px;
  border-top: 1px solid var(--line);
}

.work-order__time-line:first-child {
  border-top: 0;
}

.work-order__time-name {
  min-width: 0;
}

.work-order__time-item {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  color: var(--ink-3);
}

.work-order__time-hours {
  flex: none;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.work-order__time-against {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  color: var(--ink-3);
}

.work-order__time-against--over {
  color: var(--bad);
}

.work-order__timesheet {
  overflow-x: auto;
}

.work-order__timesheet table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

.work-order__timesheet th,
.work-order__timesheet td {
  padding: 10px 12px;
  text-align: left;
  border-top: 1px solid var(--line);
  white-space: nowrap;
}

.work-order__timesheet td.is-hours,
.work-order__timesheet th.is-hours {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.work-order__timesheet thead th {
  font-weight: 500;
  color: var(--ink-2);
}

.work-order__timesheet tfoot td {
  font-weight: 600;
}

/* A day whose time has been signed off. */
.work-order__approved {
  display: inline-block;
  margin-left: 6px;
  color: var(--good);
  font-size: 14px;
  vertical-align: -2px;
}

/* The work diary: a day at a time, each stretch of work with what was written, then the day's
   screenshots together underneath. */
.work-diary__day .card__header {
  align-items: baseline;
}

.work-diary__entry {
  display: flex;
  gap: 20px;
  padding: 14px 20px;
  border-top: 1px solid var(--line);
}

.work-diary__when {
  flex: none;
  width: 140px;
  font-variant-numeric: tabular-nums;
}

.work-diary__time {
  display: block;
  font-size: 13px;
}

.work-diary__length {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  color: var(--ink-3);
}

.work-diary__what {
  min-width: 0;
  flex: 1;
}

.work-diary__service {
  margin: 0;
  font-size: 13px;
  font-weight: 500;
}

.work-diary__item {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  font-weight: 400;
  color: var(--ink-3);
}

.work-diary__who {
  margin: 6px 0 0;
  font-size: 12px;
  color: var(--ink-3);
}

/* What the person wrote about this stretch of work. */
.work-diary__memo {
  margin: 8px 0 0;
  padding: 8px 12px;
  border-left: 2px solid var(--line);
  font-size: 13px;
  color: var(--ink-1);
  white-space: pre-wrap;
}

.work-diary__shots {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 10px;
}

.work-diary__shot {
  position: relative;
  display: block;
  width: 180px;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface-2);
  text-decoration: none;
}

.work-diary__shot img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
}

.work-diary__shot-foot {
  display: block;
  padding: 6px 8px;
}

.work-diary__shot-time {
  display: block;
  font-size: 11px;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

/* How busy the machine was when this one was taken. */
.work-diary__shot-busy {
  display: block;
  margin-top: 1px;
  font-size: 10px;
  color: var(--ink-3);
}

@media (max-width: 640px) {
  .work-diary__entry {
    flex-direction: column;
    gap: 8px;
  }

  .work-diary__when {
    width: auto;
  }
}

/* A screenshot before its picture has arrived. */
.work-diary__shot {
  padding: 0;
  border: 1px solid var(--line);
  font: inherit;
  cursor: pointer;
  text-align: left;
}

.work-diary__shot-blank {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  background: var(--surface-2);
}

/* The day's screenshots, side by side under the stretches of work they came from. */
.work-diary__shots {
  padding: 14px 20px;
  border-top: 1px solid var(--line);
}

/* One screenshot, opened over the page with what was going on when it was taken. */
.shot-viewer {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 24px;
  background: rgb(32 33 36 / 82%);
}

.shot-viewer__body {
  display: flex;
  flex-direction: column;
  max-width: min(1100px, 100%);
  max-height: 100%;
  overflow: auto;
  border-radius: 10px;
  background: var(--surface-1);
}

.shot-viewer__frame {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0;
  /* A screen is rarely the shape of the space it is shown in; the gap reads as part of the frame. */
  background: var(--surface-2);
  border-radius: 10px 10px 0 0;
}

.shot-viewer__frame img {
  display: block;
  max-width: 100%;
  max-height: 70vh;
  object-fit: contain;
}

.shot-viewer__caption {
  padding: 14px 18px;
}

.shot-viewer__caption p {
  margin: 0;
}

.shot-viewer__when {
  font-size: 14px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.shot-viewer__busy {
  margin-top: 4px !important;
  font-size: 13px;
  color: var(--ink-1);
}

.shot-viewer__work {
  margin-top: 2px !important;
  font-size: 12px;
  color: var(--ink-3);
}

.shot-viewer__memo {
  margin-top: 10px !important;
  padding: 8px 12px;
  border-left: 2px solid var(--line);
  font-size: 13px;
  white-space: pre-wrap;
}

.shot-viewer__count {
  margin-top: 10px !important;
  font-size: 12px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

.shot-viewer__close,
.shot-viewer__step {
  flex: none;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border: 0;
  border-radius: 999px;
  background: rgb(255 255 255 / 14%);
  color: #fff;
  cursor: pointer;
}

.shot-viewer__close:hover,
.shot-viewer__step:hover {
  background: rgb(255 255 255 / 26%);
}

.shot-viewer__close {
  position: absolute;
  top: 16px;
  right: 16px;
}

@media (max-width: 640px) {
  .shot-viewer {
    padding: 12px;
  }

  .shot-viewer__step {
    position: absolute;
    bottom: 16px;
  }

  .shot-viewer__step:first-of-type {
    left: 16px;
  }
}

/* What a screenshot was taken during, under the time and how busy the machine was. */
.work-diary__shot-work {
  display: block;
  margin-top: 2px;
  overflow: hidden;
  font-size: 10px;
  color: var(--ink-3);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A day somebody worked but the tracker took nothing. */
.work-diary__none {
  margin: 0;
  padding: 14px 20px;
  border-top: 1px solid var(--line);
  font-size: 13px;
  color: var(--ink-3);
}

/* Which stretch of work a screenshot's counts are for. */
.shot-viewer__span {
  margin-top: 2px !important;
  font-size: 12px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

/* A figure in a table with how it was arrived at under it: a quote and its hours, or the other way. */
.work-order-quote {
  display: grid;
  gap: 2px;
  justify-items: end;
}

/* A list toolbar that leads with a search box: it takes the left, everything else groups right. */
.scope__head > .table-search {
  margin-right: auto;
}

/* ---- The shop's time: four totals, then the diary behind them ---- */

/*
 * The same hours over four stretches. One frame divided rather than four cards, because they are
 * one reading of one thing and nothing here is worth pressing.
 */
.time-totals {
  display: grid;
  gap: 8px;
}

/* Whose time is counted. The four numbers mean something else to a member than to an owner. */
.time-totals__caption {
  margin: 0;
  color: var(--ink-2);
  font-size: 13px;
}

.time-totals__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

.time-totals__cell {
  padding: 12px 16px;
}

.time-totals__cell + .time-totals__cell {
  border-left: 1px solid var(--line);
}

.time-totals__label {
  margin: 0;
  color: var(--ink-2);
  font-size: 12px;
  line-height: 16px;
}

.time-totals__value {
  margin: 2px 0 0;
  font-size: 20px;
  font-weight: 500;
  line-height: 28px;
  font-variant-numeric: tabular-nums;
}

.time-totals__unit {
  color: var(--ink-2);
  font-size: 12px;
  font-weight: 400;
}

/* Two by two on a narrow screen: the dividers follow the rows rather than the source order. */
@media (max-width: 720px) {
  .time-totals__grid {
    grid-template-columns: repeat(2, 1fr);
  }

  .time-totals__cell:nth-child(odd) {
    border-left: 0;
  }

  .time-totals__cell:nth-child(n + 3) {
    border-top: 1px solid var(--line);
  }
}

.diary {
  display: grid;
  gap: 12px;
}

.diary__title {
  margin: 0;
  font-size: 16px;
  font-weight: 500;
  line-height: 24px;
}

/* What sits over a filter, naming it without the weight of a form label. */
.diary__legend {
  color: var(--ink-2);
  font-size: 12px;
  font-weight: 500;
  line-height: 16px;
}

.diary__who {
  display: grid;
  gap: 6px;
}

.diary__people {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

/* Whose time is on screen. One is always pressed, so the page is never about nobody. */
.diary-person {
  padding: 5px 10px;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--surface);
  color: var(--ink-2);
  font-size: 12px;
  font-weight: 500;
  line-height: 16px;
}

.diary-person:hover {
  border-color: var(--ink-3);
  color: var(--ink);
}

.diary-person[aria-pressed="true"] {
  border-color: var(--blue);
  background: var(--blue-wash);
  color: var(--blue);
}

.diary__filters {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
}

.diary__filter {
  display: grid;
  gap: 6px;
  min-width: 0;
}

.diary__filter .filter-select {
  width: 100%;
}

@media (max-width: 560px) {
  .diary__filters {
    grid-template-columns: 1fr;
  }
}

/* The month beside the week: the month takes what it needs, the week keeps the rest for its bars. */
.diary__panes {
  display: grid;
  grid-template-columns: 232px 1fr;
  gap: 16px;
  align-items: start;
}

@media (max-width: 860px) {
  .diary__panes {
    grid-template-columns: 1fr;
  }
}

/* ---- The month ---- */
.calendar {
  max-width: 264px;
}

.calendar__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 4px;
}

.calendar__head .icon-btn {
  width: 28px;
  height: 28px;
}

.calendar__head .ms {
  font-size: 20px;
}

.calendar__month {
  font-weight: 500;
}

.calendar__weekdays,
.calendar__days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
}

.calendar__weekdays {
  color: var(--ink-2);
  font-size: 11px;
  font-weight: 500;
  text-align: center;
}

.calendar__days {
  margin-top: 4px;
  row-gap: 2px;
  justify-items: center;
}

.calendar__day {
  position: relative;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 50%;
  background: none;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

.calendar__day:hover {
  background: var(--hover);
  color: var(--ink);
}

.calendar__day[data-today="true"] {
  border-color: var(--blue);
  color: var(--ink);
  font-weight: 500;
}

.calendar__day[aria-current="date"] {
  border-color: var(--blue);
  background: var(--blue);
  color: var(--surface);
  font-weight: 500;
}

/* A day with time against it carries a dot — unless it is the day on screen, where the fill says so. */
.calendar__day[data-tracked="true"]:not([aria-current="date"])::after {
  content: "";
  position: absolute;
  bottom: 1px;
  left: 50%;
  width: 4px;
  height: 4px;
  transform: translateX(-50%);
  border-radius: 50%;
  background: var(--diary-timed);
}

.calendar__legend {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 10px 0 0;
  padding: 0;
  list-style: none;
  color: var(--ink-2);
  font-size: 12px;
}

.calendar__legend li {
  display: flex;
  align-items: center;
  gap: 5px;
}

/*
 * The three ways time arrives. Each mark has its own shape as well as its own colour, so a bar can
 * still be read by somebody who cannot tell the colours apart.
 */
.diary-mark {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--diary-timed);
}

.diary-mark[data-kind="manual"] {
  border-radius: 2px;
  background: var(--diary-manual);
  transform: rotate(45deg);
}

.diary-mark[data-kind="overtime"] {
  border-radius: 1px;
  background: var(--diary-overtime);
}

/* ---- The week ---- */
.diary-week {
  gap: 12px;
  padding: 16px;
}

.diary-week__title {
  margin: 0;
  font-size: 13px;
  font-weight: 500;
}

.diary-week__days {
  display: grid;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.diary-week__row {
  display: flex;
  align-items: center;
  gap: 12px;
}

.diary-week__day {
  flex: none;
  width: 128px;
  font-variant-numeric: tabular-nums;
}

.diary-week__row[data-chosen="true"] .diary-week__day {
  font-weight: 500;
}

/* A day that has not happened yet is still a row, so the week keeps its shape. */
.diary-week__row[data-ahead="true"] {
  color: var(--ink-3);
}

.diary-week__row[data-openable="true"] {
  margin: -4px -8px;
  padding: 4px 8px;
  border-radius: 6px;
  cursor: pointer;
}

.diary-week__row[data-openable="true"]:hover {
  background: var(--hover);
}

.diary-week__track {
  flex: 1;
  min-width: 0;
  height: 12px;
  overflow: hidden;
  border-radius: 999px;
  background: var(--grid);
}

.diary-week__bar {
  display: flex;
  height: 100%;
  /* A few minutes still has to be a bar somebody can see. */
  min-width: 28px;
  overflow: hidden;
  border-radius: 999px;
}

.diary-week__part {
  height: 100%;
  background: var(--diary-timed);
}

.diary-week__part[data-kind="manual"] {
  background: var(--diary-manual);
}

.diary-week__part[data-kind="overtime"] {
  background: var(--diary-overtime);
}

/* A hairline of the page between two kinds, so a bar of two colours never reads as a gradient. */
.diary-week__part + .diary-week__part {
  border-left: 1px solid var(--surface);
}

.diary-week__hours {
  flex: none;
  width: 76px;
  text-align: right;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

.diary-week__totals {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
}

.diary-week__total {
  display: flex;
  flex: 1 1 120px;
  align-items: flex-start;
  gap: 8px;
}

.diary-week__total .diary-mark {
  margin-top: 7px;
}

.diary-week__label {
  margin: 0;
  color: var(--ink-2);
  font-size: 12px;
  line-height: 16px;
}

.diary-week__figure {
  margin: 2px 0 0;
  font-size: 22px;
  font-weight: 500;
  line-height: 26px;
  font-variant-numeric: tabular-nums;
}

.diary-week__figure--lg {
  font-size: 26px;
  line-height: 30px;
}

.diary-week__unit {
  color: var(--ink-2);
  font-size: 13px;
  font-weight: 400;
}

/* The week's own total, boxed off from the three kinds it is made of. */
.diary-week__sum {
  flex: 1 1 180px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--surface-alt);
}

.diary-week__allowed {
  margin: 4px 0 0;
  color: var(--ink-2);
  font-size: 12px;
}

/* ---- One day's stretches, in a sheet over the diary ---- */
.day-segments {
  display: flex;
  flex-direction: column;
  min-height: 100%;
}

/* What the day came to, under the date the sheet is headed with. */
.day-segments__head {
  padding: 12px 24px 16px;
  border-bottom: 1px solid var(--line);
}

.day-segments__summary {
  margin: 0;
  color: var(--ink-2);
  font-size: 13px;
}

.day-segments__context {
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
  color: var(--ink-2);
  font-size: 13px;
}

/* The word in front of a value — Member, Scope, Project — which is not a heading, only a label. */
.day-segments__term {
  color: var(--ink);
  font-weight: 500;
}

/*
 * What has been ticked. It sits between the day and its stretches rather than over them, so the
 * pictures never move under the pointer as they are picked.
 */
.day-segments__picked {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 24px;
  border-bottom: 1px solid var(--line);
  background: var(--surface-alt);
}

.day-segments__picked-total {
  margin: 0;
  font-size: 13px;
}

.day-segments__picked-total span {
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

.day-segments__picked-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.day-segments__body {
  display: grid;
  gap: 16px;
  align-content: start;
  padding: 16px 24px 24px;
}

/* Where the day's hours went, before any of the stretches that made them up. */
.side-panel__body .card.scope-split {
  padding: 12px 14px;
  gap: 8px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.scope-split__title {
  margin: 0;
  font-size: 12px;
  font-weight: 500;
}

.scope-split__rows {
  display: grid;
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.scope-split__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.scope-split__label {
  min-width: 0;
  overflow: hidden;
  color: var(--ink-2);
  font-size: 12px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.scope-split__hours {
  flex: none;
  font-size: 12px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

.work-sessions {
  display: grid;
  gap: 24px;
}

/* One unbroken stretch at the machine: what it was, then what was seen during it. */
.work-session {
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.work-session__head {
  display: grid;
  gap: 8px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--line);
  background: var(--surface-alt);
}

.work-session__when {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.work-session__range {
  margin: 0;
  font-size: 14px;
  font-weight: 500;
}

.work-session__length {
  color: var(--ink-2);
  font-weight: 400;
}

.work-session__count {
  color: var(--ink-2);
  font-size: 12px;
}

/* What the stretch was worked against, said once here rather than on every picture below. */
.work-session__lines {
  display: grid;
  gap: 2px;
  padding-left: 16px;
  color: var(--ink-2);
  font-size: 12px;
}

.work-session__lines p {
  margin: 0;
}

.work-session__memo {
  color: var(--ink);
}

/* A stretch nobody wrote anything about: not an error, but worth saying. */
.work-session__nomemo {
  color: var(--warn);
}

.work-session__shots {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 12px;
  padding: 16px;
}

@media (max-width: 1100px) {
  .work-session__shots {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (max-width: 860px) {
  .work-session__shots {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  .work-session__shots {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ---- One snapshot ---- */
.shot-card {
  display: flex;
  flex-direction: column;
  min-width: 0;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface);
}

.shot-card:hover {
  box-shadow: 0 1px 2px rgb(60 64 67 / 30%), 0 1px 3px 1px rgb(60 64 67 / 15%);
}

.shot-card__open {
  display: grid;
  gap: 4px;
  padding: 8px 8px 6px;
  border: 0;
  background: none;
  text-align: left;
  cursor: pointer;
}

.shot-card__frame {
  display: block;
  overflow: hidden;
  border-radius: 4px;
  background: var(--field);
}

.shot-card__frame img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  object-position: top;
}

/* A picture that has not arrived, which is still the shape of the one that will. */
.shot-card__blank {
  display: grid;
  place-items: center;
  aspect-ratio: 16 / 9;
  color: var(--ink-3);
  font-size: 11px;
}

/* The stretch cut into slices, lit where the machine was being used. */
.shot-card__activity {
  display: flex;
  gap: 2px;
}

.shot-card__slice {
  flex: 1;
  height: 6px;
  border-radius: 999px;
  background: var(--grid);
}

.shot-card__slice[data-busy="true"] {
  background: var(--diary-timed);
}

.shot-card__app {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  min-width: 0;
}

.shot-card__app-name,
.shot-card__member,
.shot-card__scope,
.shot-card__project {
  overflow: hidden;
  color: var(--ink-2);
  font-size: 10px;
  line-height: 14px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.shot-card__member {
  font-weight: 500;
}

/* Minutes of the stretch spent on something the shop counts as idle. */
.shot-card__low {
  flex: none;
  padding: 1px 5px;
  border-radius: 3px;
  background: var(--danger-wash);
  color: var(--danger);
  font-size: 10px;
  line-height: 14px;
}

.shot-card__busy {
  color: var(--ink-3);
  font-size: 10px;
  line-height: 14px;
  text-align: right;
}

.shot-card__marks {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}

/* Where the time stands: taken as read, waiting, or being argued over. */
.shot-card__status {
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ink-3);
}

.shot-card__status[data-status="approved"] {
  background: var(--diary-timed);
}

.shot-card__status[data-status="pending"] {
  background: #f9ab00;
}

.shot-card__status[data-status="disputed"] {
  background: var(--diary-overtime);
}

.shot-card__memo {
  flex: none;
  color: var(--ink-3);
  font-size: 14px;
}

/* Picking one, and when it was taken, kept off the picture so neither is pressed by accident. */
.shot-card__pick {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 6px 10px;
  border-top: 1px solid var(--line);
  cursor: pointer;
}

.shot-card__time {
  font-size: 12px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

/* ---- Work somebody else is doing for you ---- */
.shared-jobs__intro,
.shared-diary__intro {
  max-width: 68ch;
  margin: 0 0 16px;
  color: var(--ink-2);
  font-size: 13px;
  line-height: 20px;
}

.shared-jobs__list {
  margin: 0;
  padding: 0;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface);
  list-style: none;
}

.shared-job + .shared-job {
  border-top: 1px solid var(--line);
}

.shared-job__open {
  display: grid;
  grid-template-columns: 7rem minmax(0, 1fr) minmax(0, 14rem) auto auto;
  align-items: center;
  gap: 16px;
  padding: 14px 20px;
  color: inherit;
  text-decoration: none;
}

.shared-job__open:hover {
  background: var(--hover);
  text-decoration: none;
}

.shared-job__number {
  color: var(--ink-2);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

.shared-job__name {
  overflow: hidden;
  font-size: 14px;
  font-weight: 500;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.shared-job__shop,
.shared-job__due {
  overflow: hidden;
  color: var(--ink-3);
  font-size: 12px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.shared-job__go {
  color: var(--ink-3);
  font-size: 20px;
}

@media (max-width: 760px) {
  .shared-job__open {
    grid-template-columns: minmax(0, 1fr) auto;
  }

  .shared-job__number,
  .shared-job__shop,
  .shared-job__due {
    grid-column: 1;
  }
}

.shared-jobs__none {
  margin: 0;
  padding: 24px 20px;
  border: 1px dashed var(--line);
  border-radius: 8px;
  color: var(--ink-3);
  font-size: 13px;
}

/* The month beside the day, the same two panes the shop reads its own diary in. */
.shared-diary__panes {
  display: grid;
  grid-template-columns: 300px minmax(0, 1fr);
  align-items: start;
  gap: 16px;
}

@media (max-width: 1000px) {
  .shared-diary__panes {
    grid-template-columns: minmax(0, 1fr);
  }
}

.shared-diary__day {
  min-width: 0;
  padding: 0;
}

.shared-diary__date {
  margin: 0;
  padding: 14px 20px;
  border-bottom: 1px solid var(--line);
  font-size: 15px;
  font-weight: 500;
}

/* ---- How a job is set up ---- */
.project-settings {
  padding: 20px 24px;
}

/* Who the switch actually let in, said under it rather than left to be assumed. */
.project-settings__note {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin: 10px 0 0;
  color: var(--ink-2);
  font-size: 12px;
  line-height: 18px;
}

.project-settings__icon {
  flex: none;
  color: var(--ink-3);
  font-size: 16px;
  line-height: 18px;
}

/* ---- One snapshot, as large as the window will show it ---- */
/*
  A window of its own over the day, so the picture gets the whole screen while the day keeps its
  place underneath. It is the window, not a card in it: no margin, no radius, nothing to look past.
*/
.shot-detail {
  width: 100%;
  max-width: none;
  height: 100%;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: var(--surface);
  color: var(--ink);
}

.shot-detail::backdrop {
  background: rgb(32 33 36 / 82%);
}

.shot-detail__pane {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.shot-detail__head {
  display: flex;
  flex: none;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 20px;
  border-bottom: 1px solid var(--line);
}

.shot-detail__titles p {
  margin: 0;
}

.shot-detail__day {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--ink-3);
}

/* Where the time stands, in words, since there is room here for them. */
.shot-detail__status {
  padding: 1px 8px;
  border-radius: 999px;
  background: var(--hover);
  color: var(--ink-2);
  font-size: 11px;
  font-weight: 500;
}

.shot-detail__status[data-status="approved"] {
  background: var(--good-wash);
  color: var(--good);
}

.shot-detail__status[data-status="pending"] {
  background: #fef7e0;
  color: #b06000;
}

.shot-detail__source {
  padding: 1px 8px;
  border-radius: 999px;
  background: var(--blue-wash);
  color: var(--blue);
  font-size: 11px;
  font-weight: 500;
}

.shot-detail__member {
  margin-top: 2px !important;
  font-size: 12px;
  color: var(--ink-3);
}

.shot-detail__who {
  color: var(--ink);
  font-weight: 500;
}

.shot-detail__range {
  margin: 2px 0 0;
  font-size: 16px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

.shot-detail__length {
  color: var(--ink-3);
  font-weight: 400;
}

.shot-detail__count {
  margin-top: 2px !important;
  font-size: 11px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

.shot-detail__close {
  flex: none;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--ink-2);
  cursor: pointer;
}

.shot-detail__close:hover {
  background: var(--hover);
  color: var(--ink);
}

.shot-detail__body {
  display: flex;
  flex: 1;
  min-height: 0;
}

.shot-detail__stage {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
  padding: 16px 20px;
}

/*
  A screen is rarely the shape of the space it is shown in, so the picture is fitted inside the
  frame rather than cropped: a detail view that cut the edges off would be no use for reading one.
*/
.shot-detail__frame {
  display: grid;
  flex: 1;
  place-items: center;
  min-height: 0;
  overflow: hidden;
  border-radius: 8px;
  background: var(--field);
}

.shot-detail__frame img {
  display: block;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.shot-detail__blank {
  margin: 0;
  padding: 24px;
  color: var(--ink-3);
  font-size: 13px;
}

.shot-detail__under {
  flex: none;
  margin: 0;
  overflow: hidden;
  font-size: 12px;
  color: var(--ink-2);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.shot-detail__side {
  flex: none;
  width: 360px;
  max-width: 40vw;
  overflow-y: auto;
  padding: 16px 20px;
  border-left: 1px solid var(--line);
}

.shot-detail__part + .shot-detail__part {
  margin-top: 18px;
}

.shot-detail__part-title {
  margin: 0;
  font-size: 12px;
  font-weight: 500;
}

.shot-detail__value {
  margin: 2px 0 0;
  font-size: 12px;
  color: var(--ink-2);
}

.shot-detail__memo {
  margin: 4px 0 0;
  font-size: 12px;
  color: var(--ink-2);
  white-space: pre-wrap;
}

.shot-detail__note {
  margin: 6px 0 0;
  font-size: 11px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

/* The stretch minute by minute, lit where the machine was being used. */
.shot-detail__bars {
  display: flex;
  gap: 2px;
  margin-top: 6px;
}

.shot-detail__bar {
  flex: 1;
  height: 10px;
  border-radius: 2px;
  background: var(--grid);
}

.shot-detail__bar[data-busy="true"] {
  background: var(--diary-timed);
}

.shot-detail__minutes {
  width: 100%;
  margin-top: 6px;
  border-collapse: collapse;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}

.shot-detail__minutes th {
  padding: 4px 0;
  border-bottom: 1px solid var(--line);
  color: var(--ink-3);
  font-weight: 500;
  text-align: left;
}

.shot-detail__minutes th:last-child,
.shot-detail__minutes td:last-child {
  text-align: right;
}

.shot-detail__minutes td {
  padding: 3px 0;
  border-bottom: 1px solid var(--grid);
  color: var(--ink-2);
}

.shot-detail__minutes tr:last-child td {
  border-bottom: 0;
}

.shot-detail__state[data-busy="false"] {
  color: var(--ink-3);
}

.shot-detail__foot {
  display: flex;
  flex: none;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 20px;
  border-top: 1px solid var(--line);
}

.shot-detail__actions,
.shot-detail__steps {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* Under about a thousand pixels the picture and its details stop fitting side by side. */
@media (max-width: 1000px) {
  .shot-detail__body {
    flex-direction: column;
    overflow-y: auto;
  }

  .shot-detail__stage {
    flex: none;
    min-height: 52vh;
  }

  .shot-detail__side {
    width: auto;
    max-width: none;
    overflow: visible;
    border-top: 1px solid var(--line);
    border-left: 0;
  }
}
