/* The Refractory — design system.
 *
 * White/light workspace, fine neutral borders, generous whitespace, strong
 * black/white contrast. Purple is reserved for primary actions, AI state,
 * selection, focus and key progress. No gradients, no glows.
 */

:root {
  --lab-bg: #f7f7f8;
  --lab-surface: #ffffff;
  --lab-surface-raised: #fbfbfc;
  --lab-text: #111113;
  --lab-text-muted: #6f6f78;
  --lab-text-faint: #96969e;
  --lab-border: rgba(17, 17, 19, 0.10);
  --lab-border-strong: rgba(17, 17, 19, 0.16);

  --brand-magenta: #ec08ee;
  --brand-cyan: #11e2e2;
  --brand-green: #4fe7a7;

  --lab-purple: #6c4cf1;
  --lab-purple-hover: #5839dc;
  --lab-purple-active: #4527c5;
  --lab-purple-subtle: #f0edff;

  --lab-success: #2e7d4f;
  --lab-warning: #a76510;
  --lab-danger: #b33a44;

  --lab-radius: 6px;
  --lab-radius-sm: 4px;
  --lab-nav-width: 232px;
  --lab-nav-breakpoint: 900px;

  --font-sans: "Satoshi", "General Sans", -apple-system, BlinkMacSystemFont,
    "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  /* Headings and short labels only - never body text or tables.
     Space Grotesk was drawn from Space Mono, so it sits naturally beside the
     JetBrains Mono carrying the labels and SKUs, and it stays technical
     without the squared-off, heavy letterforms that read as robotic.
     Change the family here and everywhere follows. Self-hosted; see
     scripts/fetch_display_font.py. */
  --font-display: "Space Grotesk", "Segoe UI", system-ui, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, "SF Mono",
    Menlo, Consolas, monospace;
}

[data-theme="dark"] {
  --lab-bg: #0a0a0b;
  --lab-surface: #111113;
  --lab-surface-raised: #171719;
  --lab-text: #f7f7f8;
  --lab-text-muted: #acacb5;
  --lab-text-faint: #75757e;
  --lab-border: rgba(255, 255, 255, 0.11);
  --lab-border-strong: rgba(255, 255, 255, 0.18);

  --lab-purple: #8b72ff;
  --lab-purple-hover: #a08cff;
  --lab-purple-active: #b4a5ff;
  --lab-purple-subtle: #25213d;

  --lab-success: #4fae76;
  --lab-warning: #d08a2c;
  --lab-danger: #e0656f;
}

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--lab-bg);
  color: var(--lab-text);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--lab-purple); text-decoration: none; }
a:hover { text-decoration: underline; }

:focus-visible {
  outline: 2px solid var(--lab-purple);
  outline-offset: 2px;
  border-radius: var(--lab-radius-sm);
}

.mono {
  font-family: var(--font-mono);
  font-size: 0.875em;
  letter-spacing: -0.01em;
}

/* -- layout ------------------------------------------------------------- */

.lab-shell {
  display: grid;
  grid-template-columns: var(--lab-nav-width) 1fr;
  min-height: 100vh;
}

.lab-nav {
  background: var(--lab-surface);
  border-right: 1px solid var(--lab-border);
  padding: 0 12px 20px;
  display: flex;
  flex-direction: column;
  gap: 22px;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}

/* The mark and the name, then a rule. Without the rule the lockup read as the
   first item in the menu rather than as the thing the menu belongs to. */
.lab-nav__head {
  padding: 20px 10px 18px;
  margin: 0 -12px;
  padding-left: 22px;
  padding-right: 22px;
  border-bottom: 1px solid var(--lab-border);
}
.lab-brand {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  color: inherit;
  text-decoration: none;
}
.lab-brand:hover { text-decoration: none; }
.lab-brand:hover .lab-brand__name { color: var(--lab-purple); }
.lab-brand .lab-mark { height: 40px; }

/* The wordmark ships in two tones because inverting one in CSS would take the
   gradient R with it. See scripts/prepare_brand_assets.py. */
