/*
 * The TessariDB Vault web application, in the family console style: the same mode (neo-grotesque, calm, room between
 * things), the same TessariDB tokens (violet and neutrals on hue 286) and the same shell as the TessariDB S3 console,
 * so the products read as one family. System fonts only: nothing is fetched from off this server.
 *
 * Three token tiers, never skipped: PRIMITIVE values, SEMANTIC roles (the only thing rules below read), COMPONENT
 * values. A theme is a remap of the semantic tier: dark by the system preference unless the person chose light, or by
 * `data-theme="dark"` on <html>; every semantic token is mapped in both.
 */

/* ─────────────────────────────────────────────────────────── 1. PRIMITIVE ── */

:root {
  --violet-300: oklch(0.8 0.11 289);
  --violet-400: oklch(0.72 0.145 289);
  --violet-500: oklch(0.647 0.137 289);
  --violet-600: oklch(0.54 0.15 289);
  --violet-650: oklch(0.5 0.15 289);
  --violet-a12: oklch(0.647 0.137 289 / 0.12);
  --violet-a20: oklch(0.647 0.137 289 / 0.2);
  --n-1000-a50: oklch(0.13 0.009 286 / 0.5);
  --n-1000-a70: oklch(0.13 0.009 286 / 0.7);

  --n-1000: oklch(0.13 0.009 286);
  --n-950: oklch(0.16 0.011 286);
  --n-900: oklch(0.18 0.013 286);
  --n-850: oklch(0.2 0.015 286);
  --n-800: oklch(0.24 0.016 286);
  --n-700: oklch(0.28 0.018 286);
  --n-500: oklch(0.52 0.022 286);
  --n-450: oklch(0.62 0.02 286);
  --n-400: oklch(0.7 0.018 286);
  --n-200: oklch(0.93 0.01 286);
  --n-150: oklch(0.95 0.008 286);
  --n-100: oklch(0.97 0.006 286);
  --n-50: oklch(0.985 0.003 286);
  --n-0: oklch(1 0 0);

  --green-400: oklch(0.76 0.14 155);
  --green-600: oklch(0.5 0.13 155);
  --amber-400: oklch(0.79 0.13 75);
  --amber-600: oklch(0.52 0.11 75);
  --red-400: oklch(0.7 0.17 25);
  --red-600: oklch(0.53 0.19 25);

  --s-1: 0.25rem;
  --s-2: 0.5rem;
  --s-3: 0.75rem;
  --s-4: 1rem;
  --s-5: 1.5rem;
  --s-6: 2rem;
  --s-7: 2.5rem;
  --s-8: 3rem;

  /* Type: four sizes on a compact ratio (≈1.333) for a data-dense surface —
     caption 12, data 14 (tables, chips), body 16, heading/figure 28. */
  --t-caption: 0.75rem;
  --t-data: 0.875rem;
  --t-body: 1rem;
  --t-heading: 1.75rem;

  /* Layers: one named scale, never a literal. */
  --z-sticky: 20;
  --z-toast: 50;

  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 20px;
  --radius-pill: 999px;

  /* Dials (designer ref 28): quiet, near-static, airy enough to breathe. */
  --dial-variance: 30;
  --dial-motion: 30;
  --dial-density: 55;

  /* MOTION 30: state feedback only — one short duration, a strong ease-out. */
  --dur-fast: 120ms;
  --dur-press: 160ms;
  --ease: cubic-bezier(0.25, 1, 0.5, 1);
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
}

/* ──────────────────────────────────────────────────────────── 2. SEMANTIC ── */

/* Light. */
:root {
  color-scheme: light;
  --surface: var(--n-100);
  --surface-raised: var(--n-0);
  --surface-sunken: var(--n-150);
  --side: var(--n-50);
  --border: var(--n-200);
  --border-strong: var(--n-450);
  --text: var(--n-1000);
  --text-muted: var(--n-500);
  --accent: var(--violet-600);
  --accent-hover: var(--violet-650);
  --accent-text: var(--violet-650);
  --accent-wash: var(--violet-a12);
  --on-accent: var(--n-0);
  --ok: var(--green-600);
  --warn: var(--amber-600);
  --bad: var(--red-600);
  --on-bad: var(--n-0);
  --focus: var(--violet-600);
  --shadow: 0 1px 2px oklch(0.13 0.009 286 / 0.06);
  --backdrop: var(--n-1000-a50);

  --sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
}

