/*
 * The app host (app/views/layouts/dashboard.html.erb): the customer dashboard.
 * The header (the brand plate and the account menu), the sections nav (a sidebar from
 * 900px, a Menu top bar under it), main, cards and table wraps, on the tokens of
 * tokens.css, so light and dark follow the device. Every rule is scoped under
 * body.dashboard, so the public, docs and activate pages never see one. Touch targets
 * are --button-height (48px). No script: the two disclosures are <details> elements.
 */

body.dashboard {
  display: flex;
  flex-direction: column;
}

body.dashboard > main {
  flex: 1 0 auto;
  width: 100%;
  max-width: 1120px;
  margin: 0 auto;
  padding: var(--space-4);
  padding-left: max(var(--space-4), env(safe-area-inset-left));
  padding-right: max(var(--space-4), env(safe-area-inset-right));
  padding-bottom: max(var(--space-4), env(safe-area-inset-bottom));
}

/* Header: the brand on the left (the secretag.co logo on its plate: .brand and .brand-logo in components.css, 56px
   tall and 72px from 900px), the account menu on the right. It is the positioning box of the account panel. */
body.dashboard .dashboard-header {
  position: relative;
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-1) var(--space-4);
  padding-top: max(var(--space-1), env(safe-area-inset-top));
  padding-left: max(var(--space-4), env(safe-area-inset-left));
  padding-right: max(var(--space-4), env(safe-area-inset-right));
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
}

/* The logo never shrinks: the plate is the logo's width at --logo-height (56px * 336 / 120 = 156.8px) plus the plate's
   two --space-2 paddings, 172.8px under 900px. The account menu takes what is left of the row and gives way. */
body.dashboard .dashboard-header .brand {
  flex: none;
}

/* The account menu: the signed-in email is the summary's label (a long address is cut with an ellipsis inside its own
   span, the caret kept at the right edge); its panel (Log out) drops down under the header's right edge. At 375px the
   menu holds 375 - 2 * 16 (the header's side paddings) - 172.8 (the plate) - 12 (the gap) = 158.2px. */
body.dashboard .dashboard-account {
  flex: 0 1 auto;
  min-width: 0;
}

body.dashboard .dashboard-account-toggle,
body.dashboard .dashboard-menu-toggle {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--button-height);
  padding: 0 var(--space-3);
  border: 1px solid var(--border-input);
  border-radius: var(--radius-input);
  background: var(--bg);
  color: var(--text);
  font-weight: 700;
  list-style: none;
  cursor: pointer;
}

body.dashboard .dashboard-account-toggle::-webkit-details-marker,
body.dashboard .dashboard-menu-toggle::-webkit-details-marker {
  display: none;
}

/* A drawn caret (borders in currentColor, so no icon file) that turns when the disclosure opens. */
body.dashboard .dashboard-account-toggle::after,
body.dashboard .dashboard-menu-toggle::after {
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  margin-top: -3px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
}

body.dashboard .dashboard-account[open] > .dashboard-account-toggle::after,
body.dashboard .dashboard-menu[open] > .dashboard-menu-toggle::after {
  margin-top: 3px;
  transform: rotate(-135deg);
}

body.dashboard .dashboard-account[open] > .dashboard-account-toggle,
body.dashboard .dashboard-menu[open] > .dashboard-menu-toggle {
  background: var(--surface);
}

/* The summary stays a flex row no wider than the menu's share of the header (max-width 100% of .dashboard-account),
   so the email span shrinks and draws its ellipsis while the caret (flex: none) stays whole after it. */
body.dashboard .dashboard-account-toggle {
  min-width: 0;
  max-width: 100%;
  font-size: var(--text-sm);
  font-weight: 400;
}

