/* app.css — component styles for the Employee Studio SPA. All values via --hz-* tokens. */
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; font-family: var(--hz-sans); color: var(--hz-fg-1); background: var(--hz-paper); }
a { color: var(--hz-purple); text-decoration: none; }
a:hover { text-decoration: underline; }

/* Material Symbols base */
.ms { font-family: "Material Symbols Outlined"; font-weight: normal; font-style: normal;
      line-height: 1; letter-spacing: normal; text-transform: none; white-space: nowrap;
      direction: ltr; -webkit-font-feature-settings: "liga"; font-feature-settings: "liga";
      -webkit-font-smoothing: antialiased; vertical-align: middle; }

/* Buttons */
.btn { font-family: var(--hz-sans); font-weight: 600; font-size: var(--hz-body-sm-size);
       border: 0; border-radius: var(--hz-radius-md); padding: var(--hz-space-3) var(--hz-space-5);
       cursor: pointer; display: inline-flex; align-items: center; gap: var(--hz-space-2);
       transition: background-color .15s, opacity .15s; }
/* A disabled button fades and loses its pointer and hover, so a Save that
   has nothing to save reads as out of reach rather than as a button that
   silently does nothing. */
.btn:disabled { opacity: .45; cursor: default; }
.btn--primary { background: var(--hz-purple); color: var(--hz-fg-on-dark); }
.btn--primary:hover:not(:disabled) { background: var(--hz-purple-deep); }
/* Red is reserved for a super-admin perk shown inside the tenant portal (the
   Hire of a role not published yet), so it cannot be mistaken for a path a
   tenant has. */
.btn--danger { background: var(--hz-danger); color: var(--hz-fg-on-dark); }
.btn--danger:hover:not(:disabled) { background: color-mix(in srgb, var(--hz-danger) 80%, black); }
.btn--ghost { background: transparent; color: var(--hz-fg-1); }
.btn--ghost:hover:not(:disabled) { background: var(--hz-cream); }
.btn--pill { border-radius: var(--hz-radius-pill); }
/* Icon-only: square padding instead of the label button's wide sides, so it
   reads as one tappable glyph rather than a button missing its text. The
   glyph carries the size; the label lives in title/aria-label. */
.btn--icon { padding: var(--hz-space-2); gap: 0; color: var(--hz-fg-2); }
.btn--icon .ms { font-size: 20px; }
.btn--icon:hover:not(:disabled) { background: var(--hz-cream); color: var(--hz-fg-1); }
/* A primary button that is icon-only (the phone chat's Send) keeps its white
   glyph and purple hover: the ghost-style grey and cream above are for the
   transparent icon buttons and would leave the glyph invisible on purple. */
.btn--primary.btn--icon { color: var(--hz-fg-on-dark); }
.btn--primary.btn--icon:hover:not(:disabled) { background: var(--hz-purple-deep); color: var(--hz-fg-on-dark); }

/* Cards + surfaces */
.card { background: var(--hz-paper); border-radius: var(--hz-radius-lg); box-shadow: var(--hz-shadow-sm);
        padding: var(--hz-space-5); }
.card--cream { background: var(--hz-cream); box-shadow: none; }

/* Inputs */
.field { display: flex; flex-direction: column; gap: var(--hz-space-2); }
.field > label { font-weight: 600; font-size: var(--hz-caption-size); color: var(--hz-fg-2); }
.input { font-family: var(--hz-sans); font-size: var(--hz-body-sm-size); color: var(--hz-fg-1);
         background: var(--hz-paper); border: 1px solid var(--hz-line-strong);
         border-radius: var(--hz-radius-sm); padding: var(--hz-space-3) var(--hz-space-4); }
.input:focus { outline: none; border-color: var(--hz-purple); }

/* The employee's name — the one field every hire must fill, so it reads as a
   headline, not a form row, and glows purple until something is typed. */
.input--name { font-family: var(--hz-serif); font-size: var(--hz-tile-title-size); font-weight: 600;
               padding: var(--hz-space-4) var(--hz-space-5); }
.input--name::placeholder { font-family: var(--hz-sans); font-size: var(--hz-body-sm-size); font-weight: 400;
                            color: var(--hz-purple-deep); }
.input--pending { border: 2px solid var(--hz-purple); background: var(--hz-purple-faint);
                  box-shadow: 0 0 0 4px var(--hz-purple-soft); }
.input--pending:focus { box-shadow: 0 0 0 4px var(--hz-purple-soft); }

/* Error / status text */
.error { color: var(--hz-danger); font-size: var(--hz-body-sm-size); }
.success { color: var(--hz-success); font-size: var(--hz-body-sm-size); }
.placeholder { color: var(--hz-fg-4); }

/* Spinner — shared lightweight loading placeholder used inline within views. */
.spinner { color: var(--hz-fg-3); font-size: var(--hz-body-sm-size); padding: var(--hz-space-5) 0; }

/* App boot — the centered branded loader shown from first paint (index.html's
   static placeholder) through session resolution (app.js AppBoot). Same markup in
   both so the pre-JS → mounted-app handoff never flickers. */
.app-boot {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--hz-space-5);
  background: var(--hz-paper);
}
.app-boot__logo { width: 44px; height: 44px; }
.app-boot__spin {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 2.5px solid var(--hz-line-strong);
  border-top-color: var(--hz-purple);
  animation: app-boot-spin 0.7s linear infinite;
}
@keyframes app-boot-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .app-boot__spin { animation: none; } }

/* App error — app.js boot screen shown when /api/me fails for a reason other
   than "not logged in" (network error, 5xx); offers a Retry affordance. */
.app-error { color: var(--hz-fg-2); font-size: var(--hz-body-sm-size); padding: var(--hz-space-5); }
.app-error p { margin: 0 0 var(--hz-space-3) 0; color: var(--hz-danger); }

/* Subtitle — muted sans lead paragraph under a headline */
.subtitle { color: var(--hz-fg-2); margin-top: var(--hz-space-2); }

/* Stat card — metric tile: caption label above a large serif-weight value */
.stat-card {
  background: var(--hz-paper);
  border: 1px solid var(--hz-line);
  border-radius: var(--hz-radius-lg);
  box-shadow: var(--hz-shadow-sm);
  padding: var(--hz-space-5);
}
.stat-card__label {
  font-family: var(--hz-sans);
  font-size: var(--hz-caption-size);
  line-height: var(--hz-caption-lh);
  color: var(--hz-fg-3);
}
.stat-card__value {
  font-family: var(--hz-sans);
  font-weight: 600;
  font-size: var(--hz-h3-size);
  line-height: var(--hz-h3-lh);
  color: var(--hz-fg-1);
  margin-top: var(--hz-space-2);
  /* These figures reload under the reader's eyes — the connectors screen polls
     while indexing — so the digits are fixed width to keep a number from
     shifting sideways as it changes. */
  font-variant-numeric: tabular-nums;
}

/* Dashboard — Team route: stat row, view toggle, employee table/grid.
   Fidelity refs: screenshots/list.png (table), screenshots/dash.png (grid). */
.dashboard__tenant-select {
  max-width: 280px;
  margin: var(--hz-space-5) 0 0;
}
/* Shared by Team and Connectors: the view toggle on the left, the primary
   action on the right. Named for the role rather than the screen, because two
   screens use it. */
.page-toolbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--hz-space-3) var(--hz-space-4);
  margin: var(--hz-space-6) 0 var(--hz-space-4);
}
/* The right-hand group of a page toolbar: the contact pill beside the primary
   action, kept together so the pill never drifts to the left edge. */
.page-toolbar__actions { display: flex; align-items: center; flex-wrap: wrap; gap: var(--hz-space-3) var(--hz-space-4); margin-left: auto; }

/* The contact call to action — the way out when the role or connector a
   customer needs is not in the catalogue yet. A bordered ghost pill so it reads
   as an action without shouting over the screen it sits on (the hire
   catalogue, the Connectors page). */
.contact-cta { text-decoration: none; white-space: normal; text-align: left; border: 1px solid var(--hz-line-strong); color: var(--hz-fg-1); }
.contact-cta:hover { border-color: var(--hz-purple); }
.contact-cta .ms { color: var(--hz-purple); }
.contact-cta span { font-weight: 500; color: var(--hz-fg-2); }
.contact-cta strong { font-weight: 700; color: var(--hz-purple); }
.dashboard__empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--hz-space-4);
  text-align: center;
  background: var(--hz-paper);
  border: 1px dashed var(--hz-line-strong);
  border-radius: var(--hz-radius-lg);
  padding: var(--hz-space-9) var(--hz-space-5);
}

/* Stat row — three StatCards summarizing the tenant's digital employees */
.stat-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--hz-space-4);
  margin: var(--hz-space-6) 0;
}
/* Four across, matching the agent Overview's own row, and two when four would
   squeeze a seven-digit token count. */
.stat-row--four { grid-template-columns: repeat(4, 1fr); }
/* On the Team and Connectors screens the row is a summary over a table, not
   the headline, so its figures run a quarter smaller than a tile's default and
   sit flush right, where columns of numbers line up. The label keeps its size. */
.stat-row .stat-card__value {
  font-size: calc(var(--hz-h3-size) * 0.75);
  text-align: right;
}
@media (max-width: 899px) { .stat-row--four { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 599px) {
  .page-toolbar { flex-wrap: wrap; }
  /* Without the view toggle the action button still sits at the right edge. */
  .page-toolbar > .btn:last-child { margin-left: auto; }
  .stat-row, .stat-row--four { grid-template-columns: repeat(2, 1fr); gap: var(--hz-space-3); }
  .dashboard__empty { padding: var(--hz-space-6) var(--hz-space-4); }
}

/* View toggle — segmented grid/list control paired with the "Hire" button */
.view-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--hz-space-1);
  background: var(--hz-cream);
  border-radius: var(--hz-radius-pill);
  padding: var(--hz-space-1);
}
.view-toggle__btn {
  display: inline-flex;
  align-items: center;
  gap: var(--hz-space-2);
  background: transparent;
  border: 0;
  border-radius: var(--hz-radius-pill);
  padding: var(--hz-space-2) var(--hz-space-4);
  font-family: var(--hz-sans);
  font-weight: 600;
  font-size: var(--hz-caption-size);
  color: var(--hz-fg-3);
  cursor: pointer;
  transition: background-color .15s, color .15s, box-shadow .15s;
}
.view-toggle__btn--active {
  background: var(--hz-paper);
  color: var(--hz-fg-1);
  box-shadow: var(--hz-shadow-sm);
}

/* Employee table — list view of real employee rows */
.employee-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--hz-paper);
  border-radius: var(--hz-radius-lg);
  box-shadow: var(--hz-shadow-sm);
  overflow: hidden;
}
.employee-table th {
  text-align: left;
  font-family: var(--hz-sans);
  font-weight: 700;
  font-size: var(--hz-micro-size);
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--hz-fg-3);
  padding: var(--hz-space-4) var(--hz-space-5);
  border-bottom: 1px solid var(--hz-line);
}
.employee-table td {
  padding: var(--hz-space-4) var(--hz-space-5);
  border-bottom: 1px solid var(--hz-line);
  font-size: var(--hz-body-sm-size);
  color: var(--hz-fg-1);
  vertical-align: middle;
}
.employee-table tbody tr { cursor: pointer; transition: background-color .15s; }
.employee-table tbody tr:hover { background: var(--hz-cream); }
.employee-table tbody tr:last-child td { border-bottom: 0; }

/* Stacked rows — under the phone width a .table--stack table becomes a list:
   the header row goes, each row is a block, and each labelled cell prints its
   column name in front of its value. The labels are the same translated
   strings the <th>s carry, passed as data-label by the row components. A cell
   without a label is the row's own title line. */
@media (max-width: 599px) {
  .table--stack thead { display: none; }
  .table--stack, .table--stack tbody { display: block; width: 100%; }
  /* "tbody tr" / "tbody td" rather than bare "tr" / "td": each table's own
     cell rules come later in this file at the same specificity and would
     otherwise put their borders and padding back on every stacked cell. */
  .table--stack tbody tr {
    display: flex;
    flex-direction: column;
    gap: var(--hz-space-1);
    padding: var(--hz-space-3) 0;
    border-top: 1px solid var(--hz-line);
  }
  .table--stack tbody tr:first-child { border-top: 0; padding-top: 0; }
  .table--stack tbody tr:last-child { padding-bottom: 0; }
  .table--stack tbody td {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--hz-space-3);
    padding: 0;
    border: 0;
    text-align: left;
    white-space: normal;
    min-width: 0;
  }
  .table--stack tbody td[data-label]::before {
    content: attr(data-label);
    flex: none;
    color: var(--hz-fg-3);
    font-size: var(--hz-caption-size);
    font-weight: 500;
  }
  .table--stack tbody td:not([data-label]) { font-weight: 600; }
}

.employee-identity__name { font-weight: 600; color: var(--hz-fg-1); }
.employee-identity__role { font-size: var(--hz-caption-size); color: var(--hz-fg-3); }