/* Dark — the site's own surfaces. Written twice (system preference, explicit
   choice) because CSS cannot name one block for two conditions. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --surface: var(--n-950);
    --surface-raised: var(--n-850);
    --surface-sunken: var(--n-1000);
    --side: var(--n-900);
    --border: var(--n-700);
    --border-strong: var(--n-500);
    --text: var(--n-200);
    --text-muted: var(--n-400);
    --accent: var(--violet-400);
    --accent-hover: var(--violet-300);
    --accent-text: var(--violet-300);
    --accent-wash: var(--violet-a20);
    --on-accent: var(--n-1000);
    --ok: var(--green-400);
    --warn: var(--amber-400);
    --bad: var(--red-400);
    --on-bad: var(--n-1000);
    --focus: var(--violet-300);
    --shadow: none;
    --backdrop: var(--n-1000-a70);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --surface: var(--n-950);
  --surface-raised: var(--n-850);
  --surface-sunken: var(--n-1000);
  --side: var(--n-900);
  --border: var(--n-700);
  --border-strong: var(--n-500);
  --text: var(--n-200);
  --text-muted: var(--n-400);
  --accent: var(--violet-400);
  --accent-hover: var(--violet-300);
  --accent-text: var(--violet-300);
  --accent-wash: var(--violet-a20);
  --on-accent: var(--n-1000);
  --ok: var(--green-400);
  --warn: var(--amber-400);
  --bad: var(--red-400);
  --on-bad: var(--n-1000);
  --focus: var(--violet-300);
  --shadow: none;
  --backdrop: var(--n-1000-a70);
}

/* ─────────────────────────────────────────────────────────── 3. COMPONENT ── */

:root {
  --side-width: 16rem;
  --row-height: 3rem; /* 48px — the 40-48px band DENSITY 55 asks for */
  --control-height: 2.5rem; /* 40px controls, one height across every form */
  --icon: 1.125rem; /* 18px, the family's icon size beside 16px text */
  --card-radius: var(--radius-lg);
  --button-radius: var(--radius-pill); /* the product site's buttons are pills */
  --card-inset: var(--s-6);
  --control-radius: var(--radius-md);
  --page-inset: var(--s-7);
  --stack: var(--s-6); /* between cards and sections */
  --page-max: 80rem;
  --measure: 65ch;
  --icon: 1.125rem;
}

/* ≤768px: DENSITY 65, body never under 16px, targets taller, sidebar on top. */
@media (max-width: 48rem) {
  :root {
    --dial-density: 50;
    --row-height: 3rem;
    --control-height: 2.75rem; /* 44px touch targets */
    --card-inset: var(--s-5);
    --page-inset: var(--s-4);
    --stack: var(--s-5);
  }
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --dial-motion: 0;
    --dur-fast: 0ms;
    --dur-press: 0ms;
  }
}


/* ──────────────────────────────────────────────────────────────── base ── */

*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  margin: 0;
  min-height: 100dvh;
  display: grid;
  grid-template-rows: 1fr auto;
  background: var(--surface);
  color: var(--text);
  font-family: var(--sans);
  font-size: var(--t-body);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

/* Tracking tightens as size grows; leading loosens as size falls. */
h1 {
  margin: 0;
  font-size: var(--t-heading);
  line-height: 1.2;
  font-weight: 650;
  letter-spacing: -0.02em;
}

