/*
 * Platform styles.
 *
 * Organised as: tokens → reset → typography → layout → components → utilities → breakpoints.
 * Every colour, space and size resolves from a token, so a change happens in one place and
 * light/dark stay in step by construction rather than by discipline.
 *
 * Two constraints hold throughout:
 *   - No inline styles or inline event handlers anywhere, so the CSP added in P7 can forbid
 *     both without breaking a page.
 *   - Nothing may cause horizontal page scroll at 320px; wide content scrolls inside its own
 *     container instead.
 */

/* ==========================================================================
   Tokens
   ========================================================================== */

:root {
  /* Neutral ramp — the only greys used anywhere. */
  --c-bg: #f5f6f8;
  --c-surface: #ffffff;
  --c-surface-raised: #ffffff;
  --c-border: #dde1e6;
  --c-border-strong: #c3cad2;
  --c-text: #16191d;
  --c-text-muted: #5b6572;

  /* Accents. */
  --c-accent: #2c62d6;
  --c-accent-hover: #244fae;
  --c-accent-contrast: #ffffff;
  --c-accent-wash: #eaf0fc;

  --c-success: #1f7a44;
  --c-success-wash: #e6f4ec;
  --c-warning: #8a5a00;
  --c-warning-wash: #fbf1de;
  --c-danger: #b3261e;
  --c-danger-wash: #fbeae9;

  /* Typography — a 1.2 scale from a 1rem base. */
  --f-sans: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  --f-mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;

  --t-xs: 0.75rem;
  --t-sm: 0.875rem;
  --t-base: 1rem;
  --t-md: 1.125rem;
  --t-lg: 1.35rem;
  --t-xl: 1.65rem;
  --t-2xl: 2rem;

  --lh-tight: 1.25;
  --lh-normal: 1.55;

  /* Spacing — a 4px base scale. */
  --s-1: 0.25rem;
  --s-2: 0.5rem;
  --s-3: 0.75rem;
  --s-4: 1rem;
  --s-5: 1.5rem;
  --s-6: 2rem;

  /* Shape and depth. */
  --radius-sm: 6px;
  --radius: 10px;
  --radius-pill: 999px;

  --shadow-sm: 0 1px 2px rgb(16 24 40 / 6%);
  --shadow: 0 1px 2px rgb(16 24 40 / 6%), 0 2px 6px rgb(16 24 40 / 8%);

  --measure: 72rem;
  --measure-narrow: 34rem;
}

@media (prefers-color-scheme: dark) {
  :root {
    --c-bg: #121519;
    --c-surface: #1a1e23;
    --c-surface-raised: #21262c;
    --c-border: #2d343b;
    --c-border-strong: #3d4650;
    --c-text: #e7eaee;
    --c-text-muted: #98a2ae;

    --c-accent: #7aa2ff;
    --c-accent-hover: #96b6ff;
    --c-accent-contrast: #101319;
    --c-accent-wash: #1b2434;

    --c-success: #6fcf97;
    --c-success-wash: #16281f;
    --c-warning: #e3b263;
    --c-warning-wash: #2b2214;
    --c-danger: #f08579;
    --c-danger-wash: #2e1a18;

    --shadow-sm: 0 1px 2px rgb(0 0 0 / 40%);
    --shadow: 0 1px 2px rgb(0 0 0 / 35%), 0 2px 6px rgb(0 0 0 / 45%);
  }
}

/* ==========================================================================
   Reset
   ========================================================================== */

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

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

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--c-bg);
  color: var(--c-text);
  font-family: var(--f-sans);
  font-size: var(--t-base);
  line-height: var(--lh-normal);
  /* Belt and braces: no page-level sideways scroll, whatever a child does. */
  overflow-x: hidden;
}

img,
svg {
  max-width: 100%;
  height: auto;
}

/* ==========================================================================
   Typography
   ========================================================================== */

h1,
h2,
h3 {
  margin: 0 0 var(--s-3);
  line-height: var(--lh-tight);
  overflow-wrap: break-word;
}

h1 {
  font-size: var(--t-xl);
  letter-spacing: -0.01em;
}

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

h3 {
  font-size: var(--t-md);
}

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

p:last-child {
  margin-bottom: 0;
}

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

a:hover {
  color: var(--c-accent-hover);
}

code {
  font-family: var(--f-mono);
  font-size: 0.9em;
  overflow-wrap: anywhere;
}

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

/* ==========================================================================
   Layout
   ========================================================================== */