/* Employee grid — tiled card view of real employee rows */
.employee-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: var(--hz-space-4);
}
.employee-card {
  display: flex;
  align-items: flex-start;
  gap: var(--hz-space-3);
  background: var(--hz-paper);
  border: 1px solid var(--hz-line);
  border-radius: var(--hz-radius-lg);
  box-shadow: var(--hz-shadow-sm);
  padding: var(--hz-space-4);
  cursor: pointer;
  transition: box-shadow .15s, border-color .15s;
}
.employee-card:hover { border-color: var(--hz-purple); box-shadow: var(--hz-shadow-md); }
.employee-card__avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: var(--hz-radius-pill);
  background: var(--hz-purple-soft);
  color: var(--hz-ink);
  font-weight: 700;
  font-size: var(--hz-body-sm-size);
  flex: none;
}
.employee-card__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--hz-space-2); }
.employee-card__name-row { display: flex; align-items: center; justify-content: space-between; gap: var(--hz-space-2); }
.employee-card__name {
  font-weight: 600;
  color: var(--hz-fg-1);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* The three-word support id: what a customer quotes so support finds this exact
   agent, since a name alone is not unique enough. */
.employee-card__meta {
  display: flex;
  align-items: center;
  gap: var(--hz-space-2);
  font-size: var(--hz-caption-size);
  color: var(--hz-fg-3);
}
.employee-card__meta .ms { font-size: 16px; }
.employee-card__foot { display: flex; align-items: center; justify-content: space-between; }

/* Tile — signature icon-on-purple-ring card used in catalogs/grids */
/* Two rows: the icon and the title/badge head side by side, then the body
   spanning both columns beneath them. Left-aligned, because a description of
   a couple of lines is read, not admired. */
.tile {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: var(--hz-space-3);
  row-gap: var(--hz-space-2);
  align-items: start;
  text-align: left;
  background: var(--hz-paper);
  border: 1px solid var(--hz-line);
  border-radius: var(--hz-radius-lg);
  box-shadow: var(--hz-shadow-sm);
  padding: var(--hz-space-4);
  cursor: pointer;
  font-family: inherit;
  transition: box-shadow .15s, border-color .15s;
}
/* Title over badge, aligned to the top of the icon beside it rather than
   centred against it, so the title reads as the tile's first line. */
.tile__head {
  align-self: start;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--hz-space-2);
  min-width: 0;
}
.tile:hover { border-color: var(--hz-purple); box-shadow: var(--hz-shadow-md); }
/* Smaller than the old centred hero ring: at 100px it dwarfed the title it now
   sits beside, and left the tile mostly empty. */
.tile__ring {
  width: 64px;
  height: 64px;
  border-radius: var(--hz-radius-pill);
  border: 2.5px solid var(--hz-purple);
  background: transparent;
  color: var(--hz-purple);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--hz-h3-size);
}
.tile__body {
  /* The full width under the icon and head, not a third column. */
  grid-column: 1 / -1;
  color: var(--hz-fg-2);
  font-size: var(--hz-body-sm-size);
  line-height: var(--hz-body-sm-lh);
}

/* Badge — small status/role pill; tone selects the color treatment */
.badge {
  display: inline-flex;
  align-items: center;
  font-family: var(--hz-sans);
  font-weight: 700;
  font-size: var(--hz-micro-size);
  line-height: var(--hz-micro-lh);
  letter-spacing: 0.5px;
  text-transform: uppercase;
  border-radius: var(--hz-radius-pill);
  padding: var(--hz-space-1) var(--hz-space-3);
}
.badge--neutral, .badge--special {
  background: var(--hz-ink);
  color: var(--hz-fg-on-dark);
}
.badge--success {
  background: var(--hz-success);
  color: var(--hz-fg-on-dark);
}
.badge--standard {
  background: var(--hz-purple-soft);
  color: var(--hz-ink);
}
.badge--danger {
  background: var(--hz-danger);
  color: var(--hz-fg-on-dark);
}

/* Shell — persistent app frame: dark sidebar (nav/tenant switch/lang/logout)
   + main pane. Fidelity refs: screenshots/dash.png, screenshots/admin.png. */
/* The shell is exactly one viewport tall and never scrolls itself: the sidebar
   stays put and only the main pane moves, so navigation and the tenant
   switcher are always reachable no matter how long a page gets.
   dvh follows a mobile browser's shrinking viewport; vh is the fallback for
   anything that does not know it. */
.shell {
  display: grid;
  grid-template-columns: 270px 1fr;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}
.sidebar {
  background: var(--hz-ink-deep);
  color: var(--hz-fg-on-dark);
  display: flex;
  flex-direction: column;
  padding: var(--hz-space-5) var(--hz-space-4);
  gap: var(--hz-space-5);
  /* A grid item's default min-height is its content, which would push the
     sidebar past the viewport instead of letting its nav take the overflow. */
  min-height: 0;
}
.sidebar__brand {
  display: flex;
  align-items: center;
  gap: var(--hz-space-3);
  padding: 0 var(--hz-space-2);
}
.sidebar__logo { height: 28px; width: auto; }
.sidebar__logo--mark { display: none; }
.sidebar__collapse {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  flex: none;
  border: 0;
  border-radius: var(--hz-radius-sm);
  background: transparent;
  color: var(--hz-fg-on-dark-2);
  cursor: pointer;
  transition: background-color .15s, color .15s;
}
.sidebar__collapse:hover { background: var(--hz-line-on-dark); color: var(--hz-fg-on-dark); }
.sidebar__collapse .ms { font-size: 20px; }

/* Collapsed sidebar — a narrow icon rail: labels and secondary text hide, icons
   stay, and the wordmark swaps for the square mark. The choice persists in
   localStorage (see shell.js). */
.shell--collapsed { grid-template-columns: 76px 1fr; }
.shell--collapsed .sidebar { padding-left: var(--hz-space-2); padding-right: var(--hz-space-2); }
.shell--collapsed .sidebar__brand { position: relative; justify-content: center; padding: 0; }
.shell--collapsed .sidebar__logo--full { display: none; }
.shell--collapsed .sidebar__logo--mark { display: block; }
.shell--collapsed .sidebar__collapse {
  position: absolute;
  /* Center the arrow in the empty space between the centered logo's right edge and
     the rail's right border (arrow pokes into the sidebar's right padding). */
  right: -6px;
  top: 50%;
  transform: translateY(-50%);
  margin: 0;
  width: 20px;
  height: 20px;
}
/* Collapsed, the sidebar is icon-only: the labels are gone, so the glyphs
   carry all the meaning and get 10% more size to do it with. One factor rather
   than three rounded literals, so the ratio stays legible and adjustable, and
   each base is the value that applies in this state (measured, not assumed:
   the nav and logout glyphs inherit their size rather than setting one). */
.shell--collapsed .sidebar { --sidebar-icon-scale: 1.1; }
.shell--collapsed .sidebar__collapse .ms { font-size: calc(18px * var(--sidebar-icon-scale)); }
.shell--collapsed .nav__item .ms {
  font-size: calc(var(--hz-body-sm-size) * var(--sidebar-icon-scale));
}
.shell--collapsed .user-card__logout .ms {
  font-size: calc(var(--hz-micro-size) * var(--sidebar-icon-scale));
}
.shell--collapsed .nav__item { justify-content: center; }
.shell--collapsed .nav__item > span:not(.ms) { display: none; }
.shell--collapsed .tenant-switch { justify-content: center; padding-left: 0; padding-right: 0; }
.shell--collapsed .tenant-switch__name,
.shell--collapsed .tenant-switch__select,
.shell--collapsed .tenant-switch__chevron { display: none; }
.shell--collapsed .trust { display: none; }
.shell--collapsed .user-card { flex-wrap: wrap; justify-content: center; gap: var(--hz-space-2); }
.shell--collapsed .user-card__name,
.shell--collapsed .user-card__lang { display: none; }

/* Drawer mode (tablet and below) — one column under a compact top bar; the
   sidebar keeps its dark surface and slides in over a scrim. shell.js never
   adds .shell--collapsed at this width, so the rail rules above stay
   desktop-only and the persisted collapse preference is simply ignored.
   No scroll lock is needed: .shell is one viewport tall and only .main
   scrolls, and the scrim and drawer are fixed children of .shell. */
@media (max-width: 899px) {
  .shell { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr); }
  .topbar {
    display: flex;
    align-items: center;
    gap: var(--hz-space-3);
    min-height: var(--hz-topbar-h);
    padding: env(safe-area-inset-top) max(var(--hz-space-3), env(safe-area-inset-right)) 0 max(var(--hz-space-3), env(safe-area-inset-left));
    background: var(--hz-ink-deep);
    color: var(--hz-fg-on-dark);
    border-bottom: 1px solid var(--hz-line-on-dark);
  }
  .topbar__menu {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    flex: none;
    border: 0;
    border-radius: var(--hz-radius-md);
    background: transparent;
    color: inherit;
    cursor: pointer;
  }
  .topbar__menu .ms { font-size: 24px; }
  .topbar__logo { height: 28px; width: auto; }
  .topbar__tenant {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 600;
    font-size: var(--hz-body-sm-size);
  }
  .shell__scrim { position: fixed; inset: 0; z-index: 30; background: rgba(18, 18, 18, .28); }
  .sidebar {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: 31;
    width: min(300px, 86vw);
    padding-top: calc(var(--hz-space-5) + env(safe-area-inset-top));
    padding-bottom: calc(var(--hz-space-5) + env(safe-area-inset-bottom));
    padding-left: max(var(--hz-space-4), env(safe-area-inset-left));
    box-shadow: var(--hz-shadow-xl);
    overscroll-behavior: contain;
    transform: translateX(-100%);
    visibility: hidden;
    transition: transform .22s ease, visibility 0s linear .22s;
  }
  .sidebar--open { transform: none; visibility: visible; transition: transform .22s ease, visibility 0s; }
  .sidebar__collapse { width: 44px; height: 44px; }
  .sidebar__collapse .ms { font-size: 24px; }
  .nav__item { min-height: 44px; }
  .user-card__lang, .user-card__logout { min-width: 44px; min-height: 44px; }
}
@media (prefers-reduced-motion: reduce) { .sidebar { transition: none; } }

/* Tenant display — rounded card on the sidebar line color, avatar + name; a
   non-interactive current-tenant indicator, not a switcher (see TenantPicker
   on the dashboard for the real switch control). */
.tenant-switch {
  display: flex;
  align-items: center;
  gap: var(--hz-space-3);
  width: 100%;
  background: var(--hz-line-on-dark);
  border: 0;
  border-radius: var(--hz-radius-md);
  padding: var(--hz-space-3) var(--hz-space-3);
  color: var(--hz-fg-on-dark);
  font-family: var(--hz-sans);
  font-weight: 600;
  text-align: left;
}
.tenant-switch__avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: var(--hz-radius-pill);
  background: var(--hz-purple);
  color: var(--hz-fg-on-dark);
  font-size: var(--hz-caption-size);
  flex: none;
}
.tenant-switch__name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tenant-switch__select {
  flex: 1;
  min-width: 0;
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  border: 0;
  padding: 0;
  margin: 0;
  color: var(--hz-fg-on-dark);
  font-family: var(--hz-sans);
  font-weight: 600;
  font-size: inherit;
  cursor: pointer;
}
.tenant-switch__select:focus-visible { outline: 2px solid var(--hz-purple); outline-offset: 2px; border-radius: var(--hz-radius-sm); }
/* Native option list renders in the OS palette, so keep option text dark-on-light. */
.tenant-switch__select option { color: var(--hz-fg-1); }
.tenant-switch__chevron { flex: none; color: var(--hz-fg-on-dark); opacity: 0.7; }

/* Nav — sidebar's primary link list; active item fills purple */
/* On a viewport too short for the whole sidebar, the nav list is the part that
   gives: the brand, tenant switcher and user card stay pinned and reachable.
   This is not the page scrolling — the sidebar as a whole still holds still. */
.nav { display: flex; flex-direction: column; gap: var(--hz-space-1); overflow-y: auto; min-height: 0; }
.nav__item {
  display: flex;
  align-items: center;
  gap: var(--hz-space-3);
  background: transparent;
  border: 0;
  border-radius: var(--hz-radius-md);
  padding: var(--hz-space-3) var(--hz-space-3);
  color: var(--hz-fg-on-dark-2);
  font-family: var(--hz-sans);
  font-size: var(--hz-body-sm-size);
  font-weight: 500;
  cursor: pointer;
  text-align: left;
  text-decoration: none;
  transition: background-color .15s, color .15s;
}
.nav__item:hover { background: var(--hz-line-on-dark); color: var(--hz-fg-on-dark); }
.nav__item--active, .nav__item--active:hover {
  background: var(--hz-purple-deep);
  color: var(--hz-fg-on-dark);
}