h2 {
  margin: 0 0 var(--s-5);
  font-size: var(--t-caption);
  line-height: 1.4;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

p {
  margin: 0 0 var(--s-2);
}

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

code {
  font-family: var(--mono);
  font-size: 0.92em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

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

/* `hidden` must win over the display a control's own rule sets. */
[hidden] {
  display: none !important;
}

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

.hint {
  font-size: var(--t-caption);
  line-height: 1.4;
  letter-spacing: 0.01em;
  margin: 0;
}

.icon {
  inline-size: var(--icon);
  block-size: var(--icon);
  flex: none;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip {
  position: absolute;
  inset-inline-start: var(--s-2);
  inset-block-start: -10rem;
  padding: var(--s-2) var(--s-3);
  background: var(--surface-raised);
  border-radius: var(--control-radius);
  z-index: var(--z-toast);
}

.skip:focus {
  inset-block-start: var(--s-2);
}


/* ─────────────────────────────────────────────────────────────── shell ── */

.shell {
  display: grid;
  grid-template-columns: var(--side-width) minmax(0, 1fr);
  min-height: 0;
  /* The sidebar's colour and edge run the whole height of a long page, while
     the sidebar itself stays pinned to the viewport. */
  background: linear-gradient(
    to right,
    var(--side) calc(var(--side-width) - 1px),
    var(--border) calc(var(--side-width) - 1px),
    var(--border) var(--side-width),
    transparent var(--side-width)
  );
}

.side {
  position: sticky;
  inset-block-start: 0;
  z-index: var(--z-sticky);
  align-self: start;
  block-size: 100dvh;
  display: flex;
  flex-direction: column;
  gap: var(--s-5);
  padding: var(--s-6) var(--s-4);
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin: 0;
  padding-inline: var(--s-3);
  font-weight: 650;
}

/* The product, and under it the company whose records are open: the one place the page says which company it is.
   A rule closes the block, so the company reads as the context the sections below act in. Everything in the sidebar
   shares one inline inset, the nav's. */
.identity {
  display: grid;
  gap: var(--s-5);
  padding-block-end: var(--s-5);
  border-block-end: 1px solid var(--border);
}

.workspace {
  display: grid;
  gap: var(--s-1);
  padding-inline: var(--s-3);
}

.workspace[hidden] {
  display: none;
}

.workspace .caption,
.account .caption {
  margin: 0;
  font-size: var(--t-caption);
  line-height: 1.4;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.company {
  margin: 0;
  font-weight: 600;
  line-height: 1.35;
  color: var(--text);
  overflow-wrap: anywhere;
}

.brand b {
  color: var(--accent-text);
}

.logo {
  inline-size: 1.75rem;
  block-size: 1.75rem;
}

.side nav {
  display: grid;
  gap: var(--s-1);
}

.side nav a {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  min-block-size: var(--control-height);
  padding: 0 var(--s-3);
  border-radius: var(--control-radius);
  color: var(--text-muted);
  text-decoration: none;
  font-weight: 500;
  transition: background-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}

.side nav a:hover {
  color: var(--text);
  background: var(--surface-sunken);
}

.side nav a[aria-current] {
  color: var(--accent-text);
  background: var(--accent-wash);
}

.side-foot {
  margin-block-start: auto;
  display: grid;
  gap: var(--s-1);
}

/* Who is signed in, above the controls that act on their session. */
.account {
  display: grid;
  gap: var(--s-1);
  padding: 0 var(--s-3) var(--s-3);
  margin-block-end: var(--s-2);
  border-block-end: 1px solid var(--border);
}

.account[hidden] {
  display: none;
}

.account p {
  margin: 0;
  overflow-wrap: anywhere;
}

.account-name {
  font-weight: 550;
  line-height: 1.35;
  color: var(--text);
}

.account-email {
  font-size: var(--t-caption);
  line-height: 1.4;
  color: var(--text-muted);
}

.side-foot button {
  justify-content: flex-start;
  gap: var(--s-3);
  padding-inline: var(--s-3);
}

main {
  padding: var(--page-inset);
  min-inline-size: 0;
  max-inline-size: var(--page-max);
}

main:focus,
.view-title:focus {
  /* Focus lands here after a route change so a screen reader starts at the
     new view; neither is a control, so there is no ring to show. */
  outline: none;
}

.foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: var(--s-2) var(--s-4);
  padding: var(--s-4) var(--page-inset);
  border-block-start: 1px solid var(--border);
  color: var(--text-muted);
  font-size: var(--t-caption);
}

.foot p {
  margin: 0;
}

/* On a wide screen the menu button is not needed and the menu's wrapper does not exist for layout. */
.menu-toggle {
  display: none;
}

.side-menu {
  display: contents;
}

@media (max-width: 48rem) {
  .shell {
    grid-template-columns: minmax(0, 1fr);
    align-content: start;
    background: none;
  }

  /* A phone gets one bar: the company it is working in, readable at a glance, and the menu button beside it. */
  .side {
    block-size: auto;
    padding: var(--s-2) var(--s-4);
    padding-inline-end: max(var(--s-4), env(safe-area-inset-right));
    padding-inline-start: max(var(--s-4), env(safe-area-inset-left));
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s-2);
    background: var(--side);
    border-block-end: 1px solid var(--border);
  }

  .identity {
    flex: 1 1 0;
    min-inline-size: 0;
    gap: 0;
    padding-block-end: 0;
    border-block-end: 0;
  }

  /* Once a company is open its name is the bar's title, and the product's name steps back. */
  .identity:has(.workspace:not([hidden])) {
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    column-gap: var(--s-2);
  }

  .identity:has(.workspace:not([hidden])) .brand > span,
  .workspace .caption {
    display: none;
  }

  .workspace {
    padding-inline: 0;
  }

  .workspace .company {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 650;
  }

  .menu-toggle {
    display: inline-flex;
    min-inline-size: 44px;
    min-block-size: 44px;
  }

  .side-menu {
    display: none;
    flex-basis: 100%;
    flex-direction: column;
    gap: var(--s-3);
    padding-block: var(--s-2) var(--s-3);
  }

  .side[data-open] .side-menu {
    display: flex;
  }

  .side-menu nav a,
  .side-foot button {
    min-block-size: 44px;
  }

  .side-foot {
    margin-block-start: 0;
    padding-block-start: var(--s-3);
    border-block-start: 1px solid var(--border);
  }
}

/* ─────────────────────────────────────────────────────────── page header ── */

.page-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  margin-block-end: var(--s-7);
}

/* Icon actions sit level with the title's line, not between the title and the line under it. */
.page-head:has(> .actions > .icon-action) {
  align-items: flex-start;
}

.page-head > .actions:has(> .icon-action) {
  margin-block-start: calc((var(--t-heading) * 1.2 - var(--control-height)) / 2);
}

.page-head .lede {
  margin: var(--s-2) 0 0;
  max-inline-size: var(--measure);
  color: var(--text-muted);
}


/* ─────────────────────────────────────────────────────────────── forms ── */

/* Cards, fields, choices, buttons and the sign-in gate, the same as the TessariDB S3 console's, so a person who uses
   both meets one set of controls. Values come from the semantic and component tiers only. */

.card {
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--card-radius);
  box-shadow: var(--shadow);
  padding: var(--card-inset);
  margin-block-end: var(--stack);
}