.container {
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
  padding-inline: var(--s-4);
}

/* --- Shell: sidebar + content ------------------------------------------- */
/* Replaces the former top site-header/footer stack. The panel mechanism itself (.mlp-sidebar,
 * .mlp-sidebar-toggle, the responsive collapse) comes from mlp-sidebar.css (mlp-libraries) —
 * imported after this file, see head.hbs. What's below is this specific sidebar's *content*:
 * the platform brand, the current app's own nav (when it has one — see sidebarNav in
 * docs/writing-an-app.md), and account/sign-out, pinned to the bottom via
 * .sidebar__account's margin-top: auto. No footer any more — there was nothing in it that
 * didn't already belong here. */

.shell {
  display: flex;
  align-items: stretch;
  min-height: 100vh;
}

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

.sidebar__logo-placeholder {
  display: block;
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  border-radius: var(--radius-sm);
  /* Belt and braces — the source PNG already has its own rounded corners baked in, this just
     guards against any stray edge pixel. Not a button/link: a purely decorative mark, same as
     before it was a real image (see sidebar.hbs). */
  object-fit: cover;
}

.sidebar__mark {
  display: flex;
  flex-shrink: 0;
  /* Pushed to the far right of the header row — the logo placeholder and the switcher own the
     left side; this keeps its original job (a plain "go home" link) without competing for it. */
  margin-left: auto;
  color: var(--c-accent);
}

.sidebar__mark-text {
  color: var(--c-text);
  font-size: var(--t-md);
  font-weight: 650;
}

.sidebar__switcher {
  position: relative;
  min-width: 0;
}

.sidebar__switcher-trigger {
  display: flex;
  align-items: center;
  gap: var(--s-1);
  max-width: 100%;
  border: none;
  background: none;
  padding: 0;
  color: var(--c-text);
  font: inherit;
  font-size: var(--t-md);
  font-weight: 650;
  cursor: pointer;
}

.sidebar__switcher-trigger span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sidebar__switcher-trigger:hover {
  color: var(--c-accent);
}

.sidebar__nav {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}

.sidebar__nav a {
  color: var(--c-text-muted);
  text-decoration: none;
  font-size: var(--t-sm);
  font-weight: 600;
  padding-block: var(--s-1);
}

.sidebar__nav a:hover {
  color: var(--c-text);
}

.sidebar__nav a[aria-current='page'] {
  color: var(--c-accent);
}

.sidebar__account {
  position: relative;
  margin-top: auto;
  padding-top: var(--s-4);
  border-top: 1px solid var(--c-border);
  font-size: var(--t-sm);
}

.sidebar__account-trigger {
  display: flex;
  align-items: center;
  width: 100%;
  gap: var(--s-2);
  border: none;
  background: none;
  padding: 0;
  color: var(--c-text);
  font: inherit;
  cursor: pointer;
}

.sidebar__account-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: left;
  font-weight: 600;
}

.sidebar__account-trigger:hover {
  color: var(--c-accent);
}

/* Compound selector (two classes) needed to outrank .mlp-dropdown-menu's own `top` rule in
   mlp-sidebar.css, which loads after this file and would otherwise win on equal specificity. */
.mlp-dropdown-menu.sidebar__account-menu {
  /* Anchored at the very bottom of the sidebar, so the shared .mlp-dropdown-menu's default
     downward placement would clip against the viewport edge — open upward instead. */
  top: auto;
  bottom: calc(100% + var(--s-1));
}

main.content {
  flex: 1;
  min-width: 0;
  padding: var(--s-6) var(--s-4);
  /* Vertical rhythm between top-level sections, without per-page margins. */
  display: flex;
  flex-direction: column;
  gap: var(--s-5);
}

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

.page-header h1 {
  margin: 0;
}

.page-header__title {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  flex-wrap: wrap;
}

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

.breadcrumb {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  font-size: var(--t-sm);
}

/* ==========================================================================
   Components
   ========================================================================== */

/* --- Panel --------------------------------------------------------------- */