/* Sidebar foot — pinned to the bottom via margin-top:auto: trust chips + user card */
.sidebar__foot {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: var(--hz-space-3);
}
.trust {
  display: flex;
  align-items: center;
  gap: var(--hz-space-2);
  font-size: var(--hz-micro-size);
  color: var(--hz-fg-on-dark-2);
  padding: 0 var(--hz-space-2);
}
.trust .ms { font-size: 16px; }
.user-card {
  display: flex;
  align-items: center;
  gap: var(--hz-space-2);
  border-top: 1px solid var(--hz-line-on-dark);
  padding-top: var(--hz-space-3);
}
.user-card__avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--hz-radius-pill);
  background: var(--hz-purple-soft);
  color: var(--hz-ink);
  font-weight: 700;
  font-size: var(--hz-caption-size);
  flex: none;
}
.user-card__name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--hz-body-sm-size);
  color: var(--hz-fg-on-dark);
}
.user-card__lang, .user-card__logout {
  background: transparent;
  border: 0;
  color: var(--hz-fg-on-dark-2);
  cursor: pointer;
  font-family: var(--hz-sans);
  font-weight: 700;
  font-size: var(--hz-micro-size);
  padding: var(--hz-space-1);
  flex: none;
}
.user-card__lang:hover, .user-card__logout:hover { color: var(--hz-fg-on-dark); }

/* Main pane — routed view sits in a centered content column */
/* The only scrolling region. min-height: 0 is what lets a grid item actually
   scroll rather than growing to fit its content. */
.main {
  --hz-main-pad: var(--hz-space-8);
  padding: var(--hz-main-pad);
  max-width: 1120px;
  overflow-y: auto;
  min-height: 0;
}
/* The hire route lifts the cap so the role catalogue can spread across the
   whole browser; the wizard steps and result below re-impose it themselves,
   since a form stretched over a wide monitor reads worse, not better. */
.main--wide { max-width: none; }
.main--wide .wizard, .main--wide .wizard__result { max-width: calc(1120px - 2 * var(--hz-space-8)); }
/* Smaller screens trade gutter for content; the pad is a custom property so
   rules that bleed to the pane edge (sub-tabs) can undo exactly this much.
   The bottom and side pads grow by the device's safe areas (notch, home bar). */
@media (max-width: 899px) {
  .main {
    --hz-main-pad: var(--hz-space-5);
    padding-bottom: calc(var(--hz-main-pad) + env(safe-area-inset-bottom));
  }
}
@media (max-width: 599px) {
  .main {
    --hz-main-pad: var(--hz-space-4);
    padding-left: max(var(--hz-main-pad), env(safe-area-inset-left));
    padding-right: max(var(--hz-main-pad), env(safe-area-inset-right));
  }
  .card, .stat-card { padding: var(--hz-space-4); }
}
/* Stub — full coming-soon pane for a routed view or tab (Connectors, Billing,
   Admin & roles' Groups/Audit tabs); shares the tile's icon-on-purple-ring
   motif but centered and full-width. */
.stub {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--hz-space-3);
  padding: var(--hz-space-10) var(--hz-space-5);
  margin: var(--hz-space-9) auto 0;
  max-width: 480px;
}
.stub__icon {
  width: 120px;
  height: 120px;
  border-radius: var(--hz-radius-pill);
  border: 2.5px solid var(--hz-purple);
  background: transparent;
  color: var(--hz-purple);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--hz-h3-size);
  margin-bottom: var(--hz-space-3);
}
@media (max-width: 599px) {
  .stub { padding: var(--hz-space-8) var(--hz-space-3); margin-top: var(--hz-space-6); }
  .stub__icon { width: 88px; height: 88px; }
}

/* Hire wizard — Catalog / Stepper / Result. Fidelity refs:
   screenshots/catalog.png, config-profil.png, config-data.png, config-review.png. */
/* As many roles per row as fit at a readable tile width, so a wide browser
   shows three or four across while each tile still has room for its
   description. One per row once two would be cramped. */
.wizard__catalog-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
  gap: var(--hz-space-4);
  margin-top: var(--hz-space-5);
}
@media (max-width: 599px) { .wizard__catalog-grid { grid-template-columns: 1fr; } }

/* The catalogue's toolbar: the search box with the contact call to action
   beside it; the pill wraps under the search box where the row is narrow. */
.wizard__catalog-toolbar { display: flex; align-items: center; flex-wrap: wrap; gap: var(--hz-space-3) var(--hz-space-4); margin-top: var(--hz-space-6); }
.wizard__catalog-toolbar .wizard__catalog-search { margin-top: 0; flex: 1 1 280px; }

/* Search — filters the loaded catalogue. The magnifier sits inside the field's
   border so the two read as one control, which is why the input drops its own
   border rather than nesting a second one. */
.wizard__catalog-search {
  display: flex;
  align-items: center;
  gap: var(--hz-space-2);
  margin-top: var(--hz-space-6);
  padding: 0 var(--hz-space-4);
  border: 1px solid var(--hz-line-strong);
  border-radius: var(--hz-radius-sm);
  background: var(--hz-paper);
  max-width: 420px;
}
.wizard__catalog-search:focus-within { border-color: var(--hz-purple); }
.wizard__catalog-search .ms { font-size: 20px; color: var(--hz-fg-3); flex: none; }
.wizard__catalog-search .input {
  flex: 1;
  border: 0;
  padding: var(--hz-space-3) 0;
  background: transparent;
}
.wizard__catalog-search .input:focus { outline: none; }
/* The browser's own clear affordance on type=search, which would sit oddly
   against the borderless input. */
.wizard__catalog-search .input::-webkit-search-cancel-button { cursor: pointer; }
/* Scaled with the ring (100 -> 64px) so it sits inside it rather than
   filling it edge to edge. */
.tile__icon { width: 32px; height: 32px; }
/* The catalogue's two groups, each under its own heading. */
.wizard__catalog-group { margin-top: var(--hz-space-8); }

/* Role card — one template in the catalogue: head, task, capabilities, what
   it needs, and the two ways on. A column so the actions sit at the bottom
   whatever the card above them holds. */
.rolecard {
  display: flex;
  flex-direction: column;
  gap: var(--hz-space-3);
  background: var(--hz-paper);
  border: 1px solid var(--hz-line);
  border-radius: var(--hz-radius-lg);
  box-shadow: var(--hz-shadow-sm);
  padding: var(--hz-space-4);
}
.rolecard__head { display: flex; align-items: center; gap: var(--hz-space-3); }
.rolecard__title { display: flex; flex-direction: column; align-items: flex-start; gap: var(--hz-space-1); min-width: 0; }
.rolecard__task { margin: 0; color: var(--hz-fg-2); font-size: var(--hz-body-sm-size); }
.rolecard__needs { display: flex; flex-direction: column; gap: var(--hz-space-2); }
.rolecard__actions { display: flex; gap: var(--hz-space-2); flex-wrap: wrap; margin-top: auto; padding-top: var(--hz-space-2); }

/* Capability bullets as a ticked list, on the card and on the role page. */
.checklist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--hz-space-1); }
.checklist li { display: flex; align-items: flex-start; gap: var(--hz-space-2); font-size: var(--hz-body-sm-size); color: var(--hz-fg-1); }
.checklist .ms { color: var(--hz-purple); font-size: 18px; flex: none; }

/* Connector-type chips: what a role needs to run. */
.needchips { display: flex; flex-wrap: wrap; gap: var(--hz-space-2); }
.needchip {
  display: inline-flex; align-items: center; gap: var(--hz-space-1);
  padding: 2px var(--hz-space-3) 2px var(--hz-space-2);
  border: 1px solid var(--hz-line-strong); border-radius: var(--hz-radius-pill);
  font-size: var(--hz-caption-size); font-weight: 600; color: var(--hz-fg-2); background: var(--hz-paper);
}
.needchip .ms { font-size: 16px; color: var(--hz-purple); }

/* Small-caps section label shared by the card and the role page. */
.role__label { font-size: var(--hz-micro-size); font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--hz-fg-3); }

/* Role page — the full story of one role beside the panel that hires it. */
.role__grid { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: var(--hz-space-6); margin-top: var(--hz-space-5); align-items: start; }
@media (max-width: 899px) { .role__grid { grid-template-columns: 1fr; } }
.role__main { display: flex; flex-direction: column; gap: var(--hz-space-5); }
.role__task { margin: 0; }
.role__section { display: flex; flex-direction: column; gap: var(--hz-space-2); }
.role__section p { margin: 0; }
.role__needs { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--hz-space-3); }
.role__need { display: flex; flex-direction: column; gap: var(--hz-space-2); padding: var(--hz-space-3); border: 1px solid var(--hz-line); border-radius: var(--hz-radius-lg); background: var(--hz-paper); }
.role__need--required { border-color: var(--hz-purple); }
.role__need p { margin: 0; font-size: var(--hz-body-sm-size); color: var(--hz-fg-2); }
.role__side { position: sticky; top: var(--hz-space-5); display: flex; flex-direction: column; gap: var(--hz-space-3); padding: var(--hz-space-4); border: 1px solid var(--hz-line); border-radius: var(--hz-radius-lg); background: var(--hz-paper); box-shadow: var(--hz-shadow-sm); }
.role__side p { margin: 0; }
/* row-gap already separates it from the head above. */
.tile__desc { display: block; margin: 0; }

.wizard__backlink {
  display: inline-flex;
  align-items: center;
  gap: var(--hz-space-2);
  background: transparent;
  border: 0;
  color: var(--hz-fg-3);
  font-family: var(--hz-sans);
  font-size: var(--hz-caption-size);
  font-weight: 600;
  cursor: pointer;
  padding: 0;
  margin-bottom: var(--hz-space-4);
}
.wizard__backlink:hover { color: var(--hz-purple); }
.wizard__backlink .ms { font-size: 18px; }

/* Two-column layout: the stepper pane + the sticky live-preview Steckbrief */
.wizard {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 340px;
  gap: var(--hz-space-8);
  align-items: start;
}
.stepper__progress {
  display: flex;
  align-items: center;
  gap: var(--hz-space-3);
  margin: var(--hz-space-5) 0 var(--hz-space-6);
}
.stepper__progress-bar {
  flex: 1;
  height: 4px;
  border-radius: var(--hz-radius-pill);
  background: var(--hz-line);
  overflow: hidden;
}
.stepper__progress-fill { height: 100%; background: var(--hz-purple); transition: width .2s; }
.stepper__form { display: flex; flex-direction: column; gap: var(--hz-space-5); }
.stepper__fields { display: flex; flex-direction: column; gap: var(--hz-space-4); }
.stepper__actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--hz-space-4);
  margin-top: var(--hz-space-4);
}
/* Steckbrief — purple-avatar live-preview card beside the stepper */
/* Not sticky on purpose: the card stays put at the top of its column while the
   form beside it changes height from step to step. */
.wizard__preview { align-self: start; }
.steckbrief {
  background: var(--hz-paper);
  border-radius: var(--hz-radius-xl);
  box-shadow: var(--hz-shadow-pop);
  padding: var(--hz-space-6) var(--hz-space-5);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--hz-space-1);
}
.steckbrief__avatar {
  width: 72px;
  height: 72px;
  border-radius: var(--hz-radius-pill);
  background: var(--hz-purple);
  color: var(--hz-fg-on-dark);
  border: 4px solid var(--hz-purple-soft);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--hz-display);
  font-size: var(--hz-h3-size);
  margin-bottom: var(--hz-space-3);
}
.steckbrief__name {
  font-family: var(--hz-display);
  font-size: var(--hz-h3-size);
  line-height: 1.1;
  color: var(--hz-ink);
  /* The customer types the name while the card shows it live. A long German
     name has no space to break at, so it must wrap inside the card's width
     rather than run out of its right edge. */
  min-width: 0;
  max-width: 100%;
  overflow-wrap: anywhere;
}
.steckbrief__role { color: var(--hz-fg-3); font-size: var(--hz-body-sm-size); margin-top: var(--hz-space-1); }
.steckbrief .badge { margin-top: var(--hz-space-3); }
.steckbrief__sections {
  width: 100%;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: var(--hz-space-4);
  margin-top: var(--hz-space-5);
  padding-top: var(--hz-space-5);
  border-top: 1px solid var(--hz-line);
}
.steckbrief__section-title {
  font-size: var(--hz-micro-size);
  font-weight: 700;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--hz-fg-3);
}
.steckbrief__section-body { font-size: var(--hz-body-sm-size); color: var(--hz-fg-1); margin-top: var(--hz-space-1); }

/* Result — post-deploy confirmation */
.wizard__result {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--hz-space-4);
  padding: var(--hz-space-9) 0;
}
.wizard__result-icon { font-size: 56px; color: var(--hz-success); }

/* Employee detail — header profile card + at-a-glance/placeholder card grid.
   Fidelity ref: screenshots/profile.png. */
.detail-header {
  display: flex;
  align-items: center;
  gap: var(--hz-space-5);
  /* The card edge already separates the header from the tabs, so this gap
     only has to acknowledge it, not restate it. */
  margin-bottom: var(--hz-space-4);
}
.detail-header__avatar {
  width: 88px;
  height: 88px;
  border-radius: var(--hz-radius-pill);
  object-fit: cover;
  background: var(--hz-purple-soft);
  flex: none;
}
.detail-header__body { flex: 1; min-width: 0; }
.detail-header__body .hz-h2 { margin: 0; }
.detail-header__role { color: var(--hz-fg-3); font-size: var(--hz-body-sm-size); margin: var(--hz-space-1) 0 0; }
.detail-header__badges { display: flex; align-items: center; gap: var(--hz-space-2); margin-top: var(--hz-space-3); }
/* Detail actions — the status-aware lifecycle controls, icon-only, stacked
   down the right edge of the header card where the running cost used to sit.
   Delete is separated by a hairline rather than pushed to an edge, so the
   group still reads as one control cluster. */