body.dashboard .dashboard-account-email {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

body.dashboard .dashboard-account-panel {
  position: absolute;
  top: 100%;
  right: max(var(--space-4), env(safe-area-inset-right));
  z-index: 5;
  min-width: 200px;
  margin-top: var(--space-1);
  padding: var(--space-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-input);
  background: var(--bg);
  color: var(--text);
}

body.dashboard .dashboard-log-out {
  margin: 0;
}

/* The account menu's pages (Your Profile, Settings, Security, and the admin pages): 48px links above Log out, a rule
   between them; the current page is marked as the sections nav marks it, by more than color. */
body.dashboard .dashboard-account-list {
  margin: 0 0 var(--space-2);
  padding: 0 0 var(--space-2);
  border-bottom: 1px solid var(--border);
  list-style: none;
}

body.dashboard .dashboard-account-link {
  display: flex;
  align-items: center;
  min-height: var(--button-height);
  padding: 0 var(--space-3);
  border-radius: var(--radius-input);
  color: var(--text);
  text-decoration: none;
  white-space: nowrap;
}

@media (hover: hover) {
  body.dashboard .dashboard-account-link:hover {
    text-decoration: underline;
  }
}

body.dashboard .dashboard-account-link[aria-current="page"] {
  background: var(--surface);
  font-weight: 700;
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 6px;
}

/* Settings: the read-only card stands apart from the form's Save button. */
body.dashboard .dashboard-settings-fixed {
  margin-top: var(--space-8);
}

/* Security: the session in use, named in words beside its device. */
body.dashboard .dashboard-this-device {
  display: inline-block;
  margin-left: var(--space-2);
  padding: 0 var(--space-2);
  border: 1px solid var(--border);
  border-left: 4px solid var(--accent);
  border-radius: var(--radius-input);
  background: var(--bg);
  font-size: var(--text-sm);
  font-weight: 700;
}

/* The header search (a linked account's pages): under 900px the header becomes a grid whose first row is the brand
   and the account menu exactly as above (the menu's track is what the flex row left it: minmax(0, 1fr), the menu at
   its right edge and never wider than the track, so a long email keeps its ellipsis) and whose second row is the
   search across the whole width. From 900px the search sits between them on one row, at most 32rem wide. The box and
   its submit are 48px tall. */
body.dashboard .dashboard-header:has(> .dashboard-search) {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-areas:
    "brand account"
    "search search";
  row-gap: var(--space-2);
  padding-bottom: var(--space-2);
}

body.dashboard .dashboard-header:has(> .dashboard-search) > .brand {
  grid-area: brand;
}

body.dashboard .dashboard-header:has(> .dashboard-search) > .dashboard-account {
  grid-area: account;
  justify-self: end;
  max-width: 100%;
}

body.dashboard .dashboard-search {
  grid-area: search;
  display: flex;
  gap: var(--space-2);
  min-width: 0;
  margin: 0;
}

body.dashboard .dashboard-search .dashboard-search-input {
  flex: 1 1 auto;
  min-width: 0;
  min-height: var(--button-height);
  margin: 0;
}

body.dashboard .dashboard-search .dashboard-search-button {
  flex: none;
  min-height: var(--button-height);
  margin: 0;
}

@media (min-width: 900px) {
  body.dashboard .dashboard-header:has(> .dashboard-search) {
    grid-template-columns: auto minmax(14rem, 1fr) minmax(0, max-content);
    grid-template-areas: "brand search account";
    padding-bottom: var(--space-1);
  }

  body.dashboard .dashboard-search {
    justify-self: center;
    width: 100%;
    max-width: 32rem;
  }
}

/* A button that reads as a link (Log out): a form control, so it stays a button. */
body.dashboard .dashboard-link-button {
  display: flex;
  align-items: center;
  width: 100%;
  min-height: var(--button-height);
  margin: 0;
  padding: 0 var(--space-3);
  border: 0;
  border-radius: var(--radius-input);
  background: none;
  color: var(--accent);
  font-size: var(--text-md);
  text-align: left;
  text-decoration: underline;
  cursor: pointer;
}

body.dashboard .dashboard-link-button:active {
  color: var(--accent-pressed);
}

/* The sections nav. Under 900px: a top bar under the header with the Menu disclosure; the list opens in the bar. */
body.dashboard .dashboard-sections {
  padding: var(--space-2) var(--space-4);
  padding-left: max(var(--space-4), env(safe-area-inset-left));
  padding-right: max(var(--space-4), env(safe-area-inset-right));
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}

body.dashboard .dashboard-menu-toggle {
  display: inline-flex;
}

body.dashboard .dashboard-section-list {
  margin: 0;
  padding: var(--space-2) 0 0;
  list-style: none;
}

body.dashboard .dashboard-section-link {
  display: flex;
  align-items: center;
  min-height: var(--button-height);
  padding: 0 var(--space-3);
  border-radius: var(--radius-input);
  color: var(--text);
  text-decoration: none;
}

@media (hover: hover) {
  body.dashboard .dashboard-section-link:hover {
    text-decoration: underline;
  }
}

/* "Other apps": a rule and a small muted caption above the second list (Activate and Docs, the two links that leave
   this host), which follows the caption with no gap of its own. */
body.dashboard .dashboard-section-caption {
  margin: var(--space-3) 0 0;
  padding: var(--space-3) var(--space-3) var(--space-1);
  border-top: 1px solid var(--border);
  color: var(--text-muted);
  font-size: var(--text-sm);
}

body.dashboard .dashboard-section-caption + .dashboard-section-list {
  padding-top: 0;
}

/* The current section is marked by more than color: bold, underlined and on the page ground. */
body.dashboard .dashboard-section-link[aria-current="page"] {
  background: var(--bg);
  font-weight: 700;
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 6px;
}

/* From 900px, signed in: two columns, the header across the top, the sections nav as a 240px left sidebar and main to
   its right. The skip link is the grid's first item; positioned off screen it takes no track, and shown on focus it
   spans the top row. Signed out (no nav) the page stays the one column above. */
@media (min-width: 900px) {
  body.dashboard:has(> .dashboard-sections) {
    display: grid;
    grid-template-columns: 240px minmax(0, 1fr);
    grid-template-rows: auto auto 1fr;
  }

  body.dashboard:has(> .dashboard-sections) > .skip-link {
    grid-column: 1 / -1;
    grid-row: 1;
  }

  body.dashboard:has(> .dashboard-sections) > .dashboard-header {
    grid-column: 1 / -1;
    grid-row: 2;
  }

  body.dashboard > .dashboard-sections {
    grid-column: 1;
    grid-row: 3;
    padding: var(--space-4) var(--space-3);
    padding-left: max(var(--space-3), env(safe-area-inset-left));
    border-right: 1px solid var(--border);
    border-bottom: 0;
  }

  body.dashboard:has(> .dashboard-sections) > main {
    grid-column: 2;
    grid-row: 3;
    margin: 0;
    padding: var(--space-6);
    padding-right: max(var(--space-6), env(safe-area-inset-right));
  }

  body.dashboard .dashboard-section-list {
    padding-top: 0;
  }

  /* The Menu disclosure stands open as the sidebar: its summary is hidden and its content shown, by CSS on the details
     element alone. A browser without ::details-content keeps the Menu summary, so the list is still reachable. */
  @supports selector(::details-content) {
    body.dashboard .dashboard-menu > .dashboard-menu-toggle {
      display: none;
    }

    body.dashboard .dashboard-menu::details-content {
      content-visibility: visible;
    }
  }
}

body.dashboard h1 {
  margin: var(--space-1) 0 var(--space-3);
  font-size: var(--text-xl);
}

body.dashboard h2 {
  margin: 0 0 var(--space-2);
  font-size: var(--text-lg);
}

/* Cards: a framed block on the surface color. */
body.dashboard .card {
  min-width: 0;
  margin-bottom: var(--space-4);
  padding: var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--surface);
  color: var(--text);
}