.panel {
  padding: clamp(var(--s-4), 4vw, var(--s-6));
  /* A step smaller than the other three sides — the full clamp(--s-4, 4vw, --s-6) read as too
     much empty air above a panel's own first row of content (a table's filter bar, say). */
  padding-top: clamp(var(--s-3), 3vw, var(--s-5));
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

.panel > h2:first-child {
  margin-top: 0;
}

.panel--centered {
  max-width: var(--measure-narrow);
  margin-inline: auto;
  text-align: center;
}

.panel--callout {
  background: var(--c-accent-wash);
  border-color: var(--c-accent);
}

/* --- Buttons ------------------------------------------------------------- */

.button {
  display: inline-block;
  padding: 0.55rem 1.1rem;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: var(--c-accent);
  color: var(--c-accent-contrast);
  font: inherit;
  font-weight: 550;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
}

.button:hover {
  background: var(--c-accent-hover);
  color: var(--c-accent-contrast);
}

.button--secondary {
  background: transparent;
  border-color: var(--c-border-strong);
  color: var(--c-text);
}

.button--secondary:hover {
  background: var(--c-bg);
  color: var(--c-text);
}

.button--full {
  width: 100%;
}

.button[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

.link-button {
  padding: 0;
  border: 0;
  background: none;
  color: var(--c-accent);
  font: inherit;
  text-decoration: underline;
  cursor: pointer;
}

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

/* A horizontal row of buttons/forms — e.g. a quick-action button next to a `.dropdown-anchor`
   kebab trigger on a detail page. Generic on purpose: any app can reach for this instead of
   reinventing a flex row, same as `.inline-form`/`.filter-bar`. */
.action-row {
  display: flex;
  align-items: center;
  gap: var(--s-2);
}

/* Wrap a `[data-mlp-dropdown-trigger]` button and its `.mlp-dropdown-menu` (mlp-dropdown-menu,
   mlp-libraries) in this anywhere outside the sidebar's own pre-positioned wrappers
   (`.sidebar__switcher`/`.sidebar__account`) — `.mlp-dropdown-menu` is `position: absolute`
   and needs a positioned ancestor to anchor to, and no app repo has its own stylesheet to
   define that itself (every app gets this file plus the shared library CSS, nothing more). */
.dropdown-anchor {
  position: relative;
  display: inline-block;
}

/* --- Forms --------------------------------------------------------------- */

.stack {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
}

.field {
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
}

.field > label,
.field > legend {
  font-size: var(--t-sm);
  font-weight: 600;
}

.field input[type='text'],
.field input[type='email'],
.field input[type='password'],
.field input[type='number'],
.field select {
  width: 100%;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-sm);
  background: var(--c-surface-raised);
  color: var(--c-text);
  font: inherit;
}

.field input::placeholder {
  color: var(--c-text-muted);
}

.field__hint {
  margin: 0;
  color: var(--c-text-muted);
  font-size: var(--t-xs);
}

fieldset.field {
  margin: 0;
  padding: var(--s-3);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-sm);
}

.checkbox-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}

.checkbox-list label,
label.checkbox {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  font-weight: 400;
}

/* --- Alerts and flashes -------------------------------------------------- */

.flash-stack {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}

.alert {
  margin: 0;
  padding: var(--s-3);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font-size: var(--t-sm);
}

.alert--success {
  background: var(--c-success-wash);
  border-color: var(--c-success);
  color: var(--c-success);
}

.alert--warning {
  background: var(--c-warning-wash);
  border-color: var(--c-warning);
  color: var(--c-warning);
}

.alert--error {
  background: var(--c-danger-wash);
  border-color: var(--c-danger);
  color: var(--c-danger);
}

.form-errors ul {
  margin: var(--s-2) 0 0;
  padding-left: var(--s-4);
}

.form-errors__title {
  margin: 0;
  font-weight: 650;
}

/* --- Launcher tiles ------------------------------------------------------ */

.tile-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--s-4);
  /* One column by default; widened at the breakpoints below (P6.3). */
  grid-template-columns: 1fr;
}

.tile__link {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  height: 100%;
  padding: var(--s-4);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  color: var(--c-text);
  text-decoration: none;
  transition:
    border-color 120ms ease,
    box-shadow 120ms ease,
    transform 120ms ease;
}

.tile__link:hover,
.tile__link:focus-visible {
  border-color: var(--c-accent);
  box-shadow: var(--shadow);
  color: var(--c-text);
  transform: translateY(-1px);
}

.tile__icon {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: var(--radius-sm);
  background: var(--c-accent-wash);
  color: var(--c-accent);
}

.tile__body {
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
  min-width: 0;
}

.tile__name {
  font-weight: 600;
}

.tile__description {
  color: var(--c-text-muted);
  font-size: var(--t-sm);
  overflow-wrap: anywhere;
}

/* --- Record lists -------------------------------------------------------- */