.detail-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--hz-space-1);
  /* It sits in the header's own flex row, so it must neither stretch nor
     shrink as the name beside it grows. */
  flex: none;
}
.detail-actions__danger {
  display: flex;
  /* Stacked, the hairline that sets Delete apart runs across, not down. */
  margin-top: var(--hz-space-2);
  padding-top: var(--hz-space-2);
  border-top: 1px solid var(--hz-line);
}
.detail-actions__danger .btn { color: var(--hz-danger); }
.detail-actions__danger .btn:hover:not(:disabled) { color: var(--hz-danger); background: var(--hz-cream); }
/* Phones: the header wraps and the lifecycle rail becomes a labelled row
   under it (see LifecycleActions). Scoped to the header because the save rows
   further down reuse .detail-actions and must keep their own layout. */
@media (max-width: 599px) {
  .detail-header { flex-wrap: wrap; gap: var(--hz-space-4); }
  .detail-header__avatar { width: 64px; height: 64px; }
  .detail-header__body { flex: 1 1 200px; }
  .detail-header__badges { flex-wrap: wrap; }
  .detail-header .detail-actions {
    flex: 1 1 100%;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: stretch;
    gap: var(--hz-space-2);
    border-top: 1px solid var(--hz-line);
    padding-top: var(--hz-space-3);
  }
  .detail-header .detail-actions .btn { flex: 1 1 auto; justify-content: center; }
  .detail-header .detail-actions__danger {
    margin: 0 0 0 auto;
    padding: 0 0 0 var(--hz-space-2);
    border-top: 0;
    border-left: 1px solid var(--hz-line);
  }
}

/* Budget — the monthly spend limit. The field holds a currency amount, so it
   is sized for one and the button sits beside it rather than under it; a
   primary action the width of the card reads as a banner, not a button. */
/* The help line above carries no bottom margin (.detail-muted zeroes it), so
   the separation belongs here — the same gap .model-tiers uses. */
.detail-requesty__form { display: flex; align-items: flex-end; gap: var(--hz-space-3);
  flex-wrap: wrap; margin-top: var(--hz-space-5); }
/* Reuses .field for the label; only the label-to-field gap is tightened, to
   match the rhythm the model tiers now use. */
.detail-requesty__field { gap: 6px; }
/* Scoped to the form, not to a .detail-requesty wrapper: the panel renders a
   Card now, so no such ancestor exists. */
.detail-requesty__form .input { max-width: 148px; }

/* Employee detail tabs — pill bar (shared .tabs/.tab) plus the panel below it */
.detail-tabs { margin: var(--hz-space-4) 0 var(--hz-space-3); }
.detail-tabpanel { margin-top: var(--hz-space-2); }
/* Company settings — the employee header with the company's initial where
   the avatar sits, and the free-text fields shown as they were typed. */
.company-mark { display: flex; align-items: center; justify-content: center; font-family: var(--hz-serif);
  font-size: 36px; font-weight: 600; color: var(--hz-purple); }
.company-address { margin: 0; white-space: pre-line; overflow-wrap: anywhere; }
.company-form { display: flex; flex-direction: column; gap: var(--hz-space-4); margin-top: var(--hz-space-4); max-width: 560px; }
.company-form__actions { flex-direction: row; justify-content: flex-end; align-items: center; gap: var(--hz-space-3); }
.detail-muted { color: var(--hz-fg-3); margin: 0; }

/* Chat tab — centered "coming soon" placeholder */
.detail-chat-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--hz-space-2);
  padding: var(--hz-space-7) var(--hz-space-5);
  color: var(--hz-fg-3);
}
.detail-chat-empty .ms { font-size: 40px; opacity: 0.5; }
.detail-chat-empty__title { font-weight: 600; color: var(--hz-fg-1); margin: 0; }

/* Chat tab — live text chat: bounded-height panel so the message list scrolls
   internally instead of growing the whole page; bubbles left (agent) / right (user). */
/* The chat panel is deliberately not a .card: the transcript below carries the
   border, so wrapping it in one would inset the only visible edge by the card's
   padding and sit lower than the cards on every other tab. */
.chat { display: flex; flex-direction: column; height: 520px; }
/* The transcript is framed rather than titled: the tab above the card already
   names this screen, so the border is what marks where the history begins and
   ends — and it makes the scrolling region legible now that nothing labels it. */
.chat__list {
  flex: 1;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--hz-space-3);
  border: 1px solid var(--hz-line);
  /* radius-lg, not md: this frame is now a top-level surface sitting beside
     the cards on the other tabs, so it takes their corner, not a nested
     element's. */
  border-radius: var(--hz-radius-lg);
  padding: var(--hz-space-4);
}
.chat__msg {
  max-width: 72%;
  padding: var(--hz-space-3) var(--hz-space-4);
  border-radius: var(--hz-radius-md);
  font-size: var(--hz-body-sm-size);
  overflow-wrap: anywhere;
}
.chat__msg--user {
  align-self: flex-end;
  background: var(--hz-purple-faint);
  color: var(--hz-fg-1);
  white-space: pre-wrap;
}
.chat__msg--agent { align-self: flex-start; background: var(--hz-cream); color: var(--hz-fg-1); }
.chat__msg--agent p { margin: 0 0 var(--hz-space-2) 0; }
.chat__msg--agent p:last-child { margin-bottom: 0; }
.chat__msg--agent pre {
  background: var(--hz-paper-2);
  border-radius: var(--hz-radius-sm);
  padding: var(--hz-space-3);
  overflow-x: auto;
}
.chat__msg--agent code { font-family: var(--hz-mono); }
.chat__thinking { color: var(--hz-fg-3); font-size: var(--hz-body-sm-size); padding: 0 var(--hz-space-2); }

/* Chat tab — attachments: chip row (shared between the composer's pending
   selection and a message bubble's already-sent files), inline agent images,
   and the composer's attach control. */
.chat__composer-col { display: flex; flex-direction: column; gap: var(--hz-space-2); margin-top: var(--hz-space-4); }
.chat__composer { display: flex; align-items: flex-end; gap: var(--hz-space-3); }
/* The composer sizes itself from its content (see chat.js), so it must not
   carry a min-height that pins it to two rows, and manual resizing would only
   fight the next keystroke. max-height is where the growing stops and the
   textarea scrolls instead, so a pasted essay cannot push the transcript off
   the screen. */
.chat__composer .input {
  flex: 1;
  resize: none;
  max-height: 168px;
  /* chat.js switches this to auto only once max-height actually clamps the
     box, so a message that fits shows no scrollbar. */
  overflow-y: hidden;
}
.chat__file-input { display: none; }
.chat__attach-hint { margin: 0; }
.chat__chips { display: flex; flex-wrap: wrap; gap: var(--hz-space-2); }
.chat__chip {
  display: inline-flex;
  align-items: center;
  gap: var(--hz-space-1);
  max-width: 220px;
  background: var(--hz-purple-faint);
  color: var(--hz-fg-1);
  border-radius: var(--hz-radius-pill);
  padding: var(--hz-space-1) var(--hz-space-3);
  font-size: var(--hz-body-sm-size);
}
.chat__chip-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat__chip-remove {
  background: none;
  border: 0;
  cursor: pointer;
  color: var(--hz-fg-3);
  font-size: 12px;
  line-height: 1;
  padding: 0;
}
.chat__chip-remove:hover { color: var(--hz-danger); }
.chat__img {
  display: block;
  max-width: 260px;
  max-height: 260px;
  border-radius: var(--hz-radius-sm);
  margin-top: var(--hz-space-2);
}
.chat__file-link { display: inline-block; margin-top: var(--hz-space-2); }

/* Integrations tab — a list of card-like rows (kind · status · actions) and the
   admin add control. Previously unstyled, which read as broken spacing. */
/* Small screens: the transcript takes a viewport-derived height so the
   composer's own growth never squeezes it, and bubbles use more of the width. */
@media (max-width: 899px) {
  .chat { height: auto; }
  .chat__list { flex: none; height: clamp(240px, calc(100dvh - 420px), 480px); }
}
@media (max-width: 599px) {
  .chat__msg { max-width: 88%; }
  .chat__img { max-width: 100%; }
  .chat__composer { gap: var(--hz-space-2); }
}

/* Configuration › Integrations — one page, three groups (channels, connectors,
   skills). Every catalogue entry is a row with its switch at the right edge;
   a switched-on entry that has settings of its own unfolds them beneath its
   head, inside the same row, so nothing about one connection sits elsewhere. */
.integrations-page { display: flex; flex-direction: column; gap: var(--hz-space-5); }
/* The help line is the group's instruction, not the first row's caption. */
.toggle-group__help { margin-bottom: var(--hz-space-4); }
.toggle-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--hz-space-3); }
/* A note or error after the list is a separate thought, not the next row. */
.toggle-list ~ p { margin-top: var(--hz-space-4); }
.toggle-row {
  padding: var(--hz-space-3) var(--hz-space-4);
  background: var(--hz-cream);
  border: 1px solid var(--hz-line);
  border-radius: var(--hz-radius-md);
}
.toggle-row--on { border-color: var(--hz-purple-soft); background: var(--hz-paper); }
.toggle-row__head { display: flex; align-items: center; gap: var(--hz-space-3); }
.toggle-row__icon { font-size: 22px; color: var(--hz-fg-3); flex: none; }
.toggle-row--on .toggle-row__icon { color: var(--hz-purple); }
.toggle-row__text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.toggle-row__name { font-weight: 600; color: var(--hz-fg-1); font-size: var(--hz-body-sm-size); }
.toggle-row__note { color: var(--hz-fg-2); }
.toggle-row__options {
  margin-top: var(--hz-space-3);
  padding-top: var(--hz-space-3);
  border-top: 1px solid var(--hz-line);
  display: flex;
  flex-direction: column;
  gap: var(--hz-space-2);
}
.toggle-row__status, .toggle-row__actions { display: flex; align-items: center; flex-wrap: wrap; gap: var(--hz-space-3); }
/* Slack workspace connection — the short form unfolded inside the Slack row
   when the tenant has not handed over a workspace token yet. It is a form, not
   a setting, so it reads as steps with a field at the end. */
.slack-connect, .telegram-setup, .telegram-access { display: flex; flex-direction: column;
  gap: var(--hz-space-3); }
.slack-connect__steps, .telegram-setup__steps { margin: 0; padding-left: var(--hz-space-4);
  display: flex; flex-direction: column; gap: var(--hz-space-1); }
.slack-connect__steps a, .telegram-setup__steps a, .telegram-access a { color: var(--hz-purple);
  font-weight: 600; }

/* The two answers @BotFather will ask for, shown ready to copy: someone is
   doing this on a phone, so the suggestion has to be readable at a glance and
   obviously a value rather than prose. */
.telegram-setup__value { font-family: var(--hz-mono); font-size: 0.92em;
  background: var(--hz-cream); border-radius: var(--hz-radius-sm); padding: 0 var(--hz-space-1); }

/* Who may talk to a Telegram agent: two lists of name + number with an add row
   under each, and the open-to-anyone switch beneath them. */
.access-list { display: flex; flex-direction: column; gap: var(--hz-space-1); }
.access-list__rows { list-style: none; margin: 0; padding: 0; display: flex;
  flex-direction: column; gap: var(--hz-space-1); }
.access-list__row { display: flex; align-items: center; gap: var(--hz-space-2); }
.access-list__row span:first-child { flex: 1; }
.access-list__add { display: flex; flex-wrap: wrap; gap: var(--hz-space-2); align-items: center; }
.access-list__add .input { flex: 1; min-width: 8rem; }
/* The channel is set up and nothing is arriving: said plainly, with the way to
   push it along, above the settings it would otherwise look fine beside. */
.telegram-access__warning { display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--hz-space-2); padding: var(--hz-space-2) var(--hz-space-3);
  background: var(--hz-cream); border-radius: var(--hz-radius-sm); }
.telegram-access__warning p { flex: 1; min-width: 12rem; margin: 0; }
.telegram-access__open { display: flex; align-items: center; gap: var(--hz-space-3); }
.telegram-access__open .toggle-row__text { flex: 1; }
.toggle-row__actions a { font-size: var(--hz-body-sm-size); color: var(--hz-purple); font-weight: 600; }

/* Switch — the on/off control on every integration row. A track that fills
   purple when on, a knob that slides across; the knob pulses while the
   request behind a flip is still in flight, so the row visibly waits rather
   than flipping early. */