/* One column that may be narrower than what it holds, so a wide control (a file picker) shrinks instead of pushing the
   page sideways on a phone. */
.field {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s-2);
  margin-block-end: var(--s-5);
  max-inline-size: 32rem;
}


.segmented {
  display: inline-flex;
  min-block-size: var(--control-height);
  padding: 3px;
  gap: 2px;
  border: 1px solid var(--border);
  border-radius: var(--control-radius);
  background: var(--surface);
}

.segmented input {
  position: absolute;
  opacity: 0;
  inline-size: 1px;
  block-size: 1px;
  margin: 0;
}

.segmented label {
  display: inline-flex;
  align-items: center;
  padding: 0 var(--s-3);
  border-radius: calc(var(--control-radius) - 3px);
  font-weight: 500;
  color: var(--text-muted);
  cursor: pointer;
  white-space: nowrap;
}

.segmented input:checked + label {
  background: var(--surface-raised);
  color: var(--text);
  font-weight: 600;
  box-shadow: 0 1px 2px oklch(0 0 0 / 0.12);
}

.segmented input:focus-visible + label {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}


label {
  font-weight: 600;
  font-size: var(--t-data);
}

input,
select,
textarea {
  font: inherit;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--control-radius);
  padding: var(--s-2) var(--s-3);
  min-block-size: var(--control-height);
  transition: border-color var(--dur-fast) var(--ease);
}

input:hover,
select:hover,
textarea:hover {
  border-color: var(--border-strong);
}

input[aria-invalid="true"],
textarea[aria-invalid="true"] {
  border-color: var(--bad);
}

button,
.button {
  font: inherit;
  font-weight: 550;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-block-size: var(--control-height);
  padding: 0 var(--s-5);
  border-radius: var(--button-radius);
  border: 1px solid var(--border);
  background: var(--surface-raised);
  color: var(--text);
  text-decoration: none;
  cursor: pointer;
  touch-action: manipulation;
  transition:
    background-color var(--dur-fast) var(--ease),
    border-color var(--dur-fast) var(--ease),
    transform var(--dur-press) var(--ease-out);
}

/* Press feedback on everything pressable. */
button:active,
.button:active {
  transform: scale(0.97);
}

@media (hover: hover) and (pointer: fine) {
  button:hover,
  .button:hover {
    background: var(--surface-sunken);
  }
}

button:disabled {
  opacity: 0.6;
  cursor: progress;
}

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

button.primary:hover,
.button.primary:hover {
  background: var(--accent-hover);
}


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

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

/* A row action shown as its icon alone: its accessible name says the action and the row, its tooltip the action. */

.message.bad {
  color: var(--bad);
  margin-block-start: var(--s-3);
  max-inline-size: var(--measure);
}

/* Signing in is the only thing on the page, so it sits in the middle of it. */
.gate {
  display: grid;
  place-items: center;
  min-block-size: 85dvh;
}

.gate .card {
  inline-size: min(100%, 25rem);
  padding: var(--s-6) var(--s-5);
  text-align: center;
}

.gate .field {
  max-inline-size: none;
  text-align: start;
}