.record-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.record {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--s-3);
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--c-border);
}

.record:first-child {
  padding-top: 0;
}

.record:last-child {
  padding-bottom: 0;
  border-bottom: 0;
}

.record__main,
.record__side {
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
  min-width: 0;
}

.record__side {
  align-items: flex-end;
  text-align: right;
}

.record__title {
  font-weight: 550;
  overflow-wrap: anywhere;
}

.record__meta {
  color: var(--c-text-muted);
  font-size: var(--t-sm);
  overflow-wrap: anywhere;
}

.record__amount {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.record__amount--income {
  color: var(--c-success);
}

/* --- Tags and pills ------------------------------------------------------ */

.tag-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1);
  justify-content: flex-end;
}

.tag,
.pill {
  display: inline-block;
  padding: 0.1rem 0.5rem;
  border-radius: var(--radius-pill);
  font-size: var(--t-xs);
  white-space: nowrap;
}

.tag {
  background: var(--c-accent-wash);
  color: var(--c-accent);
}

.pill--ok {
  background: var(--c-success-wash);
  color: var(--c-success);
}

.pill--warn {
  background: var(--c-warning-wash);
  color: var(--c-warning);
}

.pill--off {
  background: var(--c-bg);
  border: 1px solid var(--c-border);
  color: var(--c-text-muted);
}

/* --- In-app navigation ----------------------------------------------------- */

/* A lightweight section switcher inside a single app (e.g. Exercise's Workouts / Weight).
 * Plain links, current section marked with `aria-current="page"` rather than a modifier
 * class — the semantics are free and a screen reader announces it without extra markup. */
.app-nav {
  display: flex;
  gap: var(--s-4);
  margin-bottom: var(--s-2);
}

.app-nav a {
  color: var(--c-text-muted);
  text-decoration: none;
  font-size: var(--t-sm);
  font-weight: 600;
}

.app-nav a:hover {
  color: var(--c-text);
}

.app-nav a[aria-current='page'] {
  color: var(--c-accent);
}

/* --- Trend chart ------------------------------------------------------------ */

/* A single-series line chart over time (e.g. Exercise's weight trend). Geometry (point
 * coordinates, the line path) is computed server-side and passed to the template — see
 * mlp-app-exercise lib/weight.js buildTrendChart(). Colour comes entirely from existing
 * tokens, so dark mode needs no separate handling here. No legend: a single series is named
 * by the chart's own heading, not a swatch. */
.trend-chart {
  display: block;
  width: 100%;
  height: auto;
}

.trend-chart__grid {
  stroke: var(--c-border);
  stroke-width: 1;
}

.trend-chart__line {
  fill: none;
  stroke: var(--c-accent);
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
}

.trend-chart__dot {
  fill: var(--c-accent);
  stroke: var(--c-surface);
  stroke-width: 2;
}

.trend-chart__label {
  fill: var(--c-text-muted);
  font-size: var(--t-xs);
  font-family: var(--f-sans);
}

/* --- Tables -------------------------------------------------------------- */

/* Wide tables scroll inside this container so the page itself never does.
 *
 * `position: relative` is load-bearing: an absolutely-positioned descendant (a
 * `.visually-hidden` label, say) otherwise anchors to the initial containing block, lands at
 * its static offset inside the over-wide table, and extends the *document's* scroll width —
 * giving the page horizontal overflow even though the table itself is clipped. Caught at
 * 320px by the browser suite. */
/* Also caps a *tall* table's height — one page of rows (mlp-table's pagination, mlp-libraries)
 * scrolls inside this container rather than growing the page itself, so a table stays roughly
 * one screen tall no matter how many rows a page holds. The header stays put while the body
 * scrolls (`.data-table th`'s own `position: sticky` below), so which column is which is never
 * lost mid-scroll. */
.table-scroll {
  position: relative;
  overflow-x: auto;
  max-height: 60vh;
  overflow-y: auto;
}

/* A row of filter toggles above a table — reuses .button/.button--secondary for the
   active/inactive look rather than inventing new pill styling. */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin-bottom: var(--s-4);
}

/* The table's own top toolbar (Quick filters + the Advanced Filters trigger) sits at the
   right of the panel, clear of the table below it — the dialog's internal Apply/Clear row
   reuses .filter-bar too and stays left-aligned, so this is a modifier, not the default. */
.filter-bar--end {
  justify-content: flex-end;
}

