/* Tower dashboard. Tokens, type and components per plan/web-surface.md section 5.
   No inline style anywhere: this stylesheet is the only source of presentation. */

@layer tokens, base, components, utilities;

@font-face {
  font-family: "Inter";
  src: url("vendor/InterVariable.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Inter";
  src: url("vendor/InterVariable-Italic.woff2") format("woff2");
  font-weight: 100 900;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("vendor/JetBrainsMono-Regular.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}

@font-face {
  font-family: "JetBrains Mono";
  src: url("vendor/JetBrainsMono-Bold.woff2") format("woff2");
  font-weight: 700;
  font-display: swap;
}

@layer tokens {
  :root {
    --surface: #ffffff;
    --surface-raised: #f5f6f8;
    --surface-sunken: #eceef2;
    --surface-selected: #e6edff;
    --text: #1a1d24;
    --text-muted: #4b5466;
    --accent: #2450c8;
    --on-accent: #ffffff;
    --danger: #b3261e;
    --warning: #8a5300;
    --success: #17703a;
    --border: #7d8799;
    --divider: #dde1e8;
    --focus: #1d4ed8;
    --right-read: #1b56a6;
    --right-write: #0b6b5c;
    --right-view: #5b3eb0;
    --right-administer: #9a4200;
    --right-grant: #a3246c;
    --right-audit: #576100;
    --right-reclassify: #a8213c;

    --font-ui: "Inter", system-ui, sans-serif;
    --font-id: "JetBrains Mono", ui-monospace, monospace;
    --text-xs: 0.8rem;
    --text-sm: 0.875rem;
    --text-base: 1rem;
    --text-lg: 1.2rem;
    --text-xl: 1.44rem;
    --text-2xl: 1.728rem;

    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 24px;
    --space-6: 32px;
    --space-7: 48px;
    --radius-control: 6px;
    --radius-panel: 8px;
    --shadow-raised: 0 1px 0 rgb(0 0 0 / 0.06), 0 1px 3px rgb(0 0 0 / 0.08);
    --transition: 160ms ease;
    color-scheme: light;
  }

  /* Dark tokens: for an explicit dark choice, and for System while the system is dark.
     The two blocks hold the same values; a test keeps them equal. */
  :root[data-theme="dark"] {
    --surface: #101318;
    --surface-raised: #171b22;
    --surface-sunken: #0b0d11;
    --surface-selected: #1f2a44;
    --text: #e7e9ee;
    --text-muted: #a6afbd;
    --accent: #8eaeff;
    --on-accent: #0b1020;
    --danger: #ff8f86;
    --warning: #f0c060;
    --success: #6fd68f;
    --border: #6e7889;
    --divider: #2a303a;
    --focus: #9db8ff;
    --right-read: #8ab8ff;
    --right-write: #5cd3bf;
    --right-view: #c3a9ff;
    --right-administer: #ffaa6b;
    --right-grant: #ff99cf;
    --right-audit: #d0d86a;
    --right-reclassify: #ff93a6;
    --shadow-raised: 0 1px 0 rgb(0 0 0 / 0.4);
    color-scheme: dark;
  }

  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
      --surface: #101318;
      --surface-raised: #171b22;
      --surface-sunken: #0b0d11;
      --surface-selected: #1f2a44;
      --text: #e7e9ee;
      --text-muted: #a6afbd;
      --accent: #8eaeff;
      --on-accent: #0b1020;
      --danger: #ff8f86;
      --warning: #f0c060;
      --success: #6fd68f;
      --border: #6e7889;
      --divider: #2a303a;
      --focus: #9db8ff;
      --right-read: #8ab8ff;
      --right-write: #5cd3bf;
      --right-view: #c3a9ff;
      --right-administer: #ffaa6b;
      --right-grant: #ff99cf;
      --right-audit: #d0d86a;
      --right-reclassify: #ff93a6;
      --shadow-raised: 0 1px 0 rgb(0 0 0 / 0.4);
      color-scheme: dark;
    }
  }

  @media (prefers-contrast: more) {
    :root {
      --text-muted: var(--text);
      --border: var(--text);
    }
  }

  @media (prefers-reduced-motion: reduce) {
    :root {
      --transition: 0s;
    }
  }
}

@layer base {
  html {
    font-family: var(--font-ui);
    font-size: 100%;
    font-feature-settings: "ss02", "tnum";
    line-height: 1.5;
    color: var(--text);
    background: var(--surface);
  }

  body {
    margin: 0;
    min-height: 100vh;
    background: var(--surface);
  }

  /* An important declaration in this early layer outranks every later display rule,
     so a component's own display never shows an element marked hidden. */
  [hidden] {
    display: none !important;
  }

  h1,
  h2,
  h3 {
    line-height: 1.25;
    margin: 0 0 var(--space-4);
    font-weight: 650;
  }

  h1 {
    font-size: var(--text-2xl);
  }

  h2 {
    font-size: var(--text-lg);
  }

  h3 {
    font-size: var(--text-base);
  }

  p {
    margin: 0 0 var(--space-4);
    max-width: 72ch;
  }

  a {
    color: var(--accent);
    text-underline-offset: 0.15em;
  }

  a:hover {
    text-decoration-thickness: 2px;
  }

  :focus-visible {
    outline: 2px solid var(--focus);
    outline-offset: 2px;
  }

  table {
    border-collapse: collapse;
    width: 100%;
  }

  th,
  td {
    text-align: left;
    padding: var(--space-2) var(--space-3);
    border-bottom: 1px solid var(--divider);
    vertical-align: middle;
  }

  thead th {
    background: var(--surface-raised);
    font-size: var(--text-sm);
    font-weight: 600;
    position: sticky;
    top: 0;
  }

  input:not([type="checkbox"], [type="radio"], [type="hidden"]),
  select,
  textarea {
    font: inherit;
    color: var(--text);
    background: var(--surface-sunken);
    border: 1px solid var(--border);
    border-radius: var(--radius-control);
    padding: var(--space-2) var(--space-3);
    min-height: 40px;
    width: 100%;
    max-width: 32rem;
  }

  input[type="file"] {
    padding: var(--space-2);
  }

  input[type="checkbox"],
  input[type="radio"] {
    flex: none;
    width: 1.1rem;
    height: 1.1rem;
    margin: 0;
    accent-color: var(--accent);
  }

  dl {
    margin: 0;
  }

  @media (forced-colors: active) {
    :focus-visible {
      outline: 2px solid CanvasText;
    }
  }
}

@layer components {
  .skip-link {
    position: absolute;
    left: var(--space-3);
    top: -100px;
    padding: var(--space-2) var(--space-4);
    background: var(--accent);
    color: var(--on-accent);
    border-radius: var(--radius-control);
    z-index: 10;
  }

  .skip-link:focus {
    top: var(--space-3);
  }

  .selection-actions:focus-visible {
    outline: 2px solid var(--focus);
    outline-offset: 2px;
  }

  /* Shown when reached by keyboard: after the last row, a way back to the selection's
     actions without passing the whole page. */
  .skip-inline:not(:focus) {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .masthead {
    position: sticky;
    top: 0;
    z-index: 5;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-5);
    background: var(--surface-raised);
    border-bottom: 1px solid var(--divider);
  }

  .brand {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-weight: 700;
    font-size: var(--text-lg);
    color: var(--text);
    text-decoration: none;
  }

  .brand-mark {
    width: 1.25rem;
    height: 1.625rem;
    object-fit: contain;
    flex: none;
  }

  .masthead-end {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
  }

  .principal {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
  }

  .shell {
    display: grid;
    grid-template-columns: 1fr;
    /* Stacked, the navigation keeps its own height and the content takes the rest,
       so a short page does not stretch the navigation row. */
    grid-template-rows: auto 1fr;
    min-height: calc(100vh - 64px);
  }

  .sidenav ul {
    list-style: none;
    margin: 0;
    padding: var(--space-3);
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
  }

  .sidenav a {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-height: 40px;
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-control);
    color: var(--text);
    text-decoration: none;
  }

  .sidenav a:hover {
    background: var(--surface-sunken);
  }

  .sidenav a[aria-current="page"] {
    background: var(--surface-selected);
    font-weight: 600;
    box-shadow: inset 3px 0 0 var(--accent);
  }

  @media (min-width: 768px) {
    .shell {
      grid-template-columns: 15rem 1fr;
      grid-template-rows: 1fr;
    }

    .shell-single {
      grid-template-columns: 1fr;
    }

    .sidenav {
      border-right: 1px solid var(--divider);
      background: var(--surface-raised);
    }

    .sidenav ul {
      flex-direction: column;
      position: sticky;
      top: 64px;
    }
  }

  main {
    padding: var(--space-5);
    min-width: 0;
  }

  main:focus {
    outline: none;
  }

  .narrow {
    max-width: 40rem;
  }

  .lede {
    color: var(--text-muted);
    font-size: var(--text-lg);
  }

  .muted {
    color: var(--text-muted);
  }

  .panel {
    container-type: inline-size;
    background: var(--surface-raised);
    border: 1px solid var(--divider);
    border-radius: var(--radius-panel);
    box-shadow: var(--shadow-raised);
    padding: var(--space-4) var(--space-5);
    margin-bottom: var(--space-5);
  }

  .panel[aria-busy="true"] {
    opacity: 0.7;
  }

  .panel-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    flex-wrap: wrap;
  }

  .panel-state {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    font-size: var(--text-sm);
    color: var(--text-muted);
  }

  .panel-state[data-state="stale"],
  .panel-state[data-state="offline"] {
    color: var(--warning);
  }

  .panel-state[data-state="error"] {
    color: var(--danger);
  }

  .state {
    display: flex;
    gap: var(--space-3);
    align-items: flex-start;
    padding: var(--space-4);
    border: 1px dashed var(--border);
    border-radius: var(--radius-control);
    background: var(--surface);
    margin-bottom: var(--space-4);
  }

  .state p {
    margin: 0;
  }

  .state-error {
    border-style: solid;
    border-color: var(--danger);
  }

  .state-offline,
  .state-stale {
    border-style: solid;
    border-color: var(--warning);
  }

  /* A wide table scrolls inside its own labelled region, reachable by keyboard, with a
     shadow at an edge while there is more to see that way. */
  .table-scroll {
    overflow-x: auto;
    border: 1px solid var(--divider);
    border-radius: var(--radius-control);
    background:
      linear-gradient(to right, var(--surface) 30%, transparent) left / 2rem 100% no-repeat local,
      linear-gradient(to left, var(--surface) 30%, transparent) right / 2rem 100% no-repeat local,
      radial-gradient(farthest-side at 0 50%, color-mix(in srgb, var(--text) 30%, transparent), transparent) left / 0.75rem 100% no-repeat scroll,
      radial-gradient(farthest-side at 100% 50%, color-mix(in srgb, var(--text) 30%, transparent), transparent) right / 0.75rem 100% no-repeat scroll,
      var(--surface);
    margin-bottom: var(--space-4);
    max-width: 100%;
  }

  .table-scroll:focus-visible {
    outline: 2px solid var(--focus);
    outline-offset: 2px;
  }

  .table-scroll table {
    min-width: 36rem;
  }

  @media (max-width: 600px) {
    .table-scroll table {
      min-width: 0;
    }

    .table-scroll .identifier {
      white-space: normal;
      overflow-wrap: anywhere;
    }
  }

  .table-scroll .identifier {
    overflow-wrap: normal;
    white-space: nowrap;
  }

  .numeric {
    font-variant-numeric: tabular-nums;
    text-align: right;
  }

  .identifier {
    font-family: var(--font-id);
    font-size: 0.9em;
    overflow-wrap: anywhere;
  }

  .identifier-muted {
    color: var(--text-muted);
  }

  .node-name {
    font-weight: 600;
  }

  .icon {
    width: 1.1em;
    height: 1.1em;
    flex: none;
    vertical-align: -0.15em;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
  }

  .button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    min-height: 40px;
    min-width: 40px;
    padding: var(--space-2) var(--space-4);
    font: inherit;
    font-size: var(--text-sm);
    font-weight: 600;
    line-height: 1.25;
    color: var(--on-accent);
    background: var(--accent);
    border: 1px solid var(--accent);
    border-radius: var(--radius-control);
    text-decoration: none;
    cursor: pointer;
    transition:
      background-color var(--transition),
      color var(--transition);
  }

  .button:hover {
    background: color-mix(in oklch, var(--accent) 85%, var(--text));
  }

  .button-quiet {
    color: var(--accent);
    background: transparent;
    border-color: var(--border);
  }

  .button-quiet:hover {
    background: var(--surface-sunken);
  }

  .button-danger {
    color: var(--surface);
    background: var(--danger);
    border-color: var(--danger);
  }

  .button-danger:hover {
    background: color-mix(in oklch, var(--danger) 85%, var(--text));
  }

  .button-icon {
    min-height: 24px;
    min-width: 24px;
    padding: var(--space-1);
    margin-left: var(--space-1);
    color: var(--text-muted);
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-control);
    cursor: pointer;
  }

  .button-icon:hover {
    color: var(--text);
    border-color: var(--border);
  }

  .button:disabled {
    cursor: not-allowed;
    opacity: 0.55;
  }

  .button-row {
    display: flex;
    gap: var(--space-3);
    flex-wrap: wrap;
  }

  .stack {
    display: grid;
    gap: var(--space-4);
    margin-bottom: var(--space-5);
  }

  .stack > .button,
  .stack > .button-row {
    justify-self: start;
  }

  .change-form {
    display: inline-block;
  }

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

  .field {
    display: grid;
    gap: var(--space-1);
  }

  .field label {
    font-weight: 600;
  }

  .hint {
    color: var(--text-muted);
    font-size: var(--text-sm);
    margin: 0;
  }

  .field-error {
    border-left: 4px solid var(--danger);
    padding-left: var(--space-3);
  }

  .error-message {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    color: var(--danger);
    font-weight: 600;
    margin: 0;
  }

  .error-summary {
    border: 2px solid var(--danger);
    border-radius: var(--radius-panel);
    padding: var(--space-4) var(--space-5);
    margin-bottom: var(--space-5);
    background: var(--surface);
  }

  .error-summary h2 {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    color: var(--danger);
  }

  .error-summary ul {
    margin: 0;
    padding-left: var(--space-5);
  }

  .error-summary a {
    color: var(--danger);
    font-weight: 600;
  }

  .banner {
    display: flex;
    gap: var(--space-3);
    align-items: center;
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-control);
    border: 1px solid currentColor;
    margin-bottom: var(--space-4);
    background: var(--surface);
  }

  .banner-success {
    color: var(--success);
  }

  .banner-warning {
    color: var(--warning);
  }

  .banner-danger {
    color: var(--danger);
  }

  .banner span {
    color: var(--text);
  }

  /* The page-changed notice spans the sticky header, so it stays in view. */
  .masthead > #stale-banner {
    flex-basis: 100%;
    margin: 0;
  }

  .banner-fixed {
    position: fixed;
    left: var(--space-4);
    right: var(--space-4);
    bottom: var(--space-4);
    z-index: 20;
    box-shadow: var(--shadow-raised);
    color: var(--text);
    border-color: var(--warning);
  }

  .badge,
  .tag {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    box-sizing: border-box;
    height: 24px;
    padding: 0 var(--space-2);
    border-radius: 999px;
    border: 1px solid var(--border);
    font-size: var(--text-xs);
    font-weight: 600;
    line-height: 1;
    background: var(--surface);
    white-space: nowrap;
  }

  .tag .icon {
    width: 1em;
    height: 1em;
  }

  /* Each right keeps its word; the color only adds a second cue. */
  .tag-right {
    color: var(--right-color, var(--text));
    border-color: currentColor;
  }

  .tag-read { --right-color: var(--right-read); }
  .tag-write { --right-color: var(--right-write); }
  .tag-view { --right-color: var(--right-view); }
  .tag-administer { --right-color: var(--right-administer); }
  .tag-grant { --right-color: var(--right-grant); }
  .tag-audit { --right-color: var(--right-audit); }
  .tag-reclassify { --right-color: var(--right-reclassify); }

  [data-explain] {
    cursor: help;
  }

  #tip {
    position: fixed;
    z-index: 40;
    max-width: min(20rem, calc(100vw - 2 * var(--space-4)));
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-control);
    background: var(--text);
    color: var(--surface);
    font-size: var(--text-sm);
    line-height: 1.4;
    box-shadow: var(--shadow-raised);
    pointer-events: none;
  }

  .badge-environment {
    text-transform: uppercase;
    letter-spacing: 0.04em;
  }

  .badge-plenary {
    border-color: var(--warning);
  }

  .count {
    margin-left: auto;
    font-size: var(--text-xs);
    padding: 0 var(--space-2);
    border-radius: 999px;
    background: var(--accent);
    color: var(--on-accent);
  }

  .tags {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
  }

  .tag-current {
    border-color: var(--success);
  }

  .tag-revoked {
    border-color: var(--danger);
  }

  .tag-expired {
    border-color: var(--warning);
  }

  .facts {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: var(--space-2) var(--space-5);
    margin-bottom: var(--space-5);
  }

  .facts dt {
    font-weight: 600;
    color: var(--text-muted);
  }

  .facts dd {
    margin: 0;
    overflow-wrap: anywhere;
  }

  @container (max-width: 30rem) {
    .facts {
      grid-template-columns: 1fr;
      gap: var(--space-1);
    }

    .facts dd {
      margin-bottom: var(--space-2);
    }
  }

  .pager {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
  }

  .pager-size {
    color: var(--text-muted);
    font-size: var(--text-sm);
  }

  .search-form {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-3);
    margin-bottom: var(--space-2);
  }

  /* The search's progress has its own line, its height kept whether shown or not. */
  .search-progress {
    min-height: 1.5rem;
    margin: 0 0 var(--space-3);
  }

  .search-form .field {
    flex: 1 1 18rem;
  }

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

  .result {
    background: var(--surface);
    border: 1px solid var(--divider);
    border-radius: var(--radius-control);
    padding: var(--space-4);
  }

  .result-head {
    display: flex;
    gap: var(--space-3);
    align-items: center;
    flex-wrap: wrap;
    margin-bottom: var(--space-2);
  }

  .result-head {
    justify-content: space-between;
    align-items: baseline;
  }

  .result-title {
    margin: 0;
    font-size: var(--text-lg);
  }

  .result-name {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    font-weight: 600;
    color: var(--accent);
    text-align: left;
    cursor: pointer;
  }

  .result-name:hover {
    text-decoration: underline;
  }

  .result-meta {
    margin-left: auto;
    color: var(--text-muted);
    font-size: var(--text-sm);
  }

  .graph-scroll {
    overflow-x: auto;
    margin-bottom: var(--space-4);
  }

  .node-graph {
    display: block;
    max-width: none;
  }

  .graph-edge {
    stroke: var(--border);
    stroke-width: 1.5;
  }

  .graph-node rect {
    fill: var(--surface-raised);
    stroke: var(--border);
  }

  .graph-node text {
    fill: var(--text);
    font-family: var(--font-id);
    font-size: 13px;
  }

  .upload-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--space-3);
  }

  .upload-row {
    background: var(--surface);
    border: 1px solid var(--divider);
    border-radius: var(--radius-control);
    padding: var(--space-3) var(--space-4);
    min-width: 0;
  }

  .upload-head {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-3);
    align-items: baseline;
    justify-content: space-between;
  }

  .upload-name {
    margin: 0;
    font-size: var(--text-base);
    overflow-wrap: anywhere;
  }

  .upload-stage {
    margin: var(--space-2) 0 0;
  }

  /* Fixed space for the bar and one line of words, whether or not they are filled; the
     words stay on that line (the whole text is in its title) except on narrow screens,
     which keep two lines for them. */
  .upload-progress {
    display: grid;
    grid-template-rows: 0.75rem calc(1.5 * var(--text-sm));
    gap: var(--space-1);
    margin-top: var(--space-2);
  }

  .upload-progress progress {
    grid-row: 1;
    width: min(20rem, 100%);
    height: 0.75rem;
    accent-color: var(--accent);
  }

  .upload-progress > span {
    grid-row: 2;
    font-size: var(--text-sm);
    line-height: 1.5;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }

  @media (max-width: 40rem) {
    .upload-progress {
      grid-template-rows: 0.75rem calc(2 * 1.5 * var(--text-sm));
    }

    .upload-progress > span {
      white-space: normal;
    }
  }

  .upload-status {
    margin: 0;
    font-size: var(--text-sm);
  }

  /* Filled only once the button is pressed and disabled, so taking its line then moves
     nothing anyone can press. */
  .upload-status:empty {
    display: none;
  }

  .inline-form {
    display: inline;
  }

  .more-results {
    margin-top: var(--space-4);
  }

  .more-results > summary {
    cursor: pointer;
    font-weight: 600;
    margin-bottom: var(--space-4);
  }

  .searching {
    display: inline-flex;
    gap: var(--space-2);
    align-items: center;
    color: var(--text-muted);
  }

  /* Revealed only when a search outlasts 400 ms, so a quick one does not flash it. */
  .searching.htmx-request {
    opacity: 0;
    animation: tower-reveal 0s linear 400ms forwards;
  }

  @keyframes tower-reveal {
    to {
      opacity: 1;
    }
  }

  .detail-panel {
    background: var(--surface);
    padding: var(--space-5);
    overflow-y: auto;
  }

  .detail-head {
    display: flex;
    gap: var(--space-3);
    align-items: baseline;
    justify-content: space-between;
    flex-wrap: wrap;
  }

  .detail-head h2 {
    margin: 0;
    overflow-wrap: anywhere;
  }

  /* Narrow and medium widths: the details take the whole screen until dismissed. */
  .detail-panel:not([hidden]) {
    position: fixed;
    inset: 0;
    z-index: 20;
  }

  /* Wide screens: the details sit beside the results, which stay in view. */
  @media (min-width: 1100px) {
    .search-layout[data-panel-open] {
      display: grid;
      grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
      gap: var(--space-5);
      align-items: start;
    }

    .detail-panel:not([hidden]) {
      position: sticky;
      inset: auto;
      top: var(--space-4);
      max-height: calc(100vh - 2 * var(--space-4));
      border: 1px solid var(--divider);
      border-radius: var(--radius-panel);
      box-shadow: var(--shadow-raised);
    }
  }

  .result-text,
  .source-text {
    max-width: 72ch;
  }

  .source-text {
    white-space: pre-wrap;
    background: var(--surface-raised);
    border: 1px solid var(--divider);
    border-radius: var(--radius-panel);
    padding: var(--space-5);
    margin-bottom: var(--space-5);
  }

  .breadcrumbs ol {
    list-style: none;
    margin: 0 0 var(--space-3);
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
  }

  .breadcrumbs li + li::before {
    content: "/";
    margin-right: var(--space-2);
    color: var(--text-muted);
  }

  /* A table cell stays a cell, so its row's lines and background run through it. */
  .row-actions {
    text-align: right;
    white-space: nowrap;
  }

  .row-actions .button {
    min-height: 28px;
    padding-block: 0;
  }

  /* A row's actions side by side, a form's button included. */
  .row-actions form {
    display: inline-block;
  }

  .row-actions > * + * {
    margin-left: var(--space-2);
  }

  .plain-list {
    list-style: none;
    margin: 0 0 var(--space-4);
    padding: 0;
    display: grid;
    gap: var(--space-2);
  }

  .danger-zone {
    margin-top: var(--space-5);
    padding: var(--space-4);
    border: 1px solid var(--danger);
    border-radius: var(--radius-control);
    background: var(--surface);
  }

  .detail-item {
    margin-right: var(--space-3);
  }

  .summary-list {
    border-top: 1px solid var(--divider);
    padding-top: var(--space-4);
  }

  .htmx-indicator {
    visibility: hidden;
  }

  .htmx-request .htmx-indicator,
  .htmx-request.htmx-indicator {
    visibility: visible;
  }

  @media (forced-colors: active) {
    .button,
    .badge,
    .tag,
    .panel,
    .banner {
      border: 1px solid ButtonText;
    }

    .sidenav a[aria-current="page"] {
      outline: 2px solid Highlight;
    }
  }
}