.gate .logo {
  inline-size: 3rem;
  block-size: 3rem;
  margin-block-end: var(--s-3);
}

.gate h1 {
  margin-block-end: var(--s-2);
}

.gate button.link {
  border: none;
  background: none;
  padding: 0;
  color: var(--accent);
  text-decoration: underline;
}
.gate button.primary,
.gate .provider {
  inline-size: 100%;
  margin-block-start: var(--s-2);
}

.gate p.muted {
  margin-block: var(--s-3) var(--s-5);
}

/* Before signing in there is nothing to navigate: the sign-in card is the page. */
body.signed-out .side {
  display: none;
}

body.signed-out .shell {
  grid-template-columns: minmax(0, 1fr);
  background: none;
}

/* Windows high contrast and other forced palettes keep every boundary visible. */
@media (forced-colors: active) {
  button,
  .button,
  .card {
    border: 1px solid CanvasText;
  }
}

/* A choice of a few companies: radios with their labels, one per row, inside a fieldset whose legend names them. */
fieldset.choices {
  border: none;
  margin: 0 0 var(--s-5);
  padding: 0;
  text-align: start;
}

/* After a list or anything else that ends without a margin of its own, the choice still stands apart from it; after
   a field the two margins collapse into one, so nothing moves there. */
* + fieldset.choices {
  margin-block-start: var(--s-5);
}

fieldset.choices legend {
  font-weight: 600;
  font-size: var(--t-data);
  margin-block-end: var(--s-2);
}

.choice {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  min-block-size: var(--control-height);
}

.choice input {
  accent-color: var(--accent);
  inline-size: 1.125rem;
  block-size: 1.125rem;
  min-block-size: 0;
}

.choice label {
  font-weight: 500;
  font-size: var(--t-body);
}

/* After unlocking, what happened to the member's keys kept for recovery since they last looked: above the page, with
   the warning colour only on its edge, so the words carry the meaning. */
.notice-banner {
  margin-block-end: var(--s-5);
  padding: var(--s-4) var(--s-5);
  border: 1px solid var(--border);
  border-inline-start: 4px solid var(--warn);
  border-radius: var(--radius-md);
  background: var(--surface-raised);
  max-inline-size: var(--measure);
}

.notice-banner h2 {
  margin-block: 0 var(--s-2);
  font-size: var(--t-body);
}

.notice-banner ul {
  margin: 0 0 var(--s-3);
  padding-inline-start: var(--s-5);
}

.notice-banner p {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-4);
  margin: 0;
}

/* ──────────────────────────────────────────────────────────────── icons ── */

.icon {
  inline-size: var(--icon);
  block-size: var(--icon);
  flex: none;
}

/* An action shown as its icon alone: its accessible name says the action and what it acts on, its tooltip the action. */
button.icon-action,
.button.icon-action {
  inline-size: var(--control-height);
  padding: 0;
  border-radius: var(--control-radius);
  background: transparent;
  border-color: transparent;
  color: var(--text-muted);
}

button.icon-action.danger {
  background: transparent;
  border-color: transparent;
  color: var(--bad);
}

button.icon-action[aria-pressed="true"] {
  color: var(--accent-text);
}

@media (hover: hover) and (pointer: fine) {
  button.icon-action:hover,
  .button.icon-action:hover {
    background: var(--surface-sunken);
    color: var(--text);
  }

  button.icon-action.danger:hover {
    color: var(--bad);
  }
}

.actions:has(> .icon-action) {
  flex-wrap: nowrap;
  gap: var(--s-1);
}

/* The one tooltip, placed over the page by script so nothing scrolling can clip it. */
.tip {
  position: fixed;
  z-index: var(--z-toast);
  pointer-events: none;
  padding: var(--s-1) var(--s-2);
  border-radius: var(--radius-sm);
  background: var(--text);
  color: var(--surface);
  font-size: var(--t-data);
  font-weight: 550;
  white-space: nowrap;
  opacity: 0;
  transform: scale(0.97);
  transform-origin: center bottom;
  transition:
    opacity 125ms var(--ease-out),
    transform 125ms var(--ease-out);
}

.tip[data-side="below"] {
  transform-origin: center top;
}

.tip[data-open] {
  opacity: 1;
  transform: none;
}

.tip[data-instant] {
  transition-duration: 0ms;
}

@media (prefers-reduced-motion: reduce) {
  .tip {
    transform: none;
    transition-duration: 0ms;
  }
}

/* ───────────────────────────────────────────────────────────── records ── */

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin-block: var(--s-3);
}