.switch {
  position: relative;
  flex: none;
  width: 42px;
  height: 24px;
  padding: 0;
  border: 0;
  border-radius: var(--hz-radius-pill);
  background: var(--hz-line-strong);
  cursor: pointer;
  transition: background 0.15s ease;
}
.switch__knob {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
  transition: transform 0.15s ease;
}
.switch--on { background: var(--hz-purple); }
.switch--on .switch__knob { transform: translateX(18px); }
.switch:disabled { cursor: default; opacity: 0.5; }
.switch--busy .switch__knob { animation: switch-pulse 0.9s ease-in-out infinite; }
.switch:focus-visible { outline: 2px solid var(--hz-purple); outline-offset: 2px; }
@keyframes switch-pulse { 50% { opacity: 0.4; } }
@media (max-width: 599px) {
  .toggle-row__actions { flex-basis: 100%; }
}

/* Model tiers — one labelled field per tier on the Configuration tab. The
   label sits above its field so a long model id has the full width, and the
   tier name is monospaced because it is a config key, not prose. */
/* A setting is separated from the next by more than its label is from its
   own field, so each label/field pair reads as one group. */
.model-tiers { display: flex; flex-direction: column; gap: var(--hz-space-7); margin-top: var(--hz-space-5); }
.model-tier { display: flex; flex-direction: column; gap: 6px; }
.model-tier__name { display: flex; align-items: center; gap: var(--hz-space-2); font-size: var(--hz-body-sm-size); }
/* The dropdown lists model names, so it reads in the sans face (the rule
   below gives the tier's fields the mono face; this one is the more specific
   of the two) and is capped like the field it replaced, so its arrow sits by
   the text rather than at the card's far edge. The arrow is drawn here: the
   browser's own would be pushed to the border, outside the field's padding. */
.model-tier select.model-tier__select {
  width: 100%; max-width: 400px; font-family: var(--hz-sans); cursor: pointer;
  appearance: none; -webkit-appearance: none;
  padding-right: calc(var(--hz-space-4) + 24px);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236b6478' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
  background-repeat: no-repeat; background-position: right var(--hz-space-3) center; background-size: 18px 18px;
}
/* A config key or a model id is an identifier the operator will compare
   character by character, so it gets the mono face wherever it appears. */
.mono { font-family: var(--hz-mono); }
/* Wide enough for the longest model id in play (claude-haiku-4-5-20251001,
   25 characters in the mono face) and no wider — a field that runs the width
   of the card reads as if it wanted a sentence. */
.model-tier .input { font-family: var(--hz-mono); font-size: var(--hz-body-sm-size); max-width: 400px; }
.pill-note {
  font-size: var(--hz-micro-size);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--hz-fg-3);
  background: var(--hz-cream);
  border: 1px solid var(--hz-line);
  border-radius: var(--hz-radius-pill);
  padding: 2px var(--hz-space-2);
}
.pill-note--warn { color: var(--hz-purple); border-color: var(--hz-purple); }

/* Detail grid — At a glance + the poller-metrics cards (activity/usage/model),
   each degrading per-value to the neutral Placeholder until polled */
/* Overview's headline figures. Four across on a wide screen, two when that
   would squeeze a seven-digit token count. */
.detail-stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--hz-space-4);
  margin-bottom: var(--hz-space-4);
}
@media (max-width: 899px) { .detail-stats { grid-template-columns: repeat(2, 1fr); } }
.detail-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--hz-space-4);
  /* Let each card end where its content does, rather than stretching the
     shorter one to match and leaving a lane of empty card behind it. */
  align-items: start;
}
@media (max-width: 899px) { .detail-grid { grid-template-columns: 1fr; } }
.detail-card__head {
  display: flex;
  align-items: center;
  gap: var(--hz-space-2);
  color: var(--hz-fg-3);
  margin-bottom: var(--hz-space-4);
}
.detail-card__head .ms { font-size: 18px; }
.detail-card__title {
  font-size: var(--hz-micro-size);
  font-weight: 700;
  letter-spacing: 0.5px;
  text-transform: uppercase;
}
/* A fixed label column so values line up with each other and sit next to the
   label they belong to. They used to be flung to the card's right edge, which
   left a lane of dead space the eye had to cross for every row. */
.glance-list {
  display: grid;
  grid-template-columns: minmax(0, 132px) 1fr;
  gap: var(--hz-space-3) var(--hz-space-4);
  margin: 0;
  font-size: var(--hz-body-sm-size);
}
.glance-list dt { color: var(--hz-fg-3); }
.glance-list dd { margin: 0; color: var(--hz-fg-1); overflow-wrap: anywhere; }
@media (max-width: 599px) {
  .glance-list { grid-template-columns: 1fr; gap: 2px 0; }
  .glance-list dd { margin-bottom: var(--hz-space-3); }
  .glance-list dd:last-child { margin-bottom: 0; }
}

/* Onboarding — the first-run screen a self-registered person lands on, before
   they belong to any tenant. Renders outside the Shell, like the sign-in page
   it replaced (that page now lives at auth.hainzelman.com). */
.onboarding {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--hz-cream);
  padding: var(--hz-space-5);
}
.onboarding__card {
  display: flex;
  flex-direction: column;
  gap: var(--hz-space-3);
  width: 100%;
  max-width: 420px;
  padding: var(--hz-space-7) var(--hz-space-6);
  background: var(--hz-paper);
  border-radius: var(--hz-radius-lg);
  box-shadow: var(--hz-shadow-xl);
}
.onboarding__card .hz-eyebrow { margin-bottom: 0; }
.onboarding__card .btn { justify-content: center; margin-top: var(--hz-space-3); }
/* Phones: top-aligned so the card does not jump when the keyboard opens. */
@media (max-width: 599px) {
  .onboarding { align-items: flex-start; padding: var(--hz-space-8) var(--hz-space-4); }
  .onboarding__card { padding: var(--hz-space-6) var(--hz-space-5); }
}
.onboarding__card .field { display: flex; flex-direction: column; gap: var(--hz-space-2); font-size: var(--hz-body-sm-size); }
.onboarding__card .field input {
  height: 36px;
  border: 1px solid var(--hz-line-strong);
  border-radius: var(--hz-radius-sm);
  padding: 0 var(--hz-space-3);
  font: inherit;
}

/* Admin & roles — tabbed console over the caller's administrable tenants.
   Fidelity ref: screenshots/admin.png. */
.admin-roles .tabs { margin: var(--hz-space-6) 0 var(--hz-space-6); }
.roles-panel, .people-panel { display: flex; flex-direction: column; gap: var(--hz-space-5); }
.panel-heading {
  font-family: var(--hz-sans);
  font-weight: 700;
  font-size: var(--hz-micro-size);
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--hz-fg-3);
  margin: var(--hz-space-4) 0 0;
}

/* Pill tab bar — People / Roles / Groups / Audit */
.tabs {
  display: inline-flex;
  align-items: center;
  gap: var(--hz-space-1);
  background: var(--hz-paper);
  border: 1px solid var(--hz-line);
  border-radius: var(--hz-radius-pill);
  box-shadow: var(--hz-shadow-sm);
  padding: var(--hz-space-1);
}
.tab {
  background: transparent;
  border: 0;
  border-radius: var(--hz-radius-pill);
  padding: var(--hz-space-2) var(--hz-space-5);
  font-family: var(--hz-sans);
  font-weight: 600;
  font-size: var(--hz-body-sm-size);
  color: var(--hz-fg-3);
  cursor: pointer;
  transition: background-color .15s, color .15s;
}
.tab--active { background: var(--hz-purple); color: var(--hz-fg-on-dark); }

/* Configuration's sub-tabs. Underlined rather than a second pill bar: two
   pill rows with filled purple actives read as one confusing control, and the
   underline is already how this design language marks something subordinate. */
.detail-subtabs { margin-bottom: var(--hz-space-5); }
.tabs--sub {
  display: flex;
  background: transparent;
  box-shadow: none;
  padding: 0;
  border-radius: 0;
  border-bottom: 1px solid var(--hz-line);
  gap: 0;
}
.tabs--sub .tab {
  padding: var(--hz-space-2) var(--hz-space-4);
  border-radius: 0;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.tabs--sub .tab--active {
  background: transparent;
  color: var(--hz-purple);
  border-bottom-color: var(--hz-purple);
}
/* Phones: a tab bar scrolls sideways rather than wrapping or clipping. The
   sub-tabs bleed to the pane edge and fade out on the right so the overflow
   is visible; the pill bars usually fit once the padding tightens. */
@media (max-width: 599px) {
  .tabs { display: flex; max-width: 100%; overflow-x: auto; scrollbar-width: none; }
  .tabs::-webkit-scrollbar { display: none; }
  .tab { flex: none; white-space: nowrap; padding: var(--hz-space-2) var(--hz-space-4); }
  .tabs--sub {
    margin: 0 calc(-1 * var(--hz-main-pad));
    padding: 0 var(--hz-main-pad);
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent);
            mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent);
  }
}

/* Tenant tree — the real administrable-tenant hierarchy, People tab */
.tenant-tree { list-style: none; margin: 0; padding: var(--hz-space-4) var(--hz-space-5); }
.tenant-tree .tenant-tree { padding: var(--hz-space-2) 0 0 var(--hz-space-5); box-shadow: none; }
.tenant-tree__item { display: flex; align-items: baseline; gap: var(--hz-space-2); padding: var(--hz-space-2) 0; }
.tenant-tree__name { font-weight: 600; color: var(--hz-fg-1); font-size: var(--hz-body-sm-size); }
@media (max-width: 599px) {
  .admin-roles .tabs { margin: var(--hz-space-5) 0; }
  .tenant-tree { padding: var(--hz-space-3) var(--hz-space-4); }
  .tenant-tree .tenant-tree { padding-left: var(--hz-space-3); }
  .tenant-tree__item { flex-wrap: wrap; }
  .tenant-tree__item > .hz-micro { overflow-wrap: anywhere; }
  /* The nested list is a flex child of its parent row; on a phone it takes its own line. */
  .tenant-tree__item > .tenant-tree { flex-basis: 100%; }
}

/* Role card — one role's identity, scope badge, and description; no
   fabricated permission chips or member counts (see tenants.js). */
.role-card {
  display: flex;
  align-items: flex-start;
  gap: var(--hz-space-4);
  background: var(--hz-paper);
  border: 1px solid var(--hz-line);
  border-radius: var(--hz-radius-lg);
  box-shadow: var(--hz-shadow-sm);
  padding: var(--hz-space-5);
}
.role-card__icon {
  width: 48px;
  height: 48px;
  border-radius: var(--hz-radius-md);
  background: var(--hz-purple-soft);
  color: var(--hz-ink);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  flex: none;
}
.role-card__body { flex: 1; min-width: 0; }
.role-card__head { display: flex; align-items: center; gap: var(--hz-space-3); flex-wrap: wrap; }
.role-card__name { font-weight: 600; color: var(--hz-fg-1); font-size: var(--hz-body-sm-size); }
.role-card__desc { color: var(--hz-fg-2); font-size: var(--hz-caption-size); margin: var(--hz-space-2) 0 0; }

/* Settings — read-only account identity + the primary DE/EN language
   control. Fidelity ref: screenshots/account-lang.png. */
.settings { display: flex; flex-direction: column; gap: var(--hz-space-6); margin-top: var(--hz-space-2); }
.settings__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--hz-space-5);
  max-width: 720px;
}
.settings .field { gap: var(--hz-space-2); margin-top: var(--hz-space-4); max-width: 360px; }
.settings .input[readonly] { color: var(--hz-fg-2); background: var(--hz-cream); cursor: default; }

/* Language toggle — the two-way DE/EN language pill; mirrors .tabs but for exactly
   two mutually-exclusive choices rather than an N-way tab bar. */
.lang-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--hz-space-1);
  background: var(--hz-cream);
  border-radius: var(--hz-radius-pill);
  padding: var(--hz-space-1);
  margin-top: var(--hz-space-4);
}
.lang-toggle__btn {
  background: transparent;
  border: 0;
  border-radius: var(--hz-radius-pill);
  padding: var(--hz-space-2) var(--hz-space-5);
  font-family: var(--hz-sans);
  font-weight: 600;
  font-size: var(--hz-body-sm-size);
  color: var(--hz-fg-3);
  cursor: pointer;
  transition: background-color .15s, color .15s;
}
.lang-toggle__btn--active { background: var(--hz-purple); color: var(--hz-fg-on-dark); box-shadow: var(--hz-shadow-sm); }

/* Super-admin console: inline row actions and removable membership chips. */
.inline-actions { display: inline-flex; align-items: center; gap: var(--hz-space-2); flex-wrap: wrap; }
.chip__x {
  margin-left: var(--hz-space-2);
  border: 0; background: none; cursor: pointer;
  color: var(--hz-fg-2); font-size: 1em; line-height: 1;
}
.chip__x:hover { color: var(--hz-danger); }

/* Billing — current-month spend, per-agent table, usage chart, and past
   invoices. Cards reuse .card/.detail-card__head; these are the view's own
   header/total/table/chart/invoice primitives. */
.billing { display: flex; flex-direction: column; gap: var(--hz-space-6); margin-top: var(--hz-space-2); }
.billing__header { display: flex; flex-direction: column; gap: var(--hz-space-1); }
.billing__total { display: flex; align-items: baseline; gap: var(--hz-space-3); margin-top: var(--hz-space-3); }
.billing__total-value { font-family: var(--hz-display); font-size: var(--hz-h2-size); color: var(--hz-ink); }
.billing__total-label { color: var(--hz-fg-3); font-size: var(--hz-body-sm-size); }