.lab-wordmark { display: block; width: 100%; max-width: 172px; height: auto; }
.lab-mark { display: block; width: auto; height: 26px; }
.lab-wordmark--dark, .lab-mark--dark { display: none; }
[data-theme="dark"] .lab-wordmark--light,
[data-theme="dark"] .lab-mark--light { display: none; }
[data-theme="dark"] .lab-wordmark--dark,
[data-theme="dark"] .lab-mark--dark { display: block; }

/* The mark beside the application name. Spans, so the whole lockup can sit
   inside one anchor. */
.lab-lockup {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
}
.lab-lockup .lab-mark { height: 30px; flex: none; }
.lab-lockup__name {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.01em;
  white-space: nowrap;
}

.lab-brand__name {
  display: block;
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.015em;
  margin: 0;
}
.lab-brand__tagline {
  display: block;
  margin-top: 10px;
  font-size: 12px;
  color: var(--lab-text-muted);
  margin: 3px 0 0;
  line-height: 1.35;
}
.lab-brand__sub {
  display: block;
  font-size: 11px;
  color: var(--lab-text-faint);
  font-style: italic;
  margin: 2px 0 0;
}

.lab-nav__group { display: flex; flex-direction: column; gap: 1px; }

/* Every group after the first is fenced off by a rule rather than by more
   whitespace, which at this width just made the column look unfinished. */
.lab-nav__group + .lab-nav__group {
  border-top: 1px solid var(--lab-border);
  padding-top: 20px;
  margin-top: -2px;
}

/* Mono at its natural weight, widely tracked. The display face at 600 was
   heavier than the links it was labelling, which put the emphasis in the
   wrong place. */
.lab-nav__label {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.13em;
  color: var(--lab-text-faint);
  padding: 0 10px 8px;
}
.lab-nav__link {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 10px;
  border-radius: var(--lab-radius-sm);
  font-size: 14px;
  color: var(--lab-text);
  text-decoration: none;
}
.lab-nav__link:hover { background: var(--lab-surface-raised); text-decoration: none; }
.lab-nav__link[aria-current="page"] {
  background: var(--lab-purple-subtle);
  color: var(--lab-purple);
  font-weight: 500;
}
.lab-nav__link--muted { color: var(--lab-text-faint); }
.lab-nav__count {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--lab-text-faint);
}

/* Stroked, sized in the box and coloured from the text, so an icon takes the
   state of the link it belongs to - muted, current, hovered - for free. */
.lab-nav__icon {
  width: 16px;
  height: 16px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.75;
}
.lab-nav__link[aria-current="page"] .lab-nav__icon { opacity: 1; }

.lab-nav__footer {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-top: auto;
  padding-top: 14px;
  border-top: 1px solid var(--lab-border);
}
.lab-nav__footer form { display: flex; }

.lab-user {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 1 1 auto;
  min-width: 0;
  padding: 7px 10px;
  border-radius: var(--lab-radius-sm);
  color: var(--lab-text);
  text-decoration: none;
  min-width: 0;
}
.lab-user:hover { background: var(--lab-surface-raised); text-decoration: none; }
.lab-user[aria-current="page"] { background: var(--lab-purple-subtle); }

.lab-user__avatar {
  display: grid;
  place-items: center;
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  /* The colour is set per user from the template; white sits on all six. */
  color: #fff;
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.02em;
}
.lab-user__name {
  font-size: 13.5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.lab-user__out {
  display: grid;
  place-items: center;
  flex: none;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 0;
  border-radius: var(--lab-radius-sm);
  background: none;
  color: var(--lab-text-faint);
  cursor: pointer;
}
.lab-user__out:hover { background: var(--lab-surface-raised); color: var(--lab-text); }

.lab-main { display: flex; flex-direction: column; min-width: 0; }

.lab-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 20px 32px;
  border-bottom: 1px solid var(--lab-border);
  background: var(--lab-surface);
}
.lab-header__titles { min-width: 0; }
.lab-header__title {
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 600;
  margin: 0;
  letter-spacing: -0.02em;
}
.lab-header__meta { font-size: 13px; color: var(--lab-text-muted); margin: 2px 0 0; }
.lab-header__actions { display: flex; align-items: center; gap: 8px; }