body.dashboard .card > :first-child {
  margin-top: 0;
}

body.dashboard .card > :last-child {
  margin-bottom: 0;
}

body.dashboard .actions {
  margin-top: var(--space-4);
}

body.dashboard .dashboard-organization {
  font-weight: 700;
  overflow-wrap: anywhere;
}

/* Tables (Tags, Shipments and later pages): a wide table scrolls sideways inside its wrap, never the page, and its first column stays in
   place while the rest scrolls. */
body.dashboard .table-wrap {
  max-width: 100%;
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--surface);
}

/* Separate borders with no spacing, so each border belongs to its cell: under border-collapse the held first column's
   right edge stays with the table grid and scrolls away (measured 2026-10-29, the F2 screenshot). */
body.dashboard .table-wrap table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
}

body.dashboard .table-wrap th,
body.dashboard .table-wrap td {
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--border);
  text-align: left;
  white-space: nowrap;
}

/* A numeric or money column (plan tender-pondering-raccoon D5): its header and cells right-aligned with tabular figures,
   beating the wrap's left alignment on specificity. */
body.dashboard .table-wrap :is(th, td).dashboard-cell-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

body.dashboard .table-wrap th:first-child,
body.dashboard .table-wrap td:first-child {
  position: sticky;
  left: 0;
  z-index: 1;
  border-right: 1px solid var(--border);
  background: var(--surface);
}

/* Secondary text. */
body.dashboard .muted {
  color: var(--text-muted);
  font-size: var(--text-sm);
}

/* The as-of line (dashboard/_as_of): when each kind's data is from, and Refresh (.button, 48px). */
body.dashboard .dashboard-as-of {
  margin-bottom: var(--space-4);
  color: var(--text);
  font-size: var(--text-sm);
}

body.dashboard .dashboard-as-of ul {
  margin: 0 0 var(--space-3);
  padding: 0;
  list-style: none;
}

body.dashboard .dashboard-as-of p {
  margin: 0 0 var(--space-2);
}

body.dashboard .dashboard-as-of form {
  margin: 0 0 var(--space-2);
}

/* One line when the kinds agree (plan tender-pondering-raccoon, D2): the line, then Refresh beside it; the banner
   and the gate's reason keep a row of their own. */
body.dashboard .dashboard-as-of-one {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
}

body.dashboard .dashboard-as-of-one > p {
  flex-basis: 100%;
  margin: 0;
}

body.dashboard .dashboard-as-of-one > ul,
body.dashboard .dashboard-as-of-one > form {
  margin: 0;
}

/* The staleness banner: marked by its border and its words, never by color alone. */
body.dashboard .dashboard-banner {
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border);
  border-left: 4px solid var(--warning);
  border-radius: var(--radius-input);
  background: var(--surface);
  color: var(--text);
  font-weight: 700;
}

/* Lists (Tags, Shipments): the filter form, the sentence that says what the list is filtered by, the table and
   Previous and Next. Every control is 48px (--button-height). */
body.dashboard .dashboard-filters {
  display: grid;
  gap: var(--space-3);
  align-items: end;
  margin-bottom: var(--space-4);
}

body.dashboard .dashboard-filters .field + .field {
  margin-top: 0;
}

body.dashboard .dashboard-filters .field-input {
  min-height: var(--button-height);
}

body.dashboard .dashboard-filter-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* A row of buttons under a sentence or a list keeps --space-3 from the text: base.css sets every p margin to 0. */
body.dashboard :is(p, ul, dl) + .dashboard-filter-actions {
  margin-top: var(--space-3);
}