button.chip {
  min-block-size: 32px;
  padding: 0 var(--s-4);
  border-radius: var(--radius-pill);
  font-weight: 500;
  color: var(--text-muted);
}

button.chip[aria-pressed="true"] {
  background: var(--accent-wash);
  border-color: var(--accent);
  color: var(--accent-text);
  font-weight: 600;
}

.records {
  list-style: none;
  margin: var(--s-3) 0 0;
  padding: 0;
  border-block-start: 1px solid var(--border);
}

.record {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  gap: var(--s-4);
  min-block-size: var(--row-height);
  padding-block: var(--s-2);
  border-block-end: 1px solid var(--border);
}

.record-title {
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 550;
}

.record.unreadable {
  grid-template-columns: minmax(0, 1fr) auto;
}

.record.unreadable .message {
  grid-column: 1 / -1;
  margin-block: 0;
}

/* The trail above a record page's heading. The separator is a drawn chevron rather than a character, so a screen
   reader hears only the steps; it turns with the reading direction. */
.crumbs ol {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  margin: 0 0 var(--s-3);
  padding: 0;
  list-style: none;
  font-size: var(--t-data);
  color: var(--text-muted);
}

.crumbs li {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  min-width: 0;
}

.crumbs li + li::before {
  content: "";
  inline-size: 0.4em;
  block-size: 0.4em;
  border-block-start: 1.5px solid currentColor;
  border-inline-end: 1.5px solid currentColor;
  transform: rotate(45deg);
}

.crumbs li:dir(rtl) + li::before {
  transform: rotate(-45deg);
}

.crumbs a {
  text-decoration: none;
}

.crumbs a:hover {
  text-decoration: underline;
}

.crumbs [aria-current] {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text);
}

.record-section {
  margin-block-start: var(--s-6);
}

/* A section's action sits as far under a line of words or a row of chips as under a field. */
.record-section > :is(p, .chips):has(+ button) {
  margin-block-end: var(--s-5);
}

/* A record's fields read as a table: one row per field, a label column, and the value with its actions pushed to the
   row's end, so every Copy sits in one column. Each row is one line box tall and centred on it, whatever it holds. */
.fields {
  display: grid;
  grid-template-columns: minmax(9rem, 12rem) minmax(0, 1fr);
  margin: 0;
  border-block-start: 1px solid var(--border);
}

.fields dt,
.fields dd {
  display: flex;
  align-items: center;
  min-block-size: var(--row-height);
  padding-block: var(--s-1);
  border-block-end: 1px solid var(--border);
}

.fields dt {
  color: var(--text-muted);
  padding-inline-end: var(--s-4);
}

.fields dd {
  flex-direction: column;
  align-items: stretch;
  justify-content: center;
  gap: var(--s-1);
  margin: 0;
  min-inline-size: 0;
}

.fields dd > p {
  margin: 0;
}

.value-row {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  min-block-size: var(--control-height);
}

.row-actions {
  display: flex;
  align-items: center;
  gap: var(--s-1);
  margin-inline-start: auto;
}

.value {
  min-inline-size: 0;
  overflow-wrap: anywhere;
}

/* Keys, fingerprints and codes are one long token each; they break anywhere rather than push the page sideways. */
.mono {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.pre {
  white-space: pre-wrap;
}

@media (max-width: 48rem) {
  .record {
    grid-template-columns: minmax(0, 1fr) auto;
  }

  .record > :last-child {
    grid-column: 1 / -1;
  }

  .fields {
    grid-template-columns: minmax(0, 1fr);
  }

  .fields dt {
    min-block-size: 0;
    padding-block: var(--s-3) 0;
    border-block-end: 0;
  }
}

.actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
}

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

/* The one confirm the records pages ask: it names the record and says what stays behind. */
dialog.confirm {
  inline-size: min(100% - 2 * var(--s-4), 30rem);
  padding: var(--s-6);
  border: 1px solid var(--border);
  border-radius: var(--card-radius);
  background: var(--surface-raised);
  color: var(--text);
  box-shadow: var(--shadow);
}

dialog.confirm::backdrop {
  background: var(--backdrop);
}

/* The dialog's title names the record, so it reads as a title rather than a section label. */
dialog.confirm h2 {
  margin-block: 0 var(--s-3);
  font-size: var(--t-body);
  font-weight: 650;
  color: var(--text);
  text-transform: none;
  letter-spacing: normal;
}

dialog.confirm .actions {
  justify-content: flex-end;
  margin-block-start: var(--s-5);
}