.lab-content { padding: 28px 32px 64px; }

/* -- components --------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 36px;
  padding: 0 14px;
  border-radius: var(--lab-radius);
  border: 1px solid var(--lab-border-strong);
  background: var(--lab-surface);
  color: var(--lab-text);
  font: inherit;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  text-decoration: none;
}
.btn:hover { background: var(--lab-surface-raised); text-decoration: none; }
.btn--primary {
  background: var(--lab-purple);
  border-color: var(--lab-purple);
  color: #fff;
}
.btn--primary:hover { background: var(--lab-purple-hover); border-color: var(--lab-purple-hover); }
.btn--primary:active { background: var(--lab-purple-active); }
.btn--ghost { border-color: transparent; background: transparent; }
.btn[disabled], .btn[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }

.card {
  background: var(--lab-surface);
  border: 1px solid var(--lab-border);
  border-radius: var(--lab-radius);
}
.card__header {
  padding: 14px 18px;
  border-bottom: 1px solid var(--lab-border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.card__title {
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 600;
  margin: 0;
}
.card__body { padding: 18px; }

.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px;
  margin-bottom: 24px;
}
.stat {
  background: var(--lab-surface);
  border: 1px solid var(--lab-border);
  border-radius: var(--lab-radius);
  padding: 16px 18px;
}
.stat__label {
  font-size: 12px;
  color: var(--lab-text-muted);
  margin: 0 0 6px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.stat__value {
  font-family: var(--font-display);
  font-size: 30px;
  font-weight: 500;
  line-height: 1;
  margin: 0;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.stat--attention .stat__value { color: var(--lab-warning); }
.stat--error .stat__value { color: var(--lab-danger); }

.table { width: 100%; border-collapse: collapse; font-size: 14px; }
.table th {
  text-align: left;
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--lab-text-muted);
  padding: 10px 14px;
  border-bottom: 1px solid var(--lab-border);
  white-space: nowrap;
}
.table td {
  padding: 11px 14px;
  border-bottom: 1px solid var(--lab-border);
  vertical-align: middle;
}
.table tbody tr:last-child td { border-bottom: none; }
.table tbody tr:hover { background: var(--lab-surface-raised); }
.table-wrap { overflow-x: auto; }

/* A block of explanation. Distinct from .badge, which is a pill: pills are
   sized by their content, so a paragraph in one renders as a large ellipse. */
.notice {
  display: block;
  padding: 10px 12px;
  border: 1px solid var(--lab-border-strong);
  border-radius: var(--lab-radius);
  background: var(--lab-surface-raised);
  font-size: 13px;
  line-height: 1.5;
  text-align: left;
  margin: 0 0 8px;
}
.notice:last-child { margin-bottom: 0; }
.notice--warning { border-color: var(--lab-warning); color: var(--lab-warning); }
.notice--danger { border-color: var(--lab-danger); color: var(--lab-danger); }

.badge {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid var(--lab-border-strong);
  font-size: 12px;
  font-weight: 500;
  white-space: nowrap;
}
.badge--purple { background: var(--lab-purple-subtle); border-color: transparent; color: var(--lab-purple); }
.badge--success { color: var(--lab-success); }
.badge--warning { color: var(--lab-warning); }
.badge--danger { color: var(--lab-danger); }
.badge--muted { color: var(--lab-text-muted); }

.empty {
  text-align: center;
  padding: 56px 24px;
  color: var(--lab-text-muted);
}
.empty__title {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 600;
  color: var(--lab-text);
  margin: 0 0 6px;
}
.empty__body { font-size: 14px; margin: 0 0 18px; }