/* Connector grid — the same connectors as tiles, mirroring the employee grid
   so the two screens' grid views read alike. */
.connector-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--hz-space-4);
}
.connector-card {
  display: flex;
  flex-direction: column;
  gap: var(--hz-space-3);
  background: var(--hz-paper);
  border: 1px solid var(--hz-line);
  border-radius: var(--hz-radius-lg);
  box-shadow: var(--hz-shadow-sm);
  padding: var(--hz-space-4);
}
.connector-card__head { display: flex; align-items: flex-start; gap: var(--hz-space-3); }
.connector-card__head .connectors__namecell { flex: 1; min-width: 0; }
/* The name may be long; it wraps rather than forcing the card wider. */
.connectors__namecell { display: flex; flex-direction: column; gap: var(--hz-space-1); min-width: 0; }
/* Right-aligned like the row's actions, and never squeezed by a long name. */
.connector-card__actions { display: flex; align-items: center; gap: var(--hz-space-1); flex: none; }
.connector-card__meta { display: flex; align-items: center; gap: var(--hz-space-3); flex-wrap: wrap; }
.connectors__name { font-weight: 600; overflow-wrap: anywhere; }
/* The glyph in front of a platform-given storage's name: whose it is (the
   tenant's, or one digital employee's), since its name alone does not say. */
.connectors__owner { display: inline-flex; align-items: center; gap: var(--hz-space-1); }
.connectors__owner .connectors__icon { flex: none; }

/* Billing table — per-agent cost/token rows, mirrors .employee-table's cells */
.billing__table { width: 100%; border-collapse: collapse; }
.billing__table th {
  text-align: left;
  font-family: var(--hz-sans);
  font-weight: 600;
  font-size: var(--hz-micro-size);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--hz-fg-3);
  padding: var(--hz-space-3) var(--hz-space-4);
  border-bottom: 1px solid var(--hz-line);
}
.billing__table td {
  padding: var(--hz-space-3) var(--hz-space-4);
  border-bottom: 1px solid var(--hz-line);
  font-size: var(--hz-body-sm-size);
  color: var(--hz-fg-1);
}
.billing__table tr:last-child td { border-bottom: 0; }
/* Both measured columns — the amount and the token count — read as columns of
   figures: right-aligned on the same edge, tabular digits so decimal points
   and thousands line up down the column, and never wrapped. The treatment the
   file and failure sizes already get. Scoped to the table so it beats the
   header's left alignment; at phone width the stacked rule wins and the
   label/value pair takes over. */
.billing__table .billing__figure { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }

/* Billing usage chart — bars scaled to the month's busiest day, no chart
   library: each bar is a plain div sized by inline height percentage. */
/* The chart is two rows: the bars, all standing on one shared baseline, and
   the day numbers beneath them in their own row, so an unlabelled day never
   lifts or lowers its bar. Both rows use the same flex slots so the numbers
   line up under their bars. */
.billing__chart { padding-top: var(--hz-space-4); }
.billing__bars {
  display: flex;
  align-items: flex-end;
  gap: var(--hz-space-1);
  height: 140px;
  border-bottom: 1px solid var(--hz-line);
}
.billing__bar-col {
  flex: 1;
  min-width: 4px;
  height: 100%;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}
.billing__bar { width: 100%; max-width: 18px; background: var(--hz-purple); border-radius: var(--hz-radius-sm) var(--hz-radius-sm) 0 0; }
.billing__labels { display: flex; gap: var(--hz-space-1); margin-top: var(--hz-space-1); }
.billing__bar-label { flex: 1; min-width: 4px; text-align: center; font-size: var(--hz-micro-size); color: var(--hz-fg-3); white-space: nowrap; overflow: hidden; }
/* Phones: a month of bars still fits, but only every sixth day label does
   (the 1st, 7th, 13th …); the rest stay in the flow so the columns keep
   lining up with their bars. */
@media (max-width: 599px) {
  .billing__bars, .billing__labels { gap: 2px; }
  .billing__bar-label { font-size: 10px; overflow: visible; }
  .billing__bar-label:not(:nth-child(6n + 1)) { visibility: hidden; }
  .billing__invoice-row { flex-wrap: wrap; }
}

/* Billing invoices — one expandable row per finalized month; at most one
   open at a time, its per-agent lines rendered via .billing__table. */
.billing__invoice-list { display: flex; flex-direction: column; gap: var(--hz-space-2); }
.billing__invoice { border: 1px solid var(--hz-line); border-radius: var(--hz-radius-md); overflow: hidden; }
.billing__invoice-row {
  width: 100%;
  display: flex;
  align-items: center;
  gap: var(--hz-space-4);
  background: var(--hz-paper);
  border: 0;
  padding: var(--hz-space-3) var(--hz-space-4);
  font-family: var(--hz-sans);
  font-size: var(--hz-body-sm-size);
  color: var(--hz-fg-1);
  cursor: pointer;
  text-align: left;
}
.billing__invoice-row:hover { background: var(--hz-cream); }
.billing__invoice-period { font-weight: 600; flex: 1; }
/* The amount in an invoice row is a column too, even though the row is flex:
   without a width of its own each amount sits wherever its digits end and the
   status badge after it shifts from row to row. */
.billing__invoice-cost {
  color: var(--hz-fg-2);
  min-width: 96px;
  text-align: right;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.billing__invoice-detail { padding: var(--hz-space-2) var(--hz-space-4) var(--hz-space-4); background: var(--hz-cream); }
/* The heading over an invoice's document-indexing lines, which only appears
   when the month has any: it separates two tables that bill for different
   things and must not read as one list. */
.billing__detail-head { margin: var(--hz-space-4) 0 var(--hz-space-2); font-size: 0.875rem; font-weight: 600; }
/* On a phone the row has no width to reserve: holding a lane open for the
   amount pushes a longer month name onto a second line, so the amount goes
   back to taking only the room its digits need. */
@media (max-width: 599px) {
  .billing__invoice-cost { min-width: 0; }
}

/* Connectors — storage connector list, add flow, and inline row actions.
   Cards/badges reuse .card/.badge; these are the view's own layout primitives. */
/* .connectors has no rule of its own on purpose: a plain block, like the Team
   screen. The stat row and toolbar are shared between the two and bring their
   own margins, and adjacent margins only collapse in a block — as a flex
   container this screen added them instead and sat 32px looser at every step.
   Banners therefore carry the margin the container's gap used to provide. */
.connectors__banner { margin-bottom: var(--hz-space-4); }
.connectors__banner { padding: var(--hz-space-3) var(--hz-space-4); border-radius: var(--hz-radius-md); background: var(--hz-cream); border: 1px solid var(--hz-warning); color: var(--hz-fg-1); font-size: var(--hz-body-sm-size); }
.connectors__banner--ok { border-color: var(--hz-success); }
.connectors__table { width: 100%; border-collapse: collapse; font-size: var(--hz-body-sm-size); }
.connectors__table th { text-align: left; padding: var(--hz-space-2) var(--hz-space-3); color: var(--hz-fg-2); font-weight: 600; }
/* middle, not top: a row is one line of data, and the action buttons sat
   against the top of the cell while the name, status and date read lower down.
   The employee table has always used middle for the same reason. */
.connectors__table td { padding: var(--hz-space-3); border-top: 1px solid var(--hz-line); vertical-align: middle; }
/* Between the phone (cards) and the desktop (room for six columns) the table
   scrolls sideways inside its card rather than stretching the page. */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
@media (max-width: 899px) {
  .connectors__table { min-width: 720px; }
  .connectors__table td { padding: var(--hz-space-2); }
  .connectors__table td:first-child { min-width: 180px; }
  .connectors__table .connectors__ragbar { width: 64px; }
}
/* align-items matters here: without it the flex default is stretch, so each
   button grew to the full height of the cell and only looked centred when the
   row happened to be one line tall. */
.connectors__actions { display: flex; gap: var(--hz-space-1); justify-content: flex-end; align-items: center; }
.connectors__group-label { margin: var(--hz-space-4) 0 var(--hz-space-1); font-size: var(--hz-body-sm-size); font-weight: 600; color: var(--hz-fg-1); }
.connectors__providers { display: grid; grid-template-columns: repeat(auto-fill, minmax(116px, 1fr)); gap: var(--hz-space-2); margin: var(--hz-space-2) 0 0; }
.connectors__provider { display: flex; flex-direction: column; align-items: center; gap: var(--hz-space-2); padding: var(--hz-space-4) var(--hz-space-3); border: 1px solid var(--hz-line-strong); border-radius: var(--hz-radius-md); background: transparent; cursor: pointer; font: inherit; color: var(--hz-fg-1); }
/* A provider's own logo, where the Portal ships one. Sized in the same box as
   the glyph it stands in for (see ProviderMark) so the two mix without the row
   changing height, and contained rather than cropped because the marks do not
   share an aspect ratio — Outlook is wide, Dropbox is square. The logos carry
   their own brand colours, so nothing here tints them. */
.provider-mark { display: block; width: 20px; height: 20px; object-fit: contain; flex: none; }
.connectors__provider-mark { width: 28px; height: 28px; }
/* The tiles mix logos with glyphs (a protocol has no logo), so the glyph is
   drawn at the logo's size — otherwise the lettered products look heavier than
   the plain ones for no reason a reader could name. */
.connectors__provider .ms { font-size: 28px; }
img.toggle-row__icon { width: 22px; height: 22px; }

/* Icons standing in for words — the connector's kind and provider, its status,
   its indexing. Each carries its word as a tooltip, so the colour is a second
   reading of the same fact and never the only one. */
.connectors__icons { display: inline-flex; align-items: center; gap: var(--hz-space-2); }
.connectors__icon { display: inline-flex; color: var(--hz-fg-2); }
.connectors__icon .ms { font-size: 20px; }
.connectors__icon--plain { color: var(--hz-fg-1); }
.connectors__icon--ok { color: var(--hz-success); }
.connectors__icon--bad { color: var(--hz-danger); }
.connectors__icon--busy { color: var(--hz-purple); }
/* Indexing cell — what ragd is doing with a connector. The bar restates the
   tooltip's percentage as a shape, so a batch that is moving is
   distinguishable at a glance from one stuck on a single large file. */
.connectors__rag { display: flex; flex-direction: column; gap: var(--hz-space-2); align-items: flex-start; }
.connectors__ragbar {
  display: block;
  width: 96px;
  height: 4px;
  border-radius: var(--hz-radius-pill);
  background: var(--hz-line);
  overflow: hidden;
}
.connectors__ragbar-fill {
  display: block;
  height: 100%;
  border-radius: var(--hz-radius-pill);
  background: var(--hz-purple);
  transition: width .3s ease;
}
@media (prefers-reduced-motion: reduce) { .connectors__ragbar-fill { transition: none; } }

.connectors__provider--picked { border-color: var(--hz-purple); box-shadow: 0 0 0 2px var(--hz-purple-faint); }

/* Mailbox choices in the add dialog and the settings dialog: a slug field, a
   column of checkboxes, the tool-prefix preview. */
.connectors__fields { display: flex; flex-direction: column; gap: var(--hz-space-3); margin-top: var(--hz-space-4); max-width: 560px; }
.connectors__fields .field { margin-top: 0; max-width: none; }
.connectors__fields code { font-family: var(--hz-mono, ui-monospace, SFMono-Regular, Menlo, monospace); font-size: 0.92em; background: var(--hz-cream); padding: 0 var(--hz-space-1); border-radius: var(--hz-radius-sm); }
/* The kind-specific half of the settings dialog, under a rule: the name field
   above it belongs to every connector, what follows belongs to this one's
   kind. */
.connectors__settingsgroup { margin-top: var(--hz-space-5); border-top: 1px solid var(--hz-line); padding-top: var(--hz-space-3); }
.connectors__settingsgroup .connectors__dialogintro { margin-top: 0; }
/* A second group of fields under a rule, so a lone checkbox beside a set of
   radio options reads as its own question rather than a fourth option. */
.connectors__fields--divided { border-top: 1px solid var(--hz-line); padding-top: var(--hz-space-4); }
/* The dialog's closing line: when the connector was added. Under a rule,
   because it is the one thing in there nobody can change. */
.connectors__dialogmeta { margin: var(--hz-space-5) 0 0; border-top: 1px solid var(--hz-line); padding-top: var(--hz-space-3); }
.connectors__reference { font-family: var(--hz-mono, ui-monospace, SFMono-Regular, Menlo, monospace); font-size: 0.92em; user-select: all; }
.connectors__note { margin-top: var(--hz-space-4); padding: var(--hz-space-2) var(--hz-space-3); border-radius: var(--hz-radius-sm); background: var(--hz-cream); border: 1px solid var(--hz-warning); color: var(--hz-fg-1); }
/* The line under a settings dialog's heading, kept clear of the first field. */
.connectors__dialogintro { margin: var(--hz-space-2) 0 var(--hz-space-4); }
.modal--narrow { width: min(640px, 94vw); }
.check { display: flex; gap: var(--hz-space-3); align-items: flex-start; cursor: pointer; font-size: var(--hz-body-sm-size); }
.check input { margin: 3px 0 0; width: 16px; height: 16px; flex: none; accent-color: var(--hz-purple); }
.check > span { display: flex; flex-direction: column; gap: 2px; }
.check__label { font-weight: 600; color: var(--hz-fg-1); }
.check--disabled { cursor: default; opacity: 0.55; }
/* Mailbox health under the status badge: reading and sending separately. */

/* Modal — the webui's first modal dialog; a fixed scrim + centered panel.
   Wide by design: the add-connector picker holds a tile per storaged flow
   type, and the width keeps each provider family on a single row, so new
   connectors grow the grid sideways before they grow it downwards. max-height
   is the backstop for a short viewport, not the expected state; 94vw hands
   narrow screens back to the grid, which reflows to fewer columns. */
/* Tooltip — the app's own, because the browser's `title` waits about a second
   and a screen that speaks in glyphs needs its words sooner. One node on
   <body>, fixed, so no scroll container can clip it; never a pointer target,
   so it cannot steal the hover that opened it. Above the modal, since a dialog
   may hold glyphs of its own. */
.tooltip {
  position: fixed; top: 0; left: 0; z-index: 50;
  max-width: 280px;
  padding: var(--hz-space-1) var(--hz-space-2);
  border-radius: var(--hz-radius-sm);
  background: var(--hz-fg-1); color: var(--hz-paper);
  font-size: var(--hz-caption-size); line-height: 1.35;
  box-shadow: 0 2px 8px rgba(18, 18, 18, .18);
  pointer-events: none;
  opacity: 0; visibility: hidden;
  transition: opacity 80ms ease;
}
.tooltip--on { opacity: 1; visibility: visible; }
@media (prefers-reduced-motion: reduce) { .tooltip { transition: none; } }
.scrim { position: fixed; inset: 0; background: rgba(18, 18, 18, .28); z-index: 40; }
.modal { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); width: min(920px, 94vw); max-height: 88vh; overflow-y: auto; background: var(--hz-paper); border-radius: var(--hz-radius-lg); padding: var(--hz-space-5); z-index: 41; box-shadow: var(--hz-shadow-xl); }
.modal h3 { margin: 0 0 var(--hz-space-2); }
.modal .field { display: flex; flex-direction: column; gap: var(--hz-space-2); margin-top: var(--hz-space-4); max-width: 420px; font-size: var(--hz-body-sm-size); }
.modal .field input { height: 36px; border: 1px solid var(--hz-line-strong); border-radius: var(--hz-radius-sm); padding: 0 var(--hz-space-3); font: inherit; }
.modal__actions { display: flex; justify-content: flex-end; gap: var(--hz-space-2); margin-top: var(--hz-space-5); }
/* Phones: the dialog docks to the bottom edge as a sheet — reachable with a
   thumb, scrollable inside, and clear of the home indicator. */