/* A row count (mlp-table's .table-row-count, mlp-libraries) sharing a .filter-bar with the
 * filter controls — margin-right: auto keeps it pinned left regardless of the row's own
 * justify-content, pushing every sibling after it to the right the way a lone flex item with
 * "auto" margins always does, rather than needing a separate space-between layout. */
.filter-bar .table-row-count {
  margin: 0 auto 0 0;
}

/* An icon-only .button — square instead of text-shaped padding, for a trigger like the
   Advanced Filters button that carries no visible label (see the icon-filter partial). */
.button--icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.55rem;
}

/* table-layout: fixed means column widths come from the <colgroup> alone (mlp-table's
 * ColumnSpec.width, mlp-libraries), computed once, not recalculated from whichever rows happen
 * to be on screen — without it, sorting or paging to a row with a much longer/shorter value
 * visibly reflows every column's width, not just the one that changed. A column with no width
 * of its own just shares the leftover space evenly with every other width-less column. */
.data-table {
  width: 100%;
  table-layout: fixed;
  border-collapse: collapse;
  font-size: var(--t-sm);
}

.data-table th,
.data-table td {
  padding: var(--s-3) var(--s-3) var(--s-3) 0;
  border-bottom: 1px solid var(--c-border);
  text-align: left;
  vertical-align: top;
  /* A fixed-width cell can't grow to fit an unusually long value the way auto layout would —
     wrap it onto a second line instead of silently overflowing into the next column. */
  overflow-wrap: break-word;
}

.data-table th {
  position: sticky;
  top: 0;
  background: var(--c-surface);
  color: var(--c-text-muted);
  font-size: var(--t-xs);
  font-weight: 650;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.data-table tr:last-child td {
  border-bottom: 0;
}

/* --- Definition lists ---------------------------------------------------- */

.facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s-1) var(--s-4);
  margin: 0;
  font-size: var(--t-sm);
}

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

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

/* --- Admin --------------------------------------------------------------- */

.admin-bar {
  background: var(--c-accent-wash);
  border-bottom: 1px solid var(--c-border);
}

.admin-bar__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--s-3);
  padding-block: var(--s-2);
}

.admin-bar__label {
  color: var(--c-accent);
  font-size: var(--t-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.admin-bar__nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-4);
  font-size: var(--t-sm);
}

.order-input {
  width: 5rem;
}

.pager {
  display: flex;
  gap: var(--s-3);
}

.secret {
  padding: var(--s-3);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--radius-sm);
  background: var(--c-surface-raised);
  font-family: var(--f-mono);
  font-size: var(--t-md);
  overflow-wrap: anywhere;
  user-select: all;
}

/* --- Auth screens -------------------------------------------------------- */

.auth-shell {
  flex: 1;
  display: grid;
  place-items: center;
  padding: var(--s-4);
}

.auth-card {
  width: 100%;
  max-width: 24rem;
  padding: clamp(var(--s-5), 5vw, var(--s-6));
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.auth-card__title {
  margin: 0;
  font-size: var(--t-lg);
}

.auth-card__subtitle {
  margin: var(--s-1) 0 var(--s-5);
}

/* --- Error pages --------------------------------------------------------- */

.status-code {
  margin: 0;
  color: var(--c-text-muted);
  font-size: var(--t-2xl);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  line-height: 1;
}

.error-detail {
  margin-top: var(--s-4);
  padding: var(--s-3);
  border: 1px solid var(--c-border);
  border-radius: var(--radius-sm);
  background: var(--c-bg);
  font-size: var(--t-xs);
  text-align: left;
  overflow-x: auto;
}

/* ==========================================================================
   Accessibility and utilities
   ========================================================================== */

.skip-link {
  position: absolute;
  left: -9999px;
}

.skip-link:focus {
  left: var(--s-4);
  top: var(--s-4);
  z-index: 10;
  padding: var(--s-2) var(--s-3);
  background: var(--c-surface);
  border: 1px solid var(--c-accent);
  border-radius: var(--radius-sm);
}

:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--c-accent);
  outline-offset: 2px;
}

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

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ==========================================================================
   Breakpoints — mobile first (P6.3)
   ========================================================================== */

/* 2 columns from 36rem (576px). */
@media (min-width: 36rem) {
  .tile-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* 3 columns from 52rem (832px). */
@media (min-width: 52rem) {
  .tile-grid {
    grid-template-columns: repeat(3, 1fr);
  }

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

/* 4 columns from 68rem (1088px). */
@media (min-width: 68rem) {
  .tile-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}