.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; }
.field__label { font-size: 13px; font-weight: 500; }
.field__hint { font-size: 12px; color: var(--lab-text-muted); }
.field__error { font-size: 13px; color: var(--lab-danger); }
input[type="text"], input[type="email"], input[type="password"], input[type="search"],
input[type="number"], input[type="date"], input[type="tel"], input[type="url"],
select, textarea {
  font: inherit;
  font-size: 14px;
  padding: 8px 10px;
  min-height: 36px;
  border: 1px solid var(--lab-border-strong);
  border-radius: var(--lab-radius);
  background: var(--lab-surface);
  color: var(--lab-text);
  width: 100%;
}

.messages { list-style: none; padding: 0; margin: 0 0 20px; display: flex; flex-direction: column; gap: 8px; }
.messages li {
  padding: 10px 14px;
  border: 1px solid var(--lab-border-strong);
  border-radius: var(--lab-radius);
  background: var(--lab-surface);
  font-size: 14px;
}
.messages .error { border-color: var(--lab-danger); color: var(--lab-danger); }
.messages .success { border-color: var(--lab-success); color: var(--lab-success); }

.toolbar { display: flex; gap: 8px; align-items: center; margin-bottom: 18px; flex-wrap: wrap; }
.toolbar form { display: flex; gap: 8px; align-items: center; }
.toolbar input[type="search"], .toolbar select { width: auto; min-width: 180px; }

/* -- chromatic offset ----------------------------------------------------- */

/* A misregistered-print edge: the same shape stamped a pixel or two out in
   each of the subtractive and additive primaries. Borrowed from lambda.ai,
   built from the three colours in our own mark rather than their palette, so
   it reads as the Refracted gradient coming apart rather than as a copy.

   box-shadow rather than stacked elements: it costs no markup, cannot be
   selected or read out, and the browser composites it on the GPU. */
.chroma {
  box-shadow:
    1px 0 0 0 var(--brand-cyan),
    2px 1px 0 0 var(--brand-green),
    -1px 0 0 0 var(--brand-magenta),
    -2px -1px 0 0 var(--brand-magenta);
}
.chroma:hover {
  box-shadow:
    2px 0 0 0 var(--brand-cyan),
    3px 1px 0 0 var(--brand-green),
    -2px 0 0 0 var(--brand-magenta),
    -3px -1px 0 0 var(--brand-magenta);
}

/* -- auth ---------------------------------------------------------------- */

/* The sign-in screen is dark whatever the theme - it is the one screen with no
   work on it, so it can carry the brand - but the panel on it is white, and
   the mark inside the panel stays black. */
.auth {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  min-height: 100vh;
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: 24px;
  background: #0b0b0c;
  color: #e9e9ec;
}

.auth__bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}