@media (min-width: 900px) {
  body.dashboard .dashboard-filters {
    grid-template-columns: minmax(0, 2fr) repeat(auto-fit, minmax(10rem, 1fr));
  }
}

/* Home's service level filter (plan tender-pondering-raccoon D3): one row at every width, at most 32rem, the select
   taking what the buttons leave; after the 900px block so the row wins there too. */
body.dashboard .dashboard-filters.dashboard-filters-inline {
  display: flex;
  align-items: flex-end;
  gap: var(--space-2);
  max-width: 32rem;
}

body.dashboard .dashboard-filters-inline .field {
  flex: 1 1 auto;
  min-width: 0;
}

body.dashboard .dashboard-filters-inline .dashboard-filter-actions {
  flex: none;
  flex-wrap: nowrap;
}

body.dashboard .dashboard-list-summary {
  margin: 0 0 var(--space-3);
  color: var(--text);
  overflow-wrap: anywhere;
}

body.dashboard .dashboard-table th,
body.dashboard .dashboard-table td {
  vertical-align: middle;
}

body.dashboard .dashboard-table thead th {
  font-size: var(--text-sm);
}

body.dashboard .dashboard-table tbody th {
  font-weight: 400;
}

/* A row's link (the first column) is a 48px target. */
body.dashboard .dashboard-row-link {
  display: inline-flex;
  align-items: center;
  min-height: var(--button-height);
  font-weight: 700;
}

body.dashboard .dashboard-cell-note {
  display: block;
  color: var(--text-muted);
  font-size: var(--text-sm);
}

/* A long address wraps in its own column instead of making every row one line wide. */
body.dashboard .dashboard-table .dashboard-cell-wide {
  min-width: 14rem;
  white-space: normal;
  overflow-wrap: anywhere;
}

/* A table with two wide cells (Users and Teams' Name and Email, Integrations' Label and Endpoint URL) holds its first
   one to 9rem from 900px, so at 1280 the table fits its card (Users: 1,026px of columns in a 956px wrap at 14rem, 80px
   less at 9rem, measured 2026-10-29). Under 900px the held first column's own rule below governs. */
@media (min-width: 900px) {
  body.dashboard .dashboard-table .dashboard-cell-wide.dashboard-cell-lead {
    min-width: 9rem;
  }

  /* A time (Users' Joined and Last sign-in, Integrations' Created) wraps before its zone name from 900px, so at 1280 a
     signed-in user's row fits (Users: 1,003px of columns in a 956px wrap with "Oct 29, 5:12 pm Chicago" on one line,
     measured 2026-10-30). 9.5rem of border box holds the widest date and time, "Dec 31, 12:59 pm" (126px plus 24px of
     padding), on one line; the two time columns at 152px leave Users 952px of columns in its 956px wrap. */
  body.dashboard .dashboard-table .dashboard-cell-time {
    min-width: 9.5rem;
    white-space: normal;
  }
}

/* On a phone the first column (held in place by the sticky rule above) stays narrow enough to leave room for the
   columns that scroll beside it, and a long first value wraps inside it, never narrower than 7rem. */
@media (max-width: 899.98px) {
  body.dashboard .table-wrap th:first-child,
  body.dashboard .table-wrap td:first-child {
    min-width: 7rem;
    max-width: 10rem;
    white-space: normal;
    overflow-wrap: anywhere;
  }
}

body.dashboard .dashboard-pager {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-4);
}

body.dashboard .dashboard-pager-position {
  margin: 0;
}

/* Count cards: the label, the figure and the formula it is counted by. */
body.dashboard .dashboard-counts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 9rem), 1fr));
  gap: var(--space-3);
  margin: 0 0 var(--space-4);
  padding: 0;
  list-style: none;
}

body.dashboard .dashboard-count {
  min-width: 0;
  padding: var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--surface);
}

body.dashboard .dashboard-count p {
  margin: 0;
}

body.dashboard .dashboard-count-label {
  font-weight: 700;
}

body.dashboard .dashboard-count-value {
  font-size: var(--text-2xl);
  font-weight: 700;
}

/* Detail pages: the way back, a heading that may hold a long id, and label and value pairs. */
body.dashboard .dashboard-back {
  margin: 0;
}

body.dashboard .dashboard-back a {
  display: inline-flex;
  align-items: center;
  min-height: var(--button-height);
}

body.dashboard .dashboard-title-wrap {
  overflow-wrap: anywhere;
}

body.dashboard h3 {
  margin: 0 0 var(--space-2);
  font-size: var(--text-md);
  overflow-wrap: anywhere;
}

body.dashboard h4 {
  margin: var(--space-3) 0 var(--space-2);
  font-size: var(--text-sm);
}

body.dashboard .dashboard-details {
  display: grid;
  gap: var(--space-2);
  margin: 0;
}

body.dashboard .dashboard-details > div {
  display: grid;
  gap: var(--space-1);
}