@layer utilities {
  .visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
}

/* The redesigned dashboard: one dialog, the file browser, rights pills and busy state. */
@layer components {
  .dialog {
    width: min(40rem, calc(100vw - 2 * var(--space-4)));
    max-height: calc(100vh - 2 * var(--space-5));
    padding: var(--space-5);
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-panel);
    box-shadow: 0 8px 32px color-mix(in oklch, var(--text) 25%, transparent);
  }

  .dialog::backdrop {
    /* Dims whatever is behind, in either mode. */
    background: rgb(0 0 0 / 0.5);
  }

  .dialog-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
  }

  .dialog-head h2 {
    margin: 0;
  }

  .dialog-error:empty {
    display: none;
  }

  .dialog-error .error-message {
    margin: 0 0 var(--space-3);
  }

  .notice-in-place {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
  }

  .node-header {
    display: grid;
    gap: var(--space-2);
    margin-bottom: var(--space-4);
  }

  .node-header h1 {
    margin: 0;
  }

  .node-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    border-bottom: 1px solid var(--divider);
  }

  .node-tabs a {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-height: 40px;
    padding: var(--space-2) var(--space-3);
    color: var(--text-muted);
    text-decoration: none;
    border-bottom: 2px solid transparent;
  }

  .node-tabs a[aria-current="page"] {
    color: var(--text);
    font-weight: 600;
    border-bottom-color: var(--accent);
  }

  .path-line {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    margin: var(--space-3) 0;
    font-family: var(--font-id);
    font-size: var(--text-sm);
    overflow-wrap: anywhere;
  }

  .path-line a[aria-current="page"] {
    color: var(--text);
    font-weight: 700;
    text-decoration: none;
  }

  .path-sep {
    color: var(--text-muted);
    padding: 0 1px;
  }

  .toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin: var(--space-3) 0;
  }

  .selection-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-left: auto;
  }

  .browser .select-col {
    width: 2.5rem;
  }

  .browser tbody tr[data-drop-target] {
    outline: 2px dashed var(--accent);
    outline-offset: -2px;
    background: var(--surface-selected);
  }

  .browser tbody tr:has(input[data-select]:checked) {
    background: var(--surface-selected);
  }

  .browser th[scope="row"] a,
  .browser th[scope="row"] span {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
  }

  .row-menu-cell {
    width: 3rem;
    text-align: right;
  }

  .row-menu {
    position: relative;
    display: inline-block;
  }

  .row-menu > summary {
    list-style: none;
  }

  .row-menu > summary::-webkit-details-marker {
    display: none;
  }

  .row-menu .menu {
    position: absolute;
    right: 0;
    z-index: 5;
    min-width: 13rem;
    margin: var(--space-1) 0 0;
    padding: var(--space-1);
    list-style: none;
    text-align: left;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-control);
    box-shadow: 0 4px 16px color-mix(in oklch, var(--text) 18%, transparent);
  }

  .row-menu .menu a,
  .row-menu .menu button {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    width: 100%;
    min-height: 36px;
    padding: var(--space-2) var(--space-3);
    font: inherit;
    font-size: var(--text-sm);
    color: var(--text);
    text-align: left;
    text-decoration: none;
    background: transparent;
    border: 0;
    border-radius: var(--radius-control);
    cursor: pointer;
  }

  .row-menu .menu a:hover,
  .row-menu .menu button:hover {
    background: var(--surface-sunken);
  }

  .row-menu .menu-danger a {
    color: var(--danger);
  }

  .button-danger-quiet {
    color: var(--danger);
    background: transparent;
    border-color: var(--border);
  }

  .button-danger-quiet:hover {
    background: color-mix(in oklch, var(--danger) 10%, var(--surface));
  }

  .button-primary {
    color: var(--on-accent);
    background: var(--accent);
    border-color: var(--accent);
  }

  .folder-picker {
    display: grid;
    gap: var(--space-1);
    max-height: 16rem;
    overflow-y: auto;
    margin: 0 0 var(--space-4);
    padding: var(--space-2);
    list-style: none;
    border: 1px solid var(--divider);
    border-radius: var(--radius-control);
  }

  .folder-picker a {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-height: 36px;
    padding: var(--space-1) var(--space-2);
  }

  .choice-list {
    display: grid;
    gap: var(--space-2);
    margin: 0;
    padding: 0;
    list-style: none;
  }

  .choice {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-height: 32px;
  }

  .choice-disabled {
    color: var(--text-muted);
  }

  .tag-choice {
    cursor: pointer;
  }

  .tag-choice input {
    margin: 0 var(--space-1) 0 0;
  }

  .tag-choice:has(input:checked) {
    color: var(--surface);
    background: var(--right-color);
  }

  .tag-missing {
    text-decoration: line-through;
    text-decoration-thickness: 2px;
    opacity: 0.8;
  }

  .tag-at {
    font-weight: 400;
    color: var(--text-muted);
  }

  .needs {
    display: inline-flex;
    flex-wrap: wrap;
    gap: var(--space-1);
  }

  .tag-deleted {
    color: var(--danger);
    border-color: var(--danger);
  }

  .grant-tags {
    gap: var(--space-2);
  }

  .grant-tag {
    display: inline-flex;
    align-items: center;
    gap: 2px;
  }

  .grant-tag .revoke {
    display: inline;
  }

  .section {
    margin-top: var(--space-5);
  }

  .danger-zone h2 {
    color: var(--danger);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: var(--text-lg);
  }

  details.technical {
    margin: var(--space-4) 0;
    color: var(--text-muted);
  }

  details.technical > summary {
    cursor: pointer;
    min-height: 32px;
  }

  .cleanup-stages {
    margin: var(--space-2) 0;
    padding-left: var(--space-5);
  }

  .cleanup-stages li.pending {
    color: var(--text-muted);
  }

  .cleanup-stages li.done::marker {
    color: var(--success, currentColor);
  }

  details.receipt {
    margin: var(--space-3) 0;
  }

  details.receipt > summary {
    cursor: pointer;
    min-height: 32px;
    overflow-wrap: anywhere;
  }

  .field-live {
    display: flex;
    justify-content: space-between;
    gap: var(--space-3);
    min-height: 1.25em;
    margin: var(--space-1) 0 0;
    font-size: var(--text-sm);
  }

  .field-live [data-live-message].is-error {
    color: var(--danger);
  }

  .field-live [data-live-message].is-warning {
    color: var(--warning);
  }

  .counter {
    margin: 0;
    text-align: right;
    font-size: var(--text-sm);
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
  }

  .zip-choice {
    border: 0;
    padding: 0;
  }


  .result-path,
  .location {
    font-family: var(--font-id);
    font-size: var(--text-sm);
    color: var(--text-muted);
    overflow-wrap: anywhere;
  }

  .result-text {
    white-space: pre-line;
  }

  .snapshot-list {
    display: grid;
    gap: var(--space-2);
    margin: var(--space-4) 0;
    padding: 0;
    list-style: none;
  }

  .snapshot-list li {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3);
  }

  .graph-scroll {
    display: flex;
    justify-content: center;
  }

  .graph-link {
    cursor: pointer;
  }

  .graph-link:hover rect {
    stroke: var(--accent);
    stroke-width: 2;
  }

  /* The box itself shows focus: an outline around the link would sit off the box. */
  .graph-link:focus-visible {
    outline: none;
  }

  .graph-link:focus-visible rect {
    stroke: var(--focus);
    stroke-width: 3;
  }

  /* One busy state for every action that takes a moment. */
  [data-busy] {
    cursor: progress;
  }

  button[data-busy]::after,
  a[data-busy]::after {
    content: "";
    width: 1em;
    height: 1em;
    border: 2px solid currentcolor;
    border-right-color: transparent;
    border-radius: 50%;
    animation: busy-spin 0.8s linear infinite;
  }

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

  @media (prefers-reduced-motion: reduce) {
    button[data-busy]::after,
    a[data-busy]::after {
      animation: none;
      border-right-color: currentcolor;
      opacity: 0.6;
    }
  }
}