@media (max-width: 599px) {
  .modal {
    top: auto;
    bottom: 0;
    left: 0;
    right: 0;
    transform: none;
    width: auto;
    max-height: 90dvh;
    border-radius: var(--hz-radius-lg) var(--hz-radius-lg) 0 0;
    padding: var(--hz-space-4) var(--hz-space-4) calc(var(--hz-space-4) + env(safe-area-inset-bottom));
  }
  .modal .field { max-width: none; }
  .modal__actions { flex-wrap: wrap; }
  .modal__actions .btn { flex: 1 1 auto; justify-content: center; }
  .connectors__providers { grid-template-columns: repeat(2, 1fr); }
}

/* ── File manager (tenant-data connector) ─────────────────────────────────
   Deliberately the same table, card and toolbar furniture as the Connectors
   screen it is reached from: the reader arrives here from a row's action, and
   a second visual language for a list of names would read as a different
   product. */
.files__toolbar { align-items: flex-start; }
.files__where { display: flex; align-items: center; gap: var(--hz-space-2); min-width: 0; }
/* Breadcrumbs wrap rather than scroll: a deep path is still readable on two
   lines, where a horizontal scroller hides the ancestors that make it
   navigable. */
.files__crumbs { display: flex; align-items: center; flex-wrap: wrap; gap: var(--hz-space-1); min-width: 0; }
.files__crumb {
  display: inline-flex;
  align-items: center;
  gap: var(--hz-space-1);
  padding: var(--hz-space-1) var(--hz-space-2);
  border: 0;
  border-radius: var(--hz-radius-sm);
  background: transparent;
  font: inherit;
  font-size: var(--hz-body-sm-size);
  color: var(--hz-fg-2);
  cursor: pointer;
}
.files__crumb:hover { background: var(--hz-cream); color: var(--hz-fg-1); }
.files__crumb .ms { font-size: 18px; }
/* The open directory is where you are, not somewhere to go. */
.files__crumb--current { color: var(--hz-fg-1); font-weight: 600; cursor: default; }
.files__crumb--current:hover { background: transparent; }
.files__sep { color: var(--hz-fg-3); }

/* New folder beside Upload, their errors stacking underneath rather than
   pushing the buttons around. */
.files__tools { display: flex; align-items: flex-start; gap: var(--hz-space-2); }
.files__upload { display: flex; flex-direction: column; align-items: flex-end; gap: var(--hz-space-2); }
.files__newfolder { display: flex; align-items: center; gap: var(--hz-space-2); flex-wrap: wrap; }
.files__newfolder input { min-width: 180px; }
/* The real input is never shown — the styled Button clicks it — but it must
   stay in the layout tree to be clickable, so it is hidden by size rather
   than by display:none. */
.files__file-input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }

.files__table { width: 100%; border-collapse: collapse; font-size: var(--hz-body-sm-size); }
.files__table th { text-align: left; padding: var(--hz-space-2) var(--hz-space-3); color: var(--hz-fg-2); font-weight: 600; }
.files__table td { padding: var(--hz-space-3); border-top: 1px solid var(--hz-line); vertical-align: middle; }
.files__name {
  display: inline-flex;
  align-items: center;
  gap: var(--hz-space-2);
  border: 0;
  background: transparent;
  padding: 0;
  font: inherit;
  font-size: var(--hz-body-sm-size);
  color: var(--hz-fg-1);
  text-align: left;
}
/* A directory is the one row that does something when clicked, so only it
   gets the affordance. */
.files__row--dir .files__name { cursor: pointer; }
.files__row--dir .files__name:hover { color: var(--hz-purple); }
.files__row--dir .files__name .ms { color: var(--hz-purple); }
.files__name .ms { font-size: 20px; color: var(--hz-fg-3); }
/* Sizes are read as a column of magnitudes, so they line up on the right with
   fixed-width digits. */
.files__size { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; color: var(--hz-fg-2); }
.files__when { white-space: nowrap; color: var(--hz-fg-2); }
/* Not a flex container: display:flex on a <td> takes the cell out of table
   layout, so the row's border stopped short of it and the column no longer
   lined up with its header. The buttons are inline-flex already. */
.files__actions { text-align: right; white-space: nowrap; }
@media (max-width: 599px) {
  .files__toolbar { flex-direction: column; align-items: stretch; }
  .files__tools { flex-wrap: wrap; }
  .files__upload { align-items: flex-start; }
  .files__newfolder { flex: 1 1 100%; }
  .files__newfolder input { min-width: 0; flex: 1 1 120px; }
  /* A folder has no size or date; its empty cells would otherwise print a bare label. */
  .files__row--dir .files__size, .files__row--dir .files__when { display: none; }
  /* The actions share the name's line instead of trailing on their own: the
     row wraps, the name takes what is left of line one, and the size and date
     are ordered after the actions so they start the following lines. */
  .table--stack tbody .files__row { flex-direction: row; flex-wrap: wrap; align-items: center; }
  .table--stack tbody .files__row td { flex: 0 0 100%; }
  .table--stack tbody .files__row td:first-child { flex: 1 1 0; min-width: 0; }
  .table--stack tbody .files__row .files__actions { flex: none; justify-content: flex-end; font-weight: 400; }
  .table--stack tbody .files__row .files__size, .table--stack tbody .files__row .files__when { order: 1; }
}
/* The download control is an anchor, not a button: the browser has to perform
   a real navigation to save the file. It still has to look like its
   neighbours. */
a.btn { text-decoration: none; }
.files__more { display: flex; justify-content: center; margin-top: var(--hz-space-4); }

/* ── Failed documents ─────────────────────────────────────────────────────
   Reached from the Connectors stat tile, and built from the same table and
   card furniture as the screen it opens from. */
/* The pressable tile: same box as an inert one, plus the affordance. Laid out
   as a grid so the chevron sits at the right edge without the label and value
   losing their own column. */
.stat-card--action {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  text-align: left;
  width: 100%;
  font: inherit;
  cursor: pointer;
}
.stat-card--action > :first-child { grid-column: 1; }
.stat-card--action > :nth-child(2) { grid-column: 1; }
.stat-card__chevron { grid-column: 2; grid-row: 1 / span 2; color: var(--hz-fg-3); }
.stat-card--action:hover { border-color: var(--hz-purple); }
.stat-card--action:hover .stat-card__chevron { color: var(--hz-purple); }

.failures__table { width: 100%; border-collapse: collapse; font-size: var(--hz-body-sm-size); }
.failures__table th { text-align: left; padding: var(--hz-space-2) var(--hz-space-3); color: var(--hz-fg-2); font-weight: 600; }
.failures__table td { padding: var(--hz-space-3); border-top: 1px solid var(--hz-line); vertical-align: middle; }
.failures__connector { white-space: nowrap; color: var(--hz-fg-2); }
/* The path is the long column and the one worth reading in full, so it takes
   the slack and wraps rather than being clipped. */
.failures__path { display: flex; align-items: center; gap: var(--hz-space-2); word-break: break-word; }
.failures__path .ms { font-size: 20px; color: var(--hz-fg-3); flex: none; }
.failures__reason { color: var(--hz-fg-1); }
.failures__size { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; color: var(--hz-fg-2); }
.failures__when { white-space: nowrap; color: var(--hz-fg-2); }
@media (max-width: 599px) {
  /* The path is what the reader scans for, so it leads the stacked row. */
  .table--stack tbody .failures__path { order: -1; justify-content: flex-start; }
}
.failures__empty {
  display: flex;
  align-items: center;
  gap: var(--hz-space-3);
  padding: var(--hz-space-6);
  color: var(--hz-fg-2);
}
.failures__empty .ms { color: var(--hz-success); }

/* Character sheet — the RPG-style creation controls shared by the Hire wizard
   and the agent's Character configuration panel. */
.segmented { display: flex; flex-wrap: wrap; gap: var(--hz-space-2); }
.segmented__opt {
  font-family: var(--hz-sans);
  font-size: var(--hz-body-sm-size);
  color: var(--hz-fg-1);
  background: var(--hz-paper);
  border: 1px solid var(--hz-line-strong);
  border-radius: var(--hz-radius-pill);
  padding: 6px 14px;
  cursor: pointer;
  transition: border-color .15s, background .15s, color .15s;
}
.segmented__opt:hover:not(:disabled) { border-color: var(--hz-purple); }
.segmented__opt--active { background: var(--hz-purple); border-color: var(--hz-purple); color: var(--hz-fg-on-dark); }
.segmented__opt:disabled { opacity: .6; cursor: default; }
.segmented--compact .segmented__opt { padding: 4px 12px; font-size: var(--hz-caption-size); }

.avatar-picker__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--hz-space-2);
}
.avatar-picker__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
  gap: var(--hz-space-2);
  max-height: 296px;
  overflow-y: auto;
  padding: var(--hz-space-1);
  border: 1px solid var(--hz-line);
  border-radius: var(--hz-radius-md);
  background: var(--hz-paper-2);
}
.avatar-tile {
  padding: 0;
  border: 3px solid transparent;
  border-radius: var(--hz-radius-pill);
  background: none;
  cursor: pointer;
  line-height: 0;
  transition: border-color .15s, transform .15s;
}
.avatar-tile img { width: 100%; height: auto; aspect-ratio: 1; border-radius: var(--hz-radius-pill); object-fit: cover; }
/* Hover-only motion: on touch a :hover scale would stick to the last tapped tile. */
@media (hover: hover) { .avatar-tile:hover { transform: scale(1.04); } }
.avatar-tile--selected { border-color: var(--hz-purple); box-shadow: 0 0 0 2px var(--hz-purple-soft); }

.trait__row { display: flex; align-items: center; gap: var(--hz-space-3); }
.trait__end { font-size: var(--hz-caption-size); color: var(--hz-fg-3); flex: none; min-width: 64px; }
.trait__end:last-child { text-align: right; }
.trait__range { flex: 1; accent-color: var(--hz-purple); min-width: 0; }
.trait__desc { color: var(--hz-fg-2); }
.traits { display: flex; flex-direction: column; gap: var(--hz-space-4); }
.traits__actions { display: flex; justify-content: flex-end; }

.counted__head { display: flex; justify-content: space-between; align-items: baseline; gap: var(--hz-space-2); }
.counted__count { color: var(--hz-fg-3); }
.field textarea.input { resize: vertical; min-height: 72px; font-family: var(--hz-sans); }