@media (min-width: 900px) {
  body.dashboard .dashboard-details > div {
    grid-template-columns: 12rem minmax(0, 1fr);
    gap: var(--space-3);
  }
}

body.dashboard .dashboard-details dt {
  color: var(--text-muted);
  font-size: var(--text-sm);
}

body.dashboard .dashboard-details dd {
  margin: 0;
  overflow-wrap: anywhere;
}

body.dashboard .dashboard-package + .dashboard-package {
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border);
}

body.dashboard .dashboard-plain-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

body.dashboard .dashboard-plain-list > li + li {
  margin-top: var(--space-2);
}

/* Edit forms: one column at the reading width. */
body.dashboard .dashboard-form {
  max-width: 40rem;
  margin-top: var(--space-4);
}

body.dashboard .dashboard-form .field-hint {
  margin: 0 0 var(--space-4);
}

/* Home's claim card (plan tender-pondering-raccoon D3): from 600px the label, the field and Add on one row (the field's
   wrapper drops out of the box tree, so its label, input and hint are the grid's items) with the hint on row 2 under
   the field; stacked under 600px as every other form. */
@media (min-width: 600px) {
  body.dashboard .dashboard-claim-form {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    column-gap: var(--space-3);
    row-gap: var(--space-1);
    align-items: center;
  }

  body.dashboard .dashboard-claim-form .field {
    display: contents;
  }

  body.dashboard .dashboard-claim-form .field-label {
    grid-row: 1;
    grid-column: 1;
    margin: 0;
  }

  body.dashboard .dashboard-claim-form .field-input {
    grid-row: 1;
    grid-column: 2;
  }

  body.dashboard .dashboard-claim-form .field-hint {
    grid-row: 2;
    grid-column: 2 / -1;
    margin: 0;
  }

  body.dashboard .dashboard-claim-form .form-actions {
    grid-row: 1;
    grid-column: 3;
    margin: 0;
  }
}

/* Home's claim card: the link to the tag the last claim added, set apart from the Add button. */
body.dashboard .dashboard-claimed {
  margin-top: var(--space-4);
}

/* Home (dashboard/home/show): the Live now badge of In Transit (marked by its border and its words, never by color
   alone), the three Fulfillment pipeline figures side by side from 900px, the report card's grade cell, Top
   destinations as a ranked list with each count at the row's end, and the formula lines under a card's list. */
body.dashboard .dashboard-count .dashboard-live {
  display: inline-block;
  margin: var(--space-1) 0;
  padding: 0 var(--space-2);
  border: 1px solid var(--border);
  border-left: 4px solid var(--success);
  border-radius: var(--radius-input);
  background: var(--bg);
  color: var(--text);
  font-size: var(--text-sm);
  font-weight: 700;
}

body.dashboard .dashboard-pipeline {
  margin-bottom: 0;
}

@media (min-width: 900px) {
  body.dashboard .dashboard-pipeline {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

body.dashboard .dashboard-table .dashboard-grade {
  font-size: var(--text-lg);
  font-weight: 700;
  text-align: center;
}

body.dashboard .dashboard-destinations {
  margin: 0;
  padding: 0;
  list-style: none;
}

body.dashboard .dashboard-destinations > li {
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--border);
  overflow-wrap: anywhere;
}

body.dashboard .dashboard-destination-count {
  flex: none;
  font-weight: 700;
}

body.dashboard .dashboard-formula {
  margin: var(--space-3) 0 0;
  color: var(--text-muted);
  font-size: var(--text-sm);
}

/* Map View and the tag's Journey card (dashboard/map): the generated outline nested at the map's viewBox, the dots as
   links painted by their state class, the selected dot's ring and the journey polyline. Every paint is a class on the
   tokens, never an attribute or an inline style. The map takes its container's full width (a phone gets all of it)
   and keeps the viewBox's 960 by 600 shape. The state chips are 48px buttons that wrap. */
body.dashboard .dashboard-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0 0 var(--space-4);
  padding: 0;
  list-style: none;
}

body.dashboard .dashboard-chip[aria-current="true"] {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 2px var(--accent);
  font-weight: 700;
}

body.dashboard .dashboard-map-svg {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 960 / 600;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius-input);
  background: var(--surface);
}

body.dashboard .dashboard-map-small {
  max-width: 40rem;
}

body.dashboard .map-outline {
  overflow: hidden;
}