/* Graph paper, faded out at the edges so it has no visible boundary. */
.auth__grid {
  position: absolute;
  inset: -1px;
  background-image:
    linear-gradient(to right, rgba(255, 255, 255, 0.05) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255, 255, 255, 0.05) 1px, transparent 1px);
  background-size: 40px 40px;
  -webkit-mask-image: radial-gradient(ellipse 80% 70% at 50% 50%, #000 25%, transparent 100%);
  mask-image: radial-gradient(ellipse 80% 70% at 50% 50%, #000 25%, transparent 100%);
}

/* The slot field. A pattern in user-space units, so one tile is the same size
   on a phone and on an ultrawide - nothing here scales with the viewport. */
.auth__slots {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
/* The slot outline only. Styling `.auth__slots rect` would also hit the rect
   that paints the pattern, and a CSS `fill` beats the `fill="url(#...)"`
   presentation attribute on it - which leaves the whole field invisible. */
.auth__slot {
  fill: none;
  stroke: rgba(255, 255, 255, 0.075);
  stroke-width: 1;
}
/* Faded out toward the edges so the field has no visible boundary and the eye
   is left in the middle, where the panel is. */
.auth__slots {
  -webkit-mask-image: radial-gradient(ellipse 62% 78% at 50% 50%, #000 0%, transparent 100%);
  mask-image: radial-gradient(ellipse 62% 78% at 50% 50%, #000 0%, transparent 100%);
}

/* The light under the bed, so the slots nearest the panel read as lit. Sized
   in viewport units from the centre, so it lands in the same place on any
   screen shape. */
.auth__lamp {
  position: absolute;
  top: 50%;
  left: 50%;
  width: min(1100px, 150vw);
  height: min(1100px, 150vh);
  transform: translate(-50%, -50%);
  background: radial-gradient(
    circle at 50% 50%,
    rgba(124, 92, 255, 0.13) 0%,
    rgba(124, 92, 255, 0.05) 38%,
    transparent 68%
  );
}

.auth__panel { width: 100%; max-width: 392px; }

/* Square corners, like the rest of this borrowed language. */
.auth__card {
  background: #fff;
  border: 0;
  border-radius: 0;
  box-shadow: 0 30px 70px rgba(0, 0, 0, 0.55);
}
.auth__card .card__body { padding: 34px 32px 32px; }

.auth__brand {
  text-align: center;
  margin-bottom: 26px;
}
/* Black mark on a white panel: the artwork as drawn, not an inversion of it. */
.auth__brand .lab-mark--light { display: block; margin: 0 auto; height: 54px; }
.auth__brand .lab-mark--dark { display: none; }

.auth__name {
  font-family: var(--font-display);
  font-size: 25px;
  font-weight: 600;
  letter-spacing: -0.015em;
  color: #111113;
  margin: 14px 0 0;
}
.auth__tagline {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: #74747f;
  margin: 9px 0 0;
  line-height: 1.6;
  /* Two even lines rather than a long one and an orphan. */
  text-wrap: balance;
}

/* The panel is white in both themes, so it does not inherit the dark tokens
   the rest of the application would hand it. */
.auth__card .field__label {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: #6f6f78;
}
.auth__card input[type="text"],
.auth__card input[type="email"],
.auth__card input[type="password"] {
  border-radius: 0;
  border-color: rgba(17, 17, 19, 0.22);
  background: #fff;
  color: #111113;
}
.auth__card input:focus {
  border-color: var(--lab-purple);
  outline: none;
  box-shadow: 0 0 0 2px rgba(108, 76, 241, 0.16);
}

.auth__division {
  margin: 18px 0 0;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.34);
}

.auth__submit {
  width: 100%;
  border-radius: 0;
  border: 0;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}

/* Each element arrives a beat after the one above it, once. --in is the
   position in the queue, set per element in the template. */
.auth__in {
  animation: auth-in 0.5s cubic-bezier(0.22, 0.7, 0.3, 1) backwards;
  animation-delay: calc(var(--in) * 70ms);
}
@keyframes auth-in {
  from { opacity: 0; transform: translateY(7px); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .auth__in { animation: none; }
}

/* -- phone chrome -------------------------------------------------------- */

/* Both hidden until the breakpoint; the drawer only exists on narrow screens. */
.lab-topbar { display: none; }
.lab-scrim { display: none; }

.lab-topbar__toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  margin-left: -9px; /* optical: aligns the bars with the content edge */
  flex: none;
  border: 0;
  border-radius: var(--lab-radius);
  background: none;
  color: var(--lab-text);
  cursor: pointer;
}
.lab-topbar__toggle:hover { background: var(--lab-surface-raised); }

/* Three bars from one element: the middle is the box, the others pseudo. */
.lab-topbar__bars,
.lab-topbar__bars::before,
.lab-topbar__bars::after {
  display: block;
  width: 18px;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
}
.lab-topbar__bars { position: relative; }
.lab-topbar__bars::before,
.lab-topbar__bars::after {
  content: "";
  position: absolute;
  left: 0;
}
.lab-topbar__bars::before { top: -6px; }
.lab-topbar__bars::after { top: 6px; }

.lab-topbar__brand {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
  color: var(--lab-text);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.01em;
  text-decoration: none;
}
.lab-topbar__brand:hover { text-decoration: none; }
.lab-topbar__brand .lab-mark { height: 22px; }

/* -- accessibility helpers ----------------------------------------------- */

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

/* Off screen until focused. With the nav in a drawer on phones, the first tab
   stop otherwise lands in the menu button on every page. */
.lab-skip {
  position: fixed;
  top: 8px;
  left: 8px;
  z-index: 100;
  padding: 9px 14px;
  border-radius: var(--lab-radius);
  background: var(--lab-purple);
  color: #fff;
  font-size: 14px;
  text-decoration: none;
  transform: translateY(calc(-100% - 16px));
}
.lab-skip:focus { transform: none; text-decoration: none; }

/* -- responsive ---------------------------------------------------------- */

/* Keep in step with --lab-nav-breakpoint, which nav.js reads. */
@media (max-width: 900px) {
  /* Rows sized explicitly. The shell is min-height:100vh, and with implicit
     auto rows the leftover height is shared between them - which quietly grew
     the top bar to a fifth of the screen. */
  .lab-shell {
    grid-template-columns: 1fr;
    grid-template-rows: auto 1fr;
  }

  .lab-topbar {
    display: flex;
    align-items: center;
    gap: 10px;
    position: sticky;
    top: 0;
    z-index: 30;
    padding: 8px 18px;
    padding-top: max(8px, env(safe-area-inset-top));
    background: var(--lab-surface);
    border-bottom: 1px solid var(--lab-border);
  }

  /* The drawer. Off canvas rather than stacked above the content, which is
     what this used to do: the nav pushed every page down by its own height
     and the actual page started below the fold. */
  .lab-nav {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    z-index: 50;
    width: min(84vw, 300px);
    height: 100%;
    height: 100dvh;
    padding: 20px 12px calc(20px + env(safe-area-inset-bottom));
    border-right: 1px solid var(--lab-border);
    box-shadow: 0 18px 48px rgba(0, 0, 0, 0.22);
    transform: translateX(-100%);
    /* visibility, not just transform, so a closed drawer is out of the tab
       order instead of being focusable off the side of the screen. */
    visibility: hidden;
    transition: transform 180ms ease, visibility 180ms;
  }
  [data-nav-open] .lab-nav { transform: none; visibility: visible; }

  .lab-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 40;
    background: rgba(10, 10, 11, 0.45);
    opacity: 0;
    pointer-events: none;
    transition: opacity 180ms ease;
  }
  [data-nav-open] .lab-scrim { opacity: 1; pointer-events: auto; }

  /* Stop the page behind the drawer scrolling under the finger. */
  html[data-nav-open],
  html[data-nav-open] body { overflow: hidden; }

  /* Comfortable thumb targets once the links are the whole screen wide. */
  .lab-nav__link { padding: 11px 10px; }

  /* You cannot scan the screen you are holding, so the button that skips the
     QR code moves above it. */
  .pair { display: flex; flex-direction: column; }
  .pair__direct { order: -1; margin: 0 0 16px; }
  .pair__code { margin-top: 0; }

  .lab-header {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
    padding: 16px 18px;
  }
  .lab-header__title { font-size: 20px; }
  .lab-header__actions { flex-wrap: wrap; }
  .lab-content { padding: 18px 18px calc(64px + env(safe-area-inset-bottom)); }

  /* 16px is the threshold below which iOS Safari zooms the page on focus and
     leaves it zoomed. Nothing else here needs the larger text. */
  input[type="text"], input[type="email"], input[type="password"],
  input[type="search"], input[type="number"], input[type="date"],
  input[type="tel"], input[type="url"], select, textarea { font-size: 16px; }

  .toolbar { gap: 6px; }
  .toolbar input[type="search"], .toolbar select { min-width: 0; flex: 1 1 160px; }
}

/* Anything laid out in fixed columns has to become one column on a phone.
   Declared by attribute so page-level inline grids are covered too. */
@media (max-width: 620px) {
  [style*="grid-template-columns"] { grid-template-columns: 1fr !important; }
  .lab-header__actions .btn { flex: 1 1 auto; }
}

@media (prefers-reduced-motion: reduce) {
  .lab-nav, .lab-scrim { transition: none; }
}