.character-summary { display: flex; flex-direction: column; gap: var(--hz-space-2); }
.character-summary__pips { display: grid; grid-template-columns: 1fr 1fr; gap: var(--hz-space-1) var(--hz-space-3); }
.pips { display: flex; align-items: center; justify-content: space-between; gap: var(--hz-space-2); font-size: var(--hz-caption-size); color: var(--hz-fg-2); }
.pips__dots { display: inline-flex; gap: 4px; }
.pips__dot { width: 8px; height: 8px; border-radius: var(--hz-radius-pill); background: var(--hz-line-strong); display: inline-block; }
.pips__dot--on { background: var(--hz-purple); }

.steckbrief__avatar--img { object-fit: cover; padding: 0; background: var(--hz-purple-soft); }
.steckbrief__stats {
  width: 100%;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--hz-space-3);
  margin-top: var(--hz-space-5);
  padding-top: var(--hz-space-4);
  border-top: 1px solid var(--hz-line);
}
.steckbrief__stat { display: flex; flex-direction: column; align-items: center; }
.steckbrief__stat-value { font-family: var(--hz-display); font-size: var(--hz-h3-size); line-height: 1; color: var(--hz-ink); }
.steckbrief__stat-label { font-size: var(--hz-micro-size); text-transform: uppercase; letter-spacing: 0.5px; color: var(--hz-fg-3); margin-top: var(--hz-space-1); }
/* The note telling the customer the rest is set later. It closes the sheet, so
   it sits apart from the stats above it and reads quieter than they do. */
.steckbrief__note { color: var(--hz-fg-3); margin: var(--hz-space-4) 0 0; text-align: center; }

/* Small screens: the wizard is one column and the Steckbrief collapses to a
   summary bar above the form — avatar, live name, tier badge, role on a second
   line. The form is the task; a full card above it would push the first
   field off a phone's screen. Kept after every steckbrief rule so these win. */
@media (max-width: 899px) {
  .wizard { grid-template-columns: minmax(0, 1fr); gap: var(--hz-space-5); }
  .wizard__preview { order: -1; }
  .steckbrief {
    display: grid;
    grid-template-columns: 48px minmax(0, 1fr) auto;
    grid-template-areas: "avatar name badge" "avatar role badge";
    column-gap: var(--hz-space-3);
    row-gap: 2px;
    align-items: center;
    text-align: left;
    padding: var(--hz-space-3) var(--hz-space-4);
    border-radius: var(--hz-radius-lg);
    box-shadow: var(--hz-shadow-md);
  }
  .steckbrief__avatar { grid-area: avatar; width: 48px; height: 48px; border-width: 3px; margin: 0; font-size: var(--hz-body-lg-size); }
  .steckbrief__name { grid-area: name; font-size: var(--hz-body-lg-size); }
  .steckbrief__role { grid-area: role; margin: 0; }
  .steckbrief .badge { grid-area: badge; margin: 0; }
  .steckbrief__sections, .steckbrief__stats, .steckbrief__note { display: none; }
}
@media (max-width: 599px) {
  .stepper__actions { flex-wrap: wrap; }
  .stepper__actions .btn { flex: 1 1 auto; justify-content: center; }
  .wizard__catalog-search { max-width: none; }
}

.employee-card__avatar--img { object-fit: cover; }
.detail-header__bio { color: var(--hz-fg-2); margin: var(--hz-space-2) 0 0; }
/* The name leads both panels, so it carries the gap from the card's intro and
   what follows it sits closer. */
.character-name, .detail-settings__form { margin-top: var(--hz-space-5); }
.character-editor { margin-top: var(--hz-space-4); }
.character-actions { flex-direction: row; align-items: center; gap: var(--hz-space-3); flex-wrap: wrap; }

/* Settings: what a saved edit says about reaching the agent, set off from the
   form above it so it reads as the consequence of the Save, not another field. */
.detail-settings__saved {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--hz-space-2);
  margin-top: var(--hz-space-4);
  padding-top: var(--hz-space-4);
  border-top: 1px solid var(--hz-line);
}
.detail-settings__saved p { margin: 0; }

/* Settings review: the dialog between Save and the save. Each change is the
   field's label over its old and new value, so an admin reads what the form
   said rather than variable names; the warnings below wear the same warm
   warning frame the Connectors screen uses for a consequence to accept. */
.settings-review__changes { list-style: none; margin: var(--hz-space-4) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--hz-space-3); }
.settings-review__change { display: flex; flex-direction: column; gap: 2px; font-size: var(--hz-body-sm-size); }
.settings-review__label { font-weight: 600; color: var(--hz-fg-1); }
.settings-review__values { display: flex; align-items: center; flex-wrap: wrap; gap: var(--hz-space-2); color: var(--hz-fg-1); overflow-wrap: anywhere; }
.settings-review__values .ms { font-size: 16px; color: var(--hz-fg-3); flex: none; }
.settings-review__from { color: var(--hz-fg-2); text-decoration: line-through; }
.settings-review__warnings { list-style: none; margin: var(--hz-space-4) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--hz-space-2); }
.settings-review__warning { display: flex; gap: var(--hz-space-2); align-items: flex-start; padding: var(--hz-space-2) var(--hz-space-3); border-radius: var(--hz-radius-sm); background: var(--hz-cream); border: 1px solid var(--hz-warning); color: var(--hz-fg-1); font-size: var(--hz-body-sm-size); }
.settings-review__warning .ms { color: var(--hz-warning); flex: none; margin-top: 1px; }

@media (max-width: 599px) {
  .avatar-picker__grid { grid-template-columns: repeat(auto-fill, minmax(64px, 1fr)); }
  .trait__end { min-width: 48px; }
  .character-summary__pips { grid-template-columns: 1fr; }
}

/* ============================================================
   Touch — tap targets and input sizing on screens without a mouse.
   ============================================================ */
@media (max-width: 899px) {
  .btn--icon { min-width: 44px; min-height: 44px; justify-content: center; }
  .tab { min-height: 44px; }
  .view-toggle__btn, .files__crumb, .segmented__opt { min-height: 40px; }
  /* iOS zooms into any control under 16px; the unclassed inputs are the ones at risk. */
  input, select, textarea { font-size: max(1em, 16px); }
}

/* ---------------------------------------------------------------------------
   Traces tab. A diary, not a log: rows grouped by day, one row per turn, and
   the detail a flat list of events beneath the row it belongs to. The filter
   bar wraps freely so adding a control never needs a layout change. */
.traces-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--hz-space-3) var(--hz-space-4);
  margin-bottom: var(--hz-space-5);
}
.traces-filter { display: flex; flex-direction: column; gap: var(--hz-space-1); min-width: 0; }
.traces-filter__label { font-size: var(--hz-micro-size); font-weight: 700; letter-spacing: 0.5px; text-transform: uppercase; color: var(--hz-fg-3); }
.traces-filter__control { padding: var(--hz-space-2) var(--hz-space-3); font-size: var(--hz-caption-size); }
.traces-filter--check { flex-direction: row; align-items: center; gap: var(--hz-space-2); padding-bottom: var(--hz-space-2);
  font-size: var(--hz-caption-size); color: var(--hz-fg-2); cursor: pointer; }
.traces-filter--check input { accent-color: var(--hz-purple); width: 16px; height: 16px; }
.traces-filter--search { flex-direction: row; align-items: center; gap: var(--hz-space-2); flex: 1 1 200px; }
.traces-filter--search .ms { color: var(--hz-fg-3); font-size: 20px; }
.traces-filter--search .input { flex: 1; }

.traces__empty, .trace-detail__empty { color: var(--hz-fg-3); font-size: var(--hz-caption-size); padding: var(--hz-space-4) 0; }
.traces__day + .traces__day { margin-top: var(--hz-space-5); }
.traces__day-label {
  margin: 0 0 var(--hz-space-2);
  font-family: var(--hz-sans);
  font-size: var(--hz-micro-size);
  font-weight: 700;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--hz-fg-3);
}
.traces__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--hz-space-2); }
.traces__more { display: flex; justify-content: center; margin-top: var(--hz-space-5); }

.trace { background: var(--hz-paper); border: 1px solid var(--hz-line); border-radius: var(--hz-radius-md); overflow: hidden; }
.trace--error { border-color: color-mix(in srgb, var(--hz-danger) 35%, var(--hz-line)); }
.trace--open { border-color: var(--hz-purple-soft); box-shadow: var(--hz-shadow-sm); border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
.trace__row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto auto;
  align-items: start;
  gap: var(--hz-space-3);
  width: 100%;
  padding: var(--hz-space-3) var(--hz-space-4);
  background: transparent;
  border: 0;
  text-align: left;
  font-family: var(--hz-sans);
  color: var(--hz-fg-1);
  cursor: pointer;
}
.trace__row:hover { background: var(--hz-paper-2); }
.trace__time { font-size: var(--hz-caption-size); color: var(--hz-fg-3); padding-top: 2px; }
.trace__main { display: flex; flex-direction: column; gap: var(--hz-space-1); min-width: 0; }
.trace__conv { display: inline-flex; align-items: center; gap: var(--hz-space-1); font-size: var(--hz-micro-size); font-weight: 600; color: var(--hz-purple); }
.trace__conv .ms { font-size: 16px; }
.trace__preview { font-size: var(--hz-body-sm-size); color: var(--hz-fg-1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.trace--open .trace__preview { white-space: normal; }
.trace__meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--hz-space-2) var(--hz-space-3); margin-top: var(--hz-space-1); }
.trace__chip { display: inline-flex; align-items: center; gap: var(--hz-space-1); font-size: var(--hz-micro-size); color: var(--hz-fg-3); }
.trace__chip .ms { font-size: 15px; }
.trace__chip-detail { color: var(--hz-fg-4); }
.trace__status { width: 10px; height: 10px; border-radius: 50%; margin-top: 6px; background: var(--hz-success); }
.trace__status--error { background: var(--hz-danger); }
.trace__chevron { color: var(--hz-fg-4); }

.trace-detail-slot { margin-top: calc(-1 * var(--hz-space-2)); }
.trace-detail {
  background: var(--hz-cream);
  border: 1px solid var(--hz-purple-soft);
  border-top: 0;
  border-radius: 0 0 var(--hz-radius-md) var(--hz-radius-md);
  padding: var(--hz-space-4) var(--hz-space-4) var(--hz-space-5);
}
.trace-detail__label { font-size: var(--hz-micro-size); font-weight: 700; letter-spacing: 0.5px; text-transform: uppercase; color: var(--hz-fg-3); }
.trace-detail__question p { margin: var(--hz-space-1) 0 0; font-size: var(--hz-body-sm-size); color: var(--hz-fg-1); white-space: pre-wrap; }
.trace-events { list-style: none; margin: var(--hz-space-4) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--hz-space-2); }
.trace-event {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr);
  gap: var(--hz-space-3);
  align-items: start;
  background: var(--hz-paper);
  border-radius: var(--hz-radius-sm);
  padding: var(--hz-space-2) var(--hz-space-3);
}
.trace-event--failed { box-shadow: inset 3px 0 0 var(--hz-danger); }
.trace-event__time { font-size: var(--hz-micro-size); color: var(--hz-fg-3); padding-top: 3px; }
.trace-event__icon .ms { font-size: 18px; color: var(--hz-fg-3); }
.trace-event--tool .trace-event__icon .ms { color: var(--hz-purple); }
.trace-event--error .trace-event__icon .ms, .trace-event--failed .trace-event__icon .ms { color: var(--hz-danger); }
.trace-event__body { display: flex; flex-direction: column; gap: var(--hz-space-1); min-width: 0; }
.trace-event__head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--hz-space-2) var(--hz-space-3); font-size: var(--hz-caption-size); }
.trace-event__kind { font-weight: 700; color: var(--hz-fg-2); }
.trace-event__name { font-family: var(--hz-mono); font-size: var(--hz-micro-size); color: var(--hz-fg-1); word-break: break-all; }
.trace-event__sub { font-size: var(--hz-micro-size); color: var(--hz-fg-3); }
.trace-event__json summary { font-size: var(--hz-micro-size); color: var(--hz-purple); cursor: pointer; font-weight: 600; }
.trace-event__json pre {
  margin: var(--hz-space-1) 0 0;
  padding: var(--hz-space-2) var(--hz-space-3);
  background: var(--hz-paper-2);
  border: 1px solid var(--hz-line);
  border-radius: var(--hz-radius-xs);
  font-size: var(--hz-micro-size);
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 320px;
  overflow: auto;
}
.trace-event__reply { font-size: var(--hz-body-sm-size); color: var(--hz-fg-1); }
.trace-event__reply p { margin: 0 0 var(--hz-space-2); }
.trace-event__reply p:last-child { margin-bottom: 0; }
@media (max-width: 599px) {
  .trace__row { grid-template-columns: minmax(0, 1fr) auto auto; }
  .trace__time { grid-column: 1 / -1; padding-top: 0; }
  .trace-event { grid-template-columns: auto minmax(0, 1fr); }
  .trace-event__time { grid-column: 1 / -1; }
}