body.dashboard .map-context {
  fill: var(--bg);
  stroke: var(--border);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

body.dashboard .map-land {
  fill: var(--bg);
  stroke: var(--text-muted);
  stroke-width: 1.5;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

body.dashboard .map-journey {
  fill: none;
  stroke: var(--accent);
  stroke-width: 3;
  stroke-linejoin: round;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

body.dashboard .map-dot {
  fill: var(--warning);
  stroke: var(--bg);
  stroke-width: 2;
}

body.dashboard .map-dot-awaiting_first_ping,
body.dashboard .map-dot-at_origin {
  fill: var(--text-muted);
}

body.dashboard .map-dot-in_transit,
body.dashboard .map-dot-approaching {
  fill: var(--accent);
}

body.dashboard .map-dot-delivered,
body.dashboard .map-dot-delivery_verification,
body.dashboard .map-dot-completed {
  fill: var(--success);
}

body.dashboard .map-dot-disputed_in_transit {
  fill: var(--danger);
}

body.dashboard .map-selected {
  fill: none;
  stroke: var(--text);
  stroke-width: 3;
}

body.dashboard .map-dot-link:focus {
  outline: none;
}

body.dashboard .map-dot-link:focus-visible .map-dot {
  stroke: var(--focus-ring);
  stroke-width: 5;
}

body.dashboard .dashboard-journey-summary {
  margin: var(--space-3) 0 0;
  overflow-wrap: anywhere;
}

/* Alerts (dashboard/alerts): the count line with Mark all read beside it from 600px, the Unread only checkbox as a
   48px label, and the list as cards. Each alert's severity chip says its severity in words with a colored left edge
   (never color alone); an unread alert carries an accent edge of its own. Under 600px the Mark read button sits
   under the alert, full width. */
body.dashboard .dashboard-alert-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

body.dashboard .dashboard-alert-count {
  margin: 0;
  font-size: var(--text-lg);
  font-weight: 700;
}

body.dashboard .dashboard-mark-all {
  margin: 0;
}

body.dashboard .dashboard-check {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--button-height);
  cursor: pointer;
}

body.dashboard .dashboard-check input {
  width: 1.25rem;
  height: 1.25rem;
  margin: 0;
  accent-color: var(--accent);
}

body.dashboard .dashboard-alerts {
  margin: 0 0 var(--space-4);
  padding: 0;
  list-style: none;
}

body.dashboard .dashboard-alert {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  background: var(--surface);
  color: var(--text);
}

body.dashboard .dashboard-alert-unread {
  border-left: 4px solid var(--accent);
}

body.dashboard .dashboard-alert-main {
  flex: 1 1 20rem;
  min-width: 0;
  overflow-wrap: anywhere;
}

body.dashboard .dashboard-alert-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin: 0 0 var(--space-1);
}

body.dashboard .dashboard-severity {
  display: inline-block;
  padding: 0 var(--space-2);
  border: 1px solid var(--border);
  border-left: 4px solid var(--text-muted);
  border-radius: var(--radius-input);
  background: var(--bg);
  color: var(--text);
  font-size: var(--text-sm);
  font-weight: 700;
}

body.dashboard .dashboard-severity-info {
  border-left-color: var(--accent);
}

body.dashboard .dashboard-severity-warning {
  border-left-color: var(--warning);
}

body.dashboard .dashboard-severity-critical {
  border-color: var(--danger);
  border-left-color: var(--danger);
}

/* An unread alert says so in words (plan tender-pondering-raccoon D7b): a chip like the severity chip, its edge the
   unread accent, so the state never rests on the card's colored edge alone. */
body.dashboard .dashboard-alert-unread-badge {
  display: inline-block;
  padding: 0 var(--space-2);
  border: 1px solid var(--border);
  border-left: 4px solid var(--accent);
  border-radius: var(--radius-input);
  background: var(--bg);
  color: var(--text);
  font-size: var(--text-sm);
  font-weight: 700;
}

body.dashboard .dashboard-alert-type {
  color: var(--text-muted);
  font-size: var(--text-sm);
}

body.dashboard .dashboard-alert-title {
  margin: 0;
  font-size: var(--text-md);
}

body.dashboard .dashboard-alert-message {
  margin: var(--space-1) 0 0;
}

body.dashboard .dashboard-alert-meta {
  margin: var(--space-1) 0 0;
  color: var(--text-muted);
  font-size: var(--text-sm);
}

body.dashboard .dashboard-alert-meta a {
  display: inline-flex;
  align-items: center;
  min-height: var(--button-height);
}

body.dashboard .dashboard-alert-action {
  flex: none;
}

body.dashboard .dashboard-alert-action form,
body.dashboard .dashboard-alert-action p {
  margin: 0;
}

@media (max-width: 599px) {
  body.dashboard .dashboard-alert-action,
  body.dashboard .dashboard-alert-action .button,
  body.dashboard .dashboard-mark-all,
  body.dashboard .dashboard-mark-all .button {
    width: 100%;
  }
}

/* Risk (dashboard/risk): the Score an Address form (street and street 2 full width, then ZIP, city and state side by
   side from 600px), the score in text and the level in words with a colored left edge (never color alone), then
   the bar (an inline SVG track and a value rect as long as the score, painted by classes on the tokens, never an
   attribute or an inline style) over its 0 and 100 scale, the reason and the six signals. The intro paragraph of
   every page that has one keeps the same gap above the card that follows it. */
body.dashboard :is(.dashboard-risk-intro, .dashboard-intro) {
  margin: 0 0 var(--space-4);
}

body.dashboard .dashboard-risk-form {
  display: grid;
  gap: var(--space-3);
}

body.dashboard .dashboard-risk-form .field {
  margin: 0;
}

body.dashboard .dashboard-risk-form .form-actions {
  margin: 0;
}

@media (min-width: 600px) {
  body.dashboard .dashboard-risk-form {
    grid-template-columns: 10rem minmax(0, 1fr) 6rem;
  }

  body.dashboard .dashboard-risk-form .dashboard-risk-field-street,
  body.dashboard .dashboard-risk-form .dashboard-risk-field-street2,
  body.dashboard .dashboard-risk-form .form-actions {
    grid-column: 1 / -1;
  }
}

body.dashboard .dashboard-risk-meter {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-6);
  margin: var(--space-2) 0 var(--space-4);
}