/* Where the rows will be while the first page loads; still, so there is nothing to reduce. */
.skeleton .bone {
  display: block;
  inline-size: 40%;
  block-size: 1rem;
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
}

/* Whom a record can be shared with: a list that scrolls inside the dialog once it is longer than a few rows. */
.targets {
  max-block-size: 16rem;
  overflow-y: auto;
  padding-inline-end: var(--s-2);
}

.choice label .detail,
.share .detail {
  display: block;
  font-weight: 400;
  font-size: var(--t-caption);
  color: var(--text-muted);
}

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

.shares {
  list-style: none;
  margin: 0;
  padding: 0;
  border-block-start: 1px solid var(--border);
}

.share {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  gap: var(--s-4);
  min-block-size: var(--row-height);
  padding-block: var(--s-2);
  border-block-end: 1px solid var(--border);
}

.share-name {
  font-weight: 550;
}

/* A key's fingerprint, read aloud group by group: monospaced so the groups line up when two people compare them. */
.fingerprint {
  font-family: var(--mono);
  font-size: var(--t-body);
  letter-spacing: 0.04em;
  overflow-wrap: anywhere;
}

/* The author's own fields: each with its remove button level with the input, then a row that opens to add one. */
.input-line {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  max-inline-size: calc(32rem + var(--control-height) + var(--s-2));
}

.custom-row > .field {
  max-inline-size: calc(32rem + var(--control-height) + var(--s-2));
}

.input-line > input {
  flex: 1;
  min-inline-size: 0;
}

/* A field whose control is a group rather than one input names it the way a label names an input. */
.field-label {
  margin: 0;
  font-weight: 600;
  font-size: var(--t-data);
}

/* An SSH key in the edit form: its public line and fingerprint, wrapped rather than scrolled. */
.ssh-key {
  display: grid;
  gap: var(--s-1);
}

.ssh-key p {
  margin: 0;
  overflow-wrap: anywhere;
}

/* An edit form's groups read like the record page's sections: no box, a caption for a heading. */
form fieldset.record-section {
  margin: var(--s-5) 0 0;
  padding: 0 0 var(--s-2);
  border: 0;
  border-block-end: 1px solid var(--border);
  min-inline-size: 0;
}

form fieldset.record-section > legend {
  margin-block-end: var(--s-4);
  padding: 0;
  font-size: var(--t-caption);
  line-height: 1.4;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
}

form > .record-section ~ button[type="submit"] {
  margin-block-start: var(--s-6);
}

button.add-field {
  justify-content: flex-start;
  gap: var(--s-2);
  padding-inline: var(--s-3);
}

.custom-add {
  display: grid;
  gap: var(--s-3);
  padding: var(--s-4);
  border: 1px solid var(--border);
  border-radius: var(--control-radius);
  background: var(--surface-raised);
}

.custom-add[hidden] {
  display: none;
}

.custom-add .field,
.custom-add .chips,
.custom-add .actions {
  margin: 0;
}

/* ─────────────────────────────────────────────────────────────── tables ── */

/* Above a list: the search box and the filter chips on one band, wrapping on a narrow screen. */
.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--s-3) var(--s-5);
  margin-block-end: var(--s-5);
}

.toolbar .field.search {
  flex: 1 1 18rem;
  max-inline-size: 28rem;
  margin: 0;
}

.search-box {
  position: relative;
  display: block;
}

.search-box > .icon {
  position: absolute;
  inset-inline-start: var(--s-3);
  inset-block-start: 50%;
  translate: 0 -50%;
  color: var(--text-muted);
  pointer-events: none;
}

.search-box > input {
  inline-size: 100%;
  padding-inline-start: calc(var(--s-3) + var(--icon) + var(--s-2));
}

.filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2) var(--s-4);
}

.filters .chips {
  margin: 0;
}

/* The records list as a table: a header row naming the columns, one row per record, the title the link. */
table.records {
  inline-size: 100%;
  border-collapse: collapse;
}

table.records th {
  padding: var(--s-2) var(--s-3);
  font-size: var(--t-caption);
  line-height: 1.4;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-align: start;
  color: var(--text-muted);
  border-block-end: 1px solid var(--border);
}

table.records td {
  block-size: var(--row-height);
  padding: var(--s-2) var(--s-3);
  vertical-align: middle;
  border-block-end: 1px solid var(--border);
}

table.records th:first-child,
table.records td:first-child {
  padding-inline-start: 0;
}

table.records td:first-child {
  inline-size: 60%;
  max-inline-size: 0;
}