@layer components {
  .dialog-where {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-2);
  }

  .dialog-where .path-line {
    margin: 0;
  }
}

/* Corrections after the independent review: rows, menus, notices, snapshots, colour modes. */
@layer components {
  .icon-fill {
    fill: currentColor;
    stroke: none;
  }

  .theme-choice {
    display: inline-flex;
    margin: 0 0 0 var(--space-3);
    padding: 2px;
    border: 1px solid var(--border);
    border-radius: var(--radius-control);
  }

  .theme-option {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    min-height: 28px;
    padding: 2px var(--space-2);
    font-size: var(--text-xs);
    color: var(--text-muted);
    border-radius: calc(var(--radius-control) - 2px);
    cursor: pointer;
  }

  .theme-option input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
  }

  .theme-option:has(input:checked) {
    color: var(--on-accent);
    background: var(--accent);
  }

  .theme-option:has(input:focus-visible) {
    outline: 2px solid var(--focus);
    outline-offset: 2px;
  }

  .browser th,
  .browser td {
    padding-block: var(--space-1);
  }

  .browser .row-menu > summary {
    min-height: 28px;
    min-width: 28px;
    margin: 0;
  }

  .browser tbody tr[draggable="true"] {
    cursor: grab;
  }

  /* A row's secondary line stands in for the columns a phone folds away; on a wider screen
     those columns show it, so it is hidden, outranking the row heading's span rule. */
  .row-secondary,
  .browser th[scope="row"] span.row-secondary {
    display: none;
    font-size: var(--text-xs);
    font-weight: 400;
    color: var(--text-muted);
  }

  @media (max-width: 600px) {
    .browser .kind-col,
    .browser .size-col,
    .col-secondary {
      display: none;
    }

    .row-secondary,
    .browser th[scope="row"] span.row-secondary {
      display: block;
    }
  }

  .row-menu .menu {
    max-height: calc(100vh - 2 * var(--space-4));
    overflow-y: auto;
  }

  .selection-count:empty {
    display: none;
  }

  .button[data-busy]:disabled {
    /* Working, not unavailable: the spinner says so. */
    opacity: 1;
  }

  .notice-in-place {
    position: relative;
  }

  .notice-in-place:focus {
    outline: none;
  }

  .notice-in-place .banner {
    flex: 1;
  }

  .notice-dismiss {
    display: inline;
  }

  /* An upload on its way in: a row of its folder, greyed and inert until it is stored. */
  tr.arriving-row,
  tr.arriving-row th {
    color: var(--text-muted);
    font-weight: 400;
  }

  tr.arriving-row th .icon {
    opacity: 0.6;
  }

  .snapshot-banner {
    margin: var(--space-3) 0;
    padding: var(--space-3) var(--space-4);
    background: var(--surface-selected);
    border-left: 4px solid var(--accent);
    border-radius: var(--radius-control);
  }

  .snapshot-banner p {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin: 0;
  }

  .snapshot-banner p + p {
    margin-top: var(--space-2);
  }

  .right-choices {
    display: grid;
    gap: var(--space-2);
    margin: 0;
    padding: 0;
    list-style: none;
  }

  /* Each right's pill and its description side by side, the descriptions aligned. */
  .right-choices li {
    display: grid;
    grid-template-columns: 8.5rem 1fr;
    align-items: baseline;
    gap: var(--space-2);
  }

  .right-choices li > .tag {
    justify-self: start;
  }

  .right-choices .hint {
    margin: 0;
  }

  .dialog-stale {
    margin: 0 0 var(--space-3);
  }
}

/* Outside the layers, because the reset is unlayered and would otherwise win. Menlo comes first
   because the reset's stack prefers SF Mono, which only some Macs have installed, so the same
   page would otherwise draw differently from one Mac to the next. */
code {
  font-family: Menlo, Consolas, "Liberation Mono", monospace;
}