body.dashboard .dashboard-risk-bar {
  flex: 1 1 100%;
}

body.dashboard .risk-bar {
  display: block;
  width: 100%;
  height: 8px;
  border-radius: var(--radius-card);
  overflow: hidden;
}

body.dashboard .risk-bar-track {
  fill: var(--border);
}

body.dashboard .risk-bar-value {
  fill: var(--text-muted);
}

body.dashboard .risk-bar-value-low {
  fill: var(--success);
}

body.dashboard .risk-bar-value-medium {
  fill: var(--warning);
}

body.dashboard .risk-bar-value-high {
  fill: var(--danger);
}

body.dashboard .dashboard-risk-scale {
  display: flex;
  justify-content: space-between;
  margin: var(--space-1) 0 0;
  color: var(--text-muted);
  font-size: var(--text-sm);
}

body.dashboard .dashboard-risk-figure {
  margin: 0;
}

body.dashboard .dashboard-risk-score-value {
  font-size: var(--text-2xl);
  font-weight: 700;
}

body.dashboard .risk-level {
  display: inline-block;
  margin: 0;
  padding: 0 var(--space-2);
  border: 1px solid var(--border);
  border-left: 4px solid var(--text-muted);
  border-radius: var(--radius-input);
  background: var(--bg);
  color: var(--text);
  font-weight: 700;
}

body.dashboard .risk-level-low {
  border-left-color: var(--success);
}

body.dashboard .risk-level-medium {
  border-left-color: var(--warning);
}

body.dashboard .risk-level-high {
  border-color: var(--danger);
  border-left-color: var(--danger);
}

body.dashboard .dashboard-risk-result h2 {
  overflow-wrap: anywhere;
}

body.dashboard .dashboard-risk-reason {
  margin: 0 0 var(--space-4);
  font-size: var(--text-lg);
  overflow-wrap: anywhere;
}

body.dashboard .dashboard-risk-signals dd {
  display: grid;
  gap: var(--space-1);
}

body.dashboard .dashboard-risk-signal-score {
  font-weight: 700;
}

body.dashboard .dashboard-risk-signal-explanation {
  color: var(--text-muted);
  font-size: var(--text-sm);
}

/* Disputes (dashboard/disputes): the status chip says the status in words with a colored left edge (never color
   alone), the tab marked aria-current="page" as the map's chips, the Amount at risk card's "How this is computed"
   disclosure (a 48px summary, then the formula and one line per part: the shipment, its disputes and its declared
   value) and the action buttons' forms side by side. */
body.dashboard .dispute-status {
  display: inline-block;
  padding: 0 var(--space-2);
  border: 1px solid var(--border);
  border-left: 4px solid var(--text-muted);
  border-radius: var(--radius-input);
  background: var(--bg);
  color: var(--text);
  font-size: var(--text-sm);
  font-weight: 700;
  white-space: nowrap;
}

body.dashboard .dispute-status-open {
  border-color: var(--danger);
  border-left-color: var(--danger);
}

body.dashboard .dispute-status-investigating {
  border-left-color: var(--warning);
}

body.dashboard .dispute-status-resolved {
  border-left-color: var(--success);
}

body.dashboard .dashboard-chip[aria-current="page"] {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 2px var(--accent);
  font-weight: 700;
}

/* The amount never runs past its card: a long figure wraps, and under 600px every card of the Disputes page takes
   the whole row, so the figure and its opened parts have the phone's width and no card sits beside an empty half. */
body.dashboard .dashboard-count-amount .dashboard-count-value {
  overflow-wrap: anywhere;
}

@media (max-width: 599px) {
  body.dashboard .dashboard-counts-disputes > li {
    grid-column: 1 / -1;
  }
}

body.dashboard .dashboard-parts {
  margin-top: var(--space-2);
}

body.dashboard :is(.dashboard-parts, .dashboard-formulas) > summary {
  display: flex;
  align-items: center;
  min-height: var(--button-height);
  color: var(--accent);
  font-weight: 700;
  text-decoration: underline;
  cursor: pointer;
}

/* A row of figures' formulas (dashboard/_formulas, plan tender-pondering-raccoon D1): closed under its row, the 48px
   summary above with the Menu toggle's drawn caret (borders in currentColor, so no icon file) turning when it opens. */
body.dashboard .dashboard-formulas {
  margin-top: var(--space-2);
}