table.records .when {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

table.records .record-title {
  display: block;
  color: var(--text);
  text-decoration: none;
}

@media (hover: hover) and (pointer: fine) {
  table.records tbody tr:hover {
    background: var(--surface-sunken);
  }

  table.records a.record-title:hover {
    color: var(--accent-text);
    text-decoration: underline;
  }
}

table.records .message {
  margin: var(--s-1) 0 0;
}

@media (max-width: 48rem) {
  table.records td:nth-child(2),
  table.records th:nth-child(2) {
    display: none;
  }
}

/* A member row: who, their role, their key's state, and Vouch where it is offered. */
.shares,
.share.member {
  --member-columns: minmax(0, 1fr) minmax(5rem, 8rem) auto minmax(4.5rem, auto);
}

.share.member {
  grid-template-columns: var(--member-columns);
}

/* The rows share the list's columns, so roles and key states line up from one person to the next. */
@media (min-width: 48.01rem) {
  .shares:has(> .share.member) {
    display: grid;
    grid-template-columns: var(--member-columns);
  }

  .shares > .share.member {
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
  }
}

/* A key's state as a badge: its words carry the meaning, the dot's colour only repeats it. */
.state {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  justify-self: start;
  padding: var(--s-1) var(--s-3);
  border-radius: var(--radius-pill);
  background: var(--surface-sunken);
  font-size: var(--t-data);
  white-space: nowrap;
  color: var(--text);
}

.state::before {
  content: "";
  inline-size: 0.5rem;
  block-size: 0.5rem;
  border-radius: 50%;
  background: var(--text-muted);
}

.state.vouched::before {
  background: var(--ok);
}

.state.waiting::before {
  background: var(--warn);
}

@media (max-width: 48rem) {
  .share.member {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--s-2);
    padding-block: var(--s-3);
  }

  .share.member > :nth-child(2) {
    display: none;
  }
}

/* A team sits under its department, and both under the company. */
.share.group[data-depth="1"] {
  padding-inline-start: var(--s-5);
}

.share.group[data-depth="2"] {
  padding-inline-start: var(--s-8);
}

.share.group > [aria-live] {
  grid-column: 1 / -1;
}

/* Like the members list, the rows share the list's columns, so key states line up whether or not a row has buttons. */
@media (min-width: 48.01rem) {
  .shares:has(> .share.group) {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto;
  }

  .shares:has(> .share.group):not(:has(.row-actions:not(:empty))) {
    grid-template-columns: minmax(0, 1fr) auto;
  }

  .shares > .share.group {
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
  }
}

.share.group .row-actions:empty {
  display: none;
}

.share.group .row-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  justify-content: flex-end;
}

/* On a phone the buttons go under the name and its key state, which would otherwise have no width left. */
@media (max-width: 48rem) {
  .share.group {
    grid-template-columns: minmax(0, 1fr) auto;
    row-gap: var(--s-2);
  }

  .share.group .row-actions {
    grid-column: 1 / -1;
    justify-content: flex-start;
    margin-inline-start: 0;
  }
}

/* A department's or team's name opens its own page, the way a record's title does in the records list. */
a.share-name {
  color: var(--text);
  text-decoration: none;
}

@media (hover: hover) and (pointer: fine) {
  a.share-name:hover {
    color: var(--accent-text);
    text-decoration: underline;
  }
}

/* The trail as a table of the same grammar: when, who, what, on whom or what, and why. Times keep their width. */
table.trail td:first-child {
  inline-size: auto;
  max-inline-size: none;
}

/* Wider than its column, a table scrolls inside its own frame and the page does not. */
.table-frame {
  overflow-x: auto;
}

.table-frame + button {
  margin-block-start: var(--s-5);
}

/* On a phone each event reads as a short stack: what happened, to whom or what and by whom, then when and why. */
@media (max-width: 48rem) {
  table.trail thead {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }

  table.trail tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: var(--s-3);
    padding-block: var(--s-3);
    border-block-end: 1px solid var(--border);
  }

  table.trail td:nth-child(n) {
    display: block;
    block-size: auto;
    padding: 0;
    border: 0;
  }

  table.trail td:nth-child(3) {
    grid-area: 1 / 1 / 2 / -1;
    font-weight: 550;
  }

  table.trail td:nth-child(4) {
    grid-area: 2 / 1;
  }

  table.trail td:nth-child(2) {
    grid-area: 2 / 2;
    color: var(--text-muted);
  }

  table.trail td:nth-child(1),
  table.trail td:nth-child(5) {
    grid-column: 1 / -1;
    font-size: var(--t-caption);
    color: var(--text-muted);
  }
}