body.dashboard .dashboard-counts + .dashboard-formulas {
  margin: calc(-1 * var(--space-2)) 0 var(--space-4);
}

/* Inside a card (Home's Fulfillment pipeline) the card's own padding ends the disclosure, as under the other cards. */
body.dashboard .card > .dashboard-formulas:last-child {
  margin-bottom: 0;
}

body.dashboard .dashboard-formulas > summary {
  gap: var(--space-2);
  width: fit-content;
  list-style: none;
}

body.dashboard .dashboard-formulas > summary::-webkit-details-marker {
  display: none;
}

body.dashboard .dashboard-formulas > summary::after {
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  margin-top: -3px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
}

body.dashboard .dashboard-formulas[open] > summary::after {
  margin-top: 3px;
  transform: rotate(-135deg);
}

body.dashboard .dashboard-formulas > .dashboard-formula {
  margin: 0;
}

body.dashboard .dashboard-count .dashboard-parts-formula {
  margin: 0 0 var(--space-2);
  color: var(--text-muted);
  font-size: var(--text-sm);
}

body.dashboard .dashboard-parts-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

body.dashboard .dashboard-parts-list > li {
  display: grid;
  gap: var(--space-1);
  padding: var(--space-2) 0;
  border-top: 1px solid var(--border);
  overflow-wrap: anywhere;
}

body.dashboard .dashboard-parts-value {
  font-weight: 700;
}

body.dashboard .dashboard-inline-form {
  margin: 0;
}

/* Reports (dashboard/reports): the index's cards, one column on a phone and two from 900px, each with View and CSV
   (48px buttons); a report's description and summary above its table. */
body.dashboard .dashboard-reports {
  display: grid;
  gap: var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

body.dashboard .dashboard-reports > .card {
  margin-bottom: 0;
}

@media (min-width: 900px) {
  body.dashboard .dashboard-reports {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

body.dashboard .dashboard-report-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: var(--space-3) 0;
}

body.dashboard .dashboard-report-description,
body.dashboard .dashboard-report-summary {
  margin: 0 0 var(--space-2);
  overflow-wrap: anywhere;
}

body.dashboard .dashboard-report-summary {
  font-weight: 700;
}

/* Search (dashboard/search): one card a group; a long title, claim or address wraps inside it. */
body.dashboard .dashboard-search-group {
  overflow-wrap: anywhere;
}

body.dashboard .dashboard-search-title {
  display: block;
  font-weight: 700;
}

/* Users and Teams, API Keys and Integrations (dashboard/users, api_keys, integrations): a new key or signing secret
   shown once with an accent edge, in mono, breaking anywhere so a phone never scrolls sideways; a user's role select
   with its Save button under it (stacked, so the Role column stays narrow); the events as a frameless fieldset of 48px checkbox labels. */
body.dashboard .dashboard-secret {
  border-left: 4px solid var(--accent);
}

body.dashboard .dashboard-secret-value {
  margin: 0 0 var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-input);
  background: var(--bg);
  font-family: var(--font-mono);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* A visually hidden span in a table cell (a row button's "of <name>") is absolutely positioned: without a positioned
   ancestor its containing block is the page, so a span in a column scrolled out of the wrap widened the page itself
   (measured at 1280px on Users and Teams). The wrap as its containing block keeps it inside the wrap's own scroll. */
body.dashboard .table-wrap {
  position: relative;
}

body.dashboard .dashboard-role-form {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
  margin: 0;
}

body.dashboard .dashboard-role-form .field-input {
  width: auto;
}

body.dashboard .dashboard-events {
  margin: 0 0 var(--space-4);
  padding: 0;
  border: 0;
}

body.dashboard .dashboard-events .dashboard-check {
  display: flex;
}

/* Support: the case status chip (the dispute chip's shape) and the thread. A message body is text: its line breaks
   are kept by white-space, and a long word or address wraps instead of widening the page. */
body.dashboard .support-status {
  display: inline-block;
  padding: 0 var(--space-2);
  border: 1px solid var(--border);
  border-left: 4px solid var(--text-muted);
  border-radius: var(--radius-input);
  background: var(--bg);
  color: var(--text);
  font-size: var(--text-sm);
  font-weight: 700;
  white-space: nowrap;
}

body.dashboard .support-status-new,
body.dashboard .support-status-open {
  border-left-color: var(--accent);
}

body.dashboard .support-status-in_progress,
body.dashboard .support-status-waiting_on_customer {
  border-left-color: var(--warning);
}

body.dashboard .support-status-resolved {
  border-left-color: var(--success);
}

body.dashboard .support-thread {
  display: grid;
  gap: var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

body.dashboard .support-message {
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border);
  border-left: 4px solid var(--text-muted);
  border-radius: var(--radius-input);
  background: var(--bg);
  min-width: 0;
}

body.dashboard .support-message-secretag {
  border-left-color: var(--accent);
}

body.dashboard .support-message-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0 0 var(--space-2);
}

body.dashboard .support-message-body {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* A display rule beats the hidden attribute, so hidden wins on this host. */
body.dashboard [hidden] {
  display: none !important;
}
