/* Nuvel — application styles.
 *
 * Every colour, size and radius here resolves to a custom property from design/tokens.css.
 * Nothing in this file may contain a hex literal or a raw font size; the only numbers are
 * structural (grid counts, stroke widths inside placeholder artwork) and they are commented.
 *
 * Logical properties only. The shell must flip under dir="rtl" without a rewrite.
 */

/* ==========================================================================
   Base
   ========================================================================== */

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

html {
  background: var(--bg);
}

body {
  margin: 0;
  min-block-size: 100dvh;
  background: var(--bg);
  color: var(--text-primary);
  font-family: var(--font-ui);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

a {
  color: inherit;
}

:focus-visible {
  outline: var(--border-width-focus) solid var(--state-focus-ring);
  outline-offset: var(--border-width-focus);
}

/* ==========================================================================
   Utilities
   ========================================================================== */

.icon-sprite {
  position: absolute;
  inline-size: 0;
  block-size: 0;
  overflow: hidden;
}

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

.skip-link {
  position: fixed;
  inset-block-start: var(--space-4);
  inset-inline-start: var(--space-4);
  z-index: 60;
  padding: var(--space-4) var(--space-5);
  border-radius: var(--radius-sm);
  background: var(--snow);
  color: var(--ink);
  font-size: var(--fs-label);
  font-weight: var(--weight-medium);
  line-height: var(--lh-label);
  text-decoration: none;
  transform: translateY(calc(-100% - var(--space-8)));
}

.skip-link:focus-visible {
  transform: translateY(0);
}

/* ==========================================================================
   Shell
   ========================================================================== */

.shell {
  display: grid;
  grid-template-columns: var(--layout-sidebar) minmax(0, 1fr);
  min-block-size: 100dvh;
}

.shell__main {
  display: flex;
  flex-direction: column;
  min-inline-size: 0;
}

/* Drawer scrim. Only exists below the sidebar breakpoint; see the media query at the end. */
.scrim {
  display: none;
}

/* ==========================================================================
   Sidebar
   ========================================================================== */

.sidebar {
  position: sticky;
  inset-block-start: 0;
  display: flex;
  flex-direction: column;
  block-size: 100dvh;
  inline-size: var(--layout-sidebar);
  background: var(--graphite);
  border-inline-end: var(--border-width-default) solid var(--border-subtle);
  overflow: hidden;
}

.sidebar__brand {
  display: flex;
  align-items: center;
  padding: var(--space-7);
}

.sidebar__tenant {
  margin-block: 0 var(--space-7);
  margin-inline: var(--space-5);
  padding: var(--space-4) var(--space-5);
  border: var(--border-width-default) solid var(--border-default);
  border-radius: var(--radius-sm);
  color: var(--text-secondary);
  font-size: var(--fs-label);
  font-weight: var(--weight-medium);
  line-height: var(--lh-label);
  letter-spacing: var(--ls-label);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.sidebar__nav {
  flex: 1 1 auto;
  min-block-size: 0;
  padding-inline: var(--space-5);
  padding-block-end: var(--space-6);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.sidebar__foot {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  padding: var(--space-5);
  border-block-start: var(--border-width-default) solid var(--border-subtle);
  color: var(--text-dim);
  font-size: var(--fs-label);
  line-height: var(--lh-label);
}

.sidebar__avatar {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  inline-size: var(--layout-avatar);
  block-size: var(--layout-avatar);
  border-radius: var(--radius-pill);
  background: var(--steel);
  color: var(--text-display);
  font-size: var(--fs-label);
  font-weight: var(--weight-semibold);
  line-height: 1;
  letter-spacing: var(--ls-label);
}

.sidebar__name {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.sidebar__signout {
  padding: var(--space-4) var(--space-5) var(--space-5);
}

.sidebar__signout .button {
  inline-size: 100%;
}

/* ==========================================================================
   Logo
   ========================================================================== */

.logo {
  display: inline-flex;
  align-items: center;
}

/* 96px wide is the minimum for the lockup in DESIGN.md §7; the pack supplies the artwork at
 * that size, so the height follows the file's own ratio. */
.logo__lockup {
  inline-size: var(--space-14);
  block-size: auto;
}

/* ==========================================================================
   Navigation
   ========================================================================== */

.nav-group + .nav-group {
  margin-block-start: var(--space-6);
}

.nav-group__label {
  margin: 0;
  padding-inline: var(--space-4);
  padding-block: 0 var(--space-4);
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: var(--fs-micro-s);
  font-weight: var(--weight-regular);
  line-height: var(--lh-micro-s);
  letter-spacing: var(--ls-micro-s);
  text-transform: uppercase;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  block-size: var(--layout-nav-item);
  padding-inline: var(--space-4);
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  font-size: var(--fs-body-s);
  line-height: 1;
  text-decoration: none;
  transition: background-color var(--motion-fast) var(--ease-standard),
              color var(--motion-fast) var(--ease-standard);
}

.nav-item:hover {
  background: var(--raised-hover);
  color: var(--text-secondary);
}

.nav-item__label {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.nav-item[aria-current="page"] {
  background: color-mix(in srgb, var(--nav-accent) 12%, transparent);
  color: var(--text-display);
}

/* No icon recolour on the active row: the pack's tonal artwork is already the section's
 * colour, and tinting it again would shift it off the palette. */

/* Icon geometry.
 * stroke-width 1.6 belongs to the placeholder artwork in components/_icons.html, not to the
 * layout: the real pack is filled shapes and drops this block entirely.
 */
.nav-item__icon {
  inline-size: var(--icon-inline-min);
  block-size: var(--icon-inline-min);
  flex: 0 0 auto;
}

/* The two chrome icons in _icons.html are the only inline drawings left; the 33 product
 * icons are files from the pack, so they carry their own artwork. */
.topbar__icon,
.topbar__search-icon {
  inline-size: var(--icon-inline-min);
  block-size: var(--icon-inline-min);
  flex: 0 0 auto;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Accents are declared here, keyed by token name, so no template writes a colour.
 * One accent per screen: the active nav item is that accent.
 */
.nav-item[data-accent="ember"] { --nav-accent: var(--ember); }
.nav-item[data-accent="flare"] { --nav-accent: var(--flare); }
.nav-item[data-accent="solar"] { --nav-accent: var(--solar); }
.nav-item[data-accent="aqua"] { --nav-accent: var(--aqua); }
.nav-item[data-accent="azure"] { --nav-accent: var(--azure); }
.nav-item[data-accent="cobalt"] { --nav-accent: var(--cobalt); }
.nav-item[data-accent="snow"] { --nav-accent: var(--snow); }
.nav-item[data-accent="steel"] { --nav-accent: var(--steel); }

/* ==========================================================================
   Topbar
   ========================================================================== */

.topbar {
  position: sticky;
  inset-block-start: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: var(--space-6);
  block-size: var(--layout-topbar);
  padding-inline: var(--space-9);
  background: var(--bg);
  border-block-end: var(--border-width-default) solid var(--border-subtle);
}

.topbar__menu {
  display: none;
  align-items: center;
  justify-content: center;
  inline-size: var(--layout-search);
  block-size: var(--layout-search);
  padding: 0;
  border: var(--border-width-default) solid var(--border-subtle);
  border-radius: var(--radius-sm);
  background: none;
  color: var(--text-secondary);
  cursor: pointer;
}

.topbar__crumbs {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-inline-size: 0;
  color: var(--text-muted);
  font-size: var(--fs-label);
  line-height: var(--lh-label);
}

.topbar__crumb {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  text-decoration: none;
}

a.topbar__crumb:hover {
  color: var(--text-primary);
}

.topbar__crumb[aria-current="page"] {
  color: var(--text-primary);
  font-weight: var(--weight-medium);
}

.topbar__sep {
  color: var(--text-dim);
}

.topbar__date {
  margin: 0;
  color: var(--text-dim);
  font-size: var(--fs-label);
  line-height: var(--lh-label);
  white-space: nowrap;
}

/* Language control: two small buttons, the active one marked by a border, not a colour. */
.topbar__lang {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  margin-inline-start: auto;
}

.topbar__lang-btn {
  padding: var(--space-3) var(--space-4);
  border: var(--border-width-default) solid transparent;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--text-dim);
  font-family: var(--font-ui);
  font-size: var(--fs-label);
  line-height: 1;
  cursor: pointer;
}

.topbar__lang-btn[aria-current="true"] {
  border-color: var(--border-default);
  color: var(--text-primary);
}

.topbar__search {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  inline-size: var(--layout-search-width);
  block-size: var(--layout-search);
  padding-inline: var(--space-5);
  border: var(--border-width-default) solid var(--border-subtle);
  border-radius: var(--radius-sm);
  background: var(--inset);
  color: var(--text-dim);
}

/* The ring belongs to the field, not to the input inside it. */
.topbar__search:focus-within {
  outline: var(--border-width-focus) solid var(--state-focus-ring);
  outline-offset: var(--border-width-focus);
}

.topbar__search-icon {
  color: var(--text-dim);
}

.topbar__search-input {
  flex: 1 1 auto;
  min-inline-size: 0;
  border: 0;
  background: none;
  color: var(--text-primary);
  font-family: var(--font-ui);
  font-size: var(--fs-label);
  line-height: var(--lh-label);
}

.topbar__search-input:focus-visible {
  outline: none;
}

.topbar__search-input::placeholder {
  color: var(--text-dim);
}

/* ==========================================================================
   Page
   ========================================================================== */

.page {
  flex: 1 1 auto;
  padding-block: var(--space-9);
  padding-inline: var(--space-9);
}

.page__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-6);
  margin-block-end: var(--space-8);
}

.page__titles {
  min-inline-size: 0;
}

.page__title {
  margin: 0;
  text-wrap: balance;
  color: var(--text-display);
  font-family: var(--font-display);
  font-size: var(--fs-h1-s);
  font-weight: var(--weight-bold);
  line-height: var(--lh-h1-s);
  letter-spacing: var(--ls-h1-s);
}

.page__lede {
  margin-block: var(--space-3) 0;
  margin-inline: 0;
  color: var(--text-dim);
  font-size: var(--fs-body-m);
  line-height: var(--lh-body-m);
}

.page__actions {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  gap: var(--space-5);
}

/* A link, not a button. components/button.html arrives in phase 2 and is the only button. */
.text-link {
  color: var(--text-primary);
  font-size: var(--fs-label);
  font-weight: var(--weight-medium);
  text-decoration: underline;
  text-decoration-color: var(--steel);
  text-underline-offset: var(--space-1);
}

/* Page body copy. `64ch` is a measure, not a size: it keeps a 1440px line readable and has
 * no token because it is typographic rhythm rather than a scale step. Clamped to the
 * container so it can never create a horizontal scrollbar at 390. */
.page__body {
  max-inline-size: min(64ch, 100%);
  overflow-wrap: break-word;
  color: var(--text-secondary);
  font-size: var(--fs-body-m);
  line-height: var(--lh-body-m);
}

.page__subtitle {
  margin-block: var(--space-8) var(--space-4);
  margin-inline: 0;
  color: var(--text-primary);
  font-size: var(--fs-h3);
  font-weight: var(--weight-semibold);
  line-height: var(--lh-h3);
  letter-spacing: var(--ls-h3);
}

.page__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin: 0;
  padding-inline-start: var(--space-6);
}

.page__body code {
  color: var(--text-primary);
  font-family: var(--font-mono);
  font-size: var(--fs-code);
  line-height: var(--lh-code);
}

/* ==========================================================================
   KPI card
   ========================================================================== */

.kpi-row {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-6);
}

.kpi {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-inline-size: 0;
  padding: var(--space-card-padding);
  border: var(--border-width-default) solid var(--border-default);
  border-radius: var(--radius-lg);
  /* Two layers: the domain glow rising from the bottom edge, then the raised surface. */
  background:
    radial-gradient(
      56% 48% at 50% 104%,
      color-mix(in srgb, var(--kpi-accent) 80%, transparent) 0%,
      transparent 70%
    ),
    var(--raised);
}

/* The 2px domain edge, faded at both ends so it reads as light rather than as a border.
 * Symmetric, so it needs no RTL variant. */
.kpi::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  block-size: var(--border-width-focus);
  background: linear-gradient(90deg, transparent, var(--kpi-accent), transparent);
  opacity: 0.55;
}

.kpi > * {
  position: relative;
  z-index: 1;
}

.kpi__label {
  margin: 0;
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: var(--fs-micro-s);
  font-weight: var(--weight-regular);
  line-height: var(--lh-micro-s);
  letter-spacing: var(--ls-micro-s);
  text-transform: uppercase;
}

.kpi__value {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  margin: var(--space-5) 0 0;
}

.kpi__number {
  color: var(--text-display);
  font-family: var(--font-numeric);
  font-size: var(--fs-numeric-m);
  font-weight: var(--weight-numeric);
  line-height: var(--lh-numeric-m);
  letter-spacing: var(--ls-numeric-m);
  font-variant-numeric: tabular-nums;
}

.kpi__unit {
  color: var(--text-dim);
  font-size: var(--fs-label);
  font-weight: var(--weight-medium);
  line-height: var(--lh-label);
}

.kpi__caption {
  margin: var(--space-4) 0 0;
  color: var(--text-dim);
  font-size: var(--fs-label);
  line-height: var(--lh-body-s);
}

.kpi__caption b {
  color: var(--text-secondary);
  font-weight: var(--weight-medium);
  font-variant-numeric: tabular-nums;
}

/* Domain accents. Same contract as the sidebar: a name in the markup, a token here. */
.kpi[data-domain="attendance"] { --kpi-accent: var(--aqua); }
.kpi[data-domain="people"] { --kpi-accent: var(--ember); }
.kpi[data-domain="money"] { --kpi-accent: var(--solar); }
.kpi[data-domain="projects"] { --kpi-accent: var(--flare); }
.kpi[data-domain="reports"] { --kpi-accent: var(--azure); }
.kpi[data-domain="system"] { --kpi-accent: var(--cobalt); }
.kpi[data-domain="general"] { --kpi-accent: var(--steel); }

/* ==========================================================================
   Card
   A table is always inside one. The shared classes live here so the Overview's fact
   panels reuse them rather than redefining a surface.
   ========================================================================== */

.card {
  background: var(--raised);
  border: var(--border-width-default) solid var(--border-default);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

.card__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
  padding: var(--space-6) var(--space-7);
  border-block-end: var(--border-width-default) solid var(--border-hairline);
}

.card__title {
  margin: 0;
  color: var(--text-primary);
  font-size: var(--fs-body);
  font-weight: var(--weight-semibold);
  line-height: 1;
}

.card__meta {
  color: var(--text-dim);
  font-size: var(--fs-label);
  line-height: var(--lh-label);
}

/* ==========================================================================
   Table
   ========================================================================== */

.table-scroll {
  overflow-x: auto;
}

.table {
  inline-size: 100%;
  /* A layout threshold, not a size token: below 40rem the six columns crush and the
   * numbers stop aligning, so the table scrolls instead. Reverse that with a real
   * mobile design, not by shrinking type. */
  min-inline-size: 40rem;
  border-collapse: collapse;
}

.table th {
  padding-block: var(--space-5) var(--space-4);
  padding-inline: var(--space-7);
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: var(--fs-micro-s);
  font-weight: var(--weight-regular);
  line-height: var(--lh-micro-s);
  letter-spacing: var(--ls-micro-s);
  text-align: start;
  text-transform: uppercase;
  white-space: nowrap;
}

.table td {
  block-size: var(--layout-row);
  padding-block: var(--space-5);
  padding-inline: var(--space-7);
  border-block-start: var(--border-width-hairline) solid var(--border-hairline);
  color: var(--text-secondary);
  font-size: var(--fs-body-m);
  line-height: var(--lh-body-s);
  vertical-align: middle;
}

.table tbody tr {
  transition: background-color var(--motion-fast) var(--ease-standard);
  animation: row-in var(--motion-base) var(--ease-standard) both;
}

/* One token step apart. Past the eighth row the stagger stops being noticeable and starts
 * being a wait, so it stops. */
.table tbody tr:nth-child(2) { animation-delay: calc(var(--stagger) * 1); }
.table tbody tr:nth-child(3) { animation-delay: calc(var(--stagger) * 2); }
.table tbody tr:nth-child(4) { animation-delay: calc(var(--stagger) * 3); }
.table tbody tr:nth-child(5) { animation-delay: calc(var(--stagger) * 4); }
.table tbody tr:nth-child(6) { animation-delay: calc(var(--stagger) * 5); }
.table tbody tr:nth-child(7) { animation-delay: calc(var(--stagger) * 6); }
.table tbody tr:nth-child(8) { animation-delay: calc(var(--stagger) * 7); }

.table tbody tr:hover {
  background: var(--raised-hover);
}

/* Numbers carry meaning, so they get the emphasised colour and tabular figures. */
.table .is-numeric {
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  text-align: end;
}

.table .is-strong {
  color: var(--text-primary);
  font-weight: var(--weight-medium);
}

.table a {
  color: inherit;
  text-decoration: none;
}

.table a:hover {
  text-decoration: underline;
  text-decoration-color: var(--steel);
  text-underline-offset: var(--space-1);
}

/* ==========================================================================
   Pill
   ========================================================================== */

/* A status is an icon plus its word. Filled pills turn four states into four coloured
 * capsules that read the same at 9px; the mark carries the shape of the state instead. */
.pill {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  color: var(--state-colour);
  font-family: var(--font-ui);
  font-size: var(--fs-body-s);
  font-weight: var(--weight-regular);
  line-height: var(--lh-body-s);
  white-space: nowrap;
}

.pill__icon {
  display: inline-flex;
  flex: 0 0 auto;
  inline-size: var(--icon-inline-min);
  block-size: var(--icon-inline-min);
}

.pill__icon svg {
  inline-size: 100%;
  block-size: 100%;
}

.pill[data-state="ok"] { --state-colour: var(--aqua); }
.pill[data-state="warn"] { --state-colour: var(--solar); }
.pill[data-state="risk"] { --state-colour: var(--ember); }

/* Paused and draft are the absence of a state, so they get no hue at all. */
.pill[data-state="idle"] { --state-colour: var(--text-dim); }

/* ==========================================================================
   Bar
   A native <progress>, so the value reaches assistive technology without an inline style.
   ========================================================================== */

.bar {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  inline-size: 100%;
  max-inline-size: var(--space-14);
  block-size: var(--space-3);
  border: 0;
  border-radius: var(--radius-pill);
  overflow: hidden;
  background: var(--border-subtle);
}

.bar::-webkit-progress-bar {
  background: var(--border-subtle);
  border-radius: var(--radius-pill);
}

.bar::-webkit-progress-value {
  background: var(--bar-accent);
  border-radius: var(--radius-pill);
}

.bar::-moz-progress-bar {
  background: var(--bar-accent);
  border-radius: var(--radius-pill);
}

.bar[data-domain="attendance"] { --bar-accent: var(--aqua); }
.bar[data-domain="people"] { --bar-accent: var(--ember); }
.bar[data-domain="money"] { --bar-accent: var(--solar); }
.bar[data-domain="projects"] { --bar-accent: var(--flare); }
.bar[data-domain="reports"] { --bar-accent: var(--azure); }
.bar[data-domain="system"] { --bar-accent: var(--cobalt); }
.bar[data-domain="general"] { --bar-accent: var(--steel); }

/* ==========================================================================
   Button
   One button. Primary is snow with ink text — never a coloured fill.
   ========================================================================== */

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  block-size: var(--layout-button);
  padding-inline: var(--space-5);
  border: var(--border-width-default) solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-primary);
  font-family: var(--font-ui);
  font-size: var(--fs-body-m);
  font-weight: var(--weight-medium);
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--motion-fast) var(--ease-standard),
              border-color var(--motion-fast) var(--ease-standard),
              color var(--motion-fast) var(--ease-standard),
              transform var(--motion-fast) var(--ease-standard);
}

/* Press, not bounce: the control acknowledges the touch and comes straight back. */
.button:active {
  transform: scale(var(--scale-press));
}

/* Hover is not in reference.html; the border lifts one step rather than the fill moving. */
.button:hover {
  border-color: var(--silver);
}

.button[data-variant="primary"] {
  background: var(--snow);
  border-color: var(--snow);
  color: var(--ink);
}

.button[data-variant="primary"]:hover {
  background: var(--text-display);
  border-color: var(--text-display);
}

.button[data-variant="danger"] {
  border-color: color-mix(in srgb, var(--ember) 55%, transparent);
  color: var(--ember);
}

.button[data-variant="danger"]:hover {
  background: color-mix(in srgb, var(--ember) 12%, transparent);
  border-color: var(--ember);
}

.button:disabled,
.button[aria-disabled="true"] {
  opacity: 0.4;
  cursor: not-allowed;
}

.button[aria-disabled="true"]:hover {
  border-color: var(--border-strong);
}

/* ==========================================================================
   Form
   Label above the control, 38px control, 8px radius, one focus ring.
   ========================================================================== */

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  min-inline-size: 0;
}

.field__label {
  color: var(--text-secondary);
  font-size: var(--fs-label);
  font-weight: var(--weight-medium);
  line-height: var(--lh-label);
  letter-spacing: var(--ls-label);
}

.field__hint {
  margin: 0;
  color: var(--text-dim);
  font-size: var(--fs-label);
  line-height: var(--lh-body-s);
}

.field__error {
  display: flex;
  gap: var(--space-3);
  margin: 0;
  color: var(--ember);
  font-size: var(--fs-label);
  line-height: var(--lh-body-s);
}

.field__control {
  inline-size: 100%;
  block-size: var(--layout-input);
  padding-inline: var(--space-5);
  border: var(--border-width-default) solid var(--border-default);
  border-radius: var(--radius-sm);
  background: var(--inset);
  color: var(--text-primary);
  font-family: var(--font-ui);
  font-size: var(--fs-body-m);
  line-height: 1;
  appearance: none;
}

.field__control:focus-visible {
  border-color: var(--text-display);
  outline: var(--border-width-focus) solid var(--state-focus-ring);
  outline-offset: var(--border-width-focus);
}

.field[data-invalid="true"] .field__control {
  border-color: var(--ember);
}

.field[data-invalid="true"] .field__control:focus-visible {
  outline-color: var(--ember);
}

.field__select {
  position: relative;
  display: block;
}

.field__control--select {
  padding-inline-end: var(--space-11);
  cursor: pointer;
}

.field__chevron {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-end: var(--space-5);
  inline-size: var(--space-3);
  block-size: var(--space-3);
  border-inline-end: var(--border-width-strong) solid var(--steel);
  border-block-end: var(--border-width-strong) solid var(--steel);
  transform: translateY(-70%) rotate(45deg);
  pointer-events: none;
}

.field__control--textarea {
  block-size: var(--layout-textarea);
  padding-block: var(--space-5);
  line-height: var(--lh-body-s);
  resize: none;
}

/* ==========================================================================
   Checkbox
   ========================================================================== */

.field--check {
  gap: var(--space-3);
}

.checkbox {
  display: inline-flex;
  align-items: center;
  gap: var(--space-5);
  color: var(--text-secondary);
  font-size: var(--fs-body-m);
  line-height: var(--lh-body-s);
  cursor: pointer;
}

.checkbox__input {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  inline-size: var(--space-6);
  block-size: var(--space-6);
  margin: 0;
  border: var(--border-width-default) solid var(--border-strong);
  border-radius: var(--radius-xs);
  background: transparent;
  appearance: none;
  cursor: pointer;
}

.checkbox__input:checked {
  background: var(--snow);
  border-color: var(--snow);
}

/* The tick is two borders on a rotated box, which is the same trick the reference uses. */
.checkbox__input:checked::after {
  content: "";
  inline-size: var(--space-4);
  block-size: var(--space-3);
  border-inline-start: var(--border-width-focus) solid var(--ink);
  border-block-end: var(--border-width-focus) solid var(--ink);
  transform: rotate(-45deg) translateY(-1px);
}

.checkbox__input:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.checkbox:has(.checkbox__input:disabled) {
  opacity: 0.45;
  cursor: not-allowed;
}

/* ==========================================================================
   Composition — the pieces the reference screens are assembled from
   ========================================================================== */

.card__body {
  padding: var(--space-7);
}

.facts {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-6);
  padding: var(--space-7);
}

.fact__label {
  margin: 0;
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: var(--fs-micro-s);
  line-height: var(--lh-micro-s);
  letter-spacing: var(--ls-micro-s);
  text-transform: uppercase;
}

/* A fact is a supporting figure, so it is Geist: Doto belongs to the one number a screen is
 * about, and there is only one of those per screen. */
.fact__value {
  margin: var(--space-4) 0 0;
  color: var(--text-primary);
  font-size: var(--fs-h3);
  font-weight: var(--weight-medium);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.fact__unit {
  margin-inline-start: var(--space-2);
  color: var(--text-dim);
  font-size: var(--fs-label);
  font-weight: var(--weight-regular);
}

.facts .bar {
  max-inline-size: none;
  block-size: var(--space-2);
  margin-block-start: var(--space-5);
}

.note {
  padding: var(--space-7);
  border: var(--border-width-default) solid var(--border-default);
  border-radius: var(--radius-lg);
  background: var(--raised);
}

.note--empty {
  border-style: dashed;
  border-color: var(--border-strong);
  background: transparent;
}

.note__title {
  margin: 0 0 var(--space-4);
  color: var(--text-primary);
  font-size: var(--fs-body);
  font-weight: var(--weight-medium);
  line-height: 1.3;
}

.note__body {
  margin: 0;
  color: var(--text-dim);
  font-size: var(--fs-label);
  line-height: var(--lh-body-s);
}

.note__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-5);
  padding-block: var(--space-4);
  border-block-start: var(--border-width-default) solid var(--border-hairline);
  color: var(--text-dim);
  font-size: var(--fs-label);
  line-height: 1;
}

.note__row b {
  color: var(--text-primary);
  font-weight: var(--weight-medium);
  font-variant-numeric: tabular-nums;
}

/* Two columns: content, then a fixed rail. The rail is a layout token because it is the same
 * 336px in every form in the product. */
.cols {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--layout-rail);
  gap: var(--space-7);
  align-items: start;
}

.cols__main,
.cols__rail {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  min-inline-size: 0;
}

.form {
  display: flex;
  flex-direction: column;
  gap: var(--space-7);
  padding: var(--space-8);
}

.form__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-6) var(--space-7);
}

/* A field that spans both columns of the form grid. The wrapper exists because field.html
 * renders its own element and cannot take a class. */
.field-span {
  grid-column: 1 / -1;
}

.form__foot {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-5);
  padding-block-start: var(--space-6);
  border-block-start: var(--border-width-default) solid var(--border-hairline);
}

/* ==========================================================================
   Empty state
   ========================================================================== */

.empty {
  padding: var(--space-7);
  border: var(--border-width-default) dashed var(--border-strong);
  border-radius: var(--radius-md);
  text-align: center;
}

.empty__title {
  margin: 0 0 var(--space-3);
  color: var(--text-primary);
  font-size: var(--fs-body-s);
  font-weight: var(--weight-medium);
  line-height: 1.3;
}

.empty[data-variant="error"] .empty__title {
  color: var(--ember);
}

.empty__body {
  margin: 0 0 var(--space-5);
  color: var(--text-dim);
  font-size: var(--fs-label);
  line-height: var(--lh-body-s);
}

/* ==========================================================================
   Error screens
   One status code, one sentence, one way back. The code is the only figure on the
   page, so it may use the 72px Doto step that nothing else in the product reaches.
   ========================================================================== */

.error {
  padding-block: var(--space-9);
  padding-inline: var(--space-7);
}

.error__body {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-5);
  text-align: center;
}

.error__code {
  margin: 0;
  color: var(--text-display);
  font-family: var(--font-numeric);
  font-size: var(--fs-numeric-xl);
  font-weight: var(--weight-numeric);
  line-height: var(--lh-numeric-xl);
  letter-spacing: var(--ls-numeric-xl);
  font-variant-numeric: tabular-nums;
}

.error__title {
  margin: 0;
  color: var(--text-primary);
  font-size: var(--fs-h3);
  font-weight: var(--weight-semibold);
  line-height: 1.3;
}

.error__text {
  margin: 0;
  max-inline-size: min(52ch, 100%);
  color: var(--text-dim);
  font-size: var(--fs-body-m);
  line-height: var(--lh-body-m);
}

.error__actions {
  margin-block-start: var(--space-3);
}

/* ==========================================================================
   Loading skeleton
   ========================================================================== */

.skeleton {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.skeleton__bar {
  block-size: var(--space-4);
  border-radius: var(--radius-xs);
  /* One step above the raised surface, otherwise the bar is invisible on it. */
  background: var(--border-default);
  animation: skeleton-pulse calc(var(--motion-slow) * 6) var(--ease-standard) infinite;
}

.skeleton__bar:last-child {
  inline-size: 60%;
}

/* Opacity only. tokens.css collapses this to nothing under prefers-reduced-motion. */
@keyframes skeleton-pulse {
  0%,
  100% {
    opacity: 0.45;
  }
  50% {
    opacity: 1;
  }
}

/* ==========================================================================
   Flash — the one message shape: {level, message, field?}
   ========================================================================== */

.flash {
  display: flex;
  align-items: flex-start;
  gap: var(--space-5);
  padding: var(--space-5) var(--space-6);
  border: var(--border-width-default) solid color-mix(in srgb, var(--flash-accent) 55%, transparent);
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--flash-accent) 12%, transparent);
}

.flash__dot {
  flex: 0 0 auto;
  inline-size: var(--space-3);
  block-size: var(--space-3);
  margin-block-start: var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--flash-accent);
}

/* The message is never the colour: spectrum on body text fails contrast. */
.flash__message {
  margin: 0;
  color: var(--text-primary);
  font-size: var(--fs-body-m);
  line-height: var(--lh-body-s);
}

.flash[data-level="info"] { --flash-accent: var(--azure); }
.flash[data-level="success"] { --flash-accent: var(--aqua); }
.flash[data-level="warning"] { --flash-accent: var(--solar); }
.flash[data-level="error"] { --flash-accent: var(--ember); }

/* ==========================================================================
   Gallery — the design-system page, not a product screen
   ========================================================================== */

.gallery {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--space-6);
}

.span-4 { grid-column: span 4; }
.span-6 { grid-column: span 6; }
.span-12 { grid-column: span 12; }

.swatches {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: var(--space-4);
}

.swatch {
  display: flex;
  align-items: flex-end;
  block-size: var(--space-11);
  padding: var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: var(--fs-micro-s);
  line-height: 1;
  letter-spacing: 0.1em;
}

.swatch--ember { background: var(--ember); }
.swatch--flare { background: var(--flare); }
.swatch--solar { background: var(--solar); }
.swatch--haze { background: var(--haze); }
.swatch--aqua { background: var(--aqua); }
.swatch--azure { background: var(--azure); }
.swatch--cobalt { background: var(--cobalt); color: var(--text-display); }
.swatch--ink { background: var(--ink); color: var(--silver); border: var(--border-width-default) solid var(--border-default); }
.swatch--graphite { background: var(--graphite); color: var(--silver); }
.swatch--steel { background: var(--steel); color: var(--snow); }
.swatch--silver { background: var(--silver); }
.swatch--snow { background: var(--snow); }

.spec {
  display: flex;
  align-items: baseline;
  gap: var(--space-5);
  padding-block: var(--space-4);
  border-block-start: var(--border-width-default) solid var(--border-hairline);
}

.spec:first-of-type {
  border-block-start: 0;
}

.spec__label {
  flex: 0 0 auto;
  inline-size: var(--space-13);
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: var(--fs-micro-s);
  line-height: var(--lh-micro-s);
  letter-spacing: var(--ls-micro-s);
  text-transform: uppercase;
}

.spec__display {
  color: var(--text-display);
  font-family: var(--font-display);
  font-size: var(--fs-h2);
  font-weight: var(--weight-bold);
  line-height: 1.1;
  letter-spacing: var(--ls-h2);
}

.spec__mono {
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: var(--fs-micro-s);
  line-height: 1;
  letter-spacing: var(--ls-micro-s);
  text-transform: uppercase;
}

.spec__numeric {
  color: var(--text-display);
  font-family: var(--font-numeric);
  font-size: var(--fs-numeric-m);
  font-weight: var(--weight-numeric);
  line-height: var(--lh-numeric-m);
}

/* ==========================================================================
   Auth
   Signed-out pages. No sidebar, one card, one action.
   ========================================================================== */

.auth {
  display: grid;
  place-items: center;
  min-block-size: 100dvh;
  padding: var(--space-8);
}

.auth__main {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  inline-size: 100%;
  /* A measure, not a size token: the form column stays readable and does not stretch. */
  max-inline-size: 24rem;
}

.auth__brand {
  display: flex;
  justify-content: center;
}

.auth__tenant {
  margin: 0;
  color: var(--text-dim);
  font-size: var(--fs-label);
  line-height: var(--lh-label);
  text-align: center;
}

.auth__card {
  padding: var(--space-9);
  border: var(--border-width-default) solid var(--border-default);
  border-radius: var(--radius-lg);
  background: var(--raised);
}

.auth__title {
  margin: 0;
  color: var(--text-display);
  font-family: var(--font-display);
  font-size: var(--fs-h1-s);
  font-weight: var(--weight-bold);
  line-height: var(--lh-h1-s);
  letter-spacing: var(--ls-h1-s);
}

.auth__lede {
  margin: var(--space-3) 0 var(--space-8);
  color: var(--text-dim);
  font-size: var(--fs-body-m);
  line-height: var(--lh-body-m);
}

.auth__form {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

.auth__actions {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  margin-block-start: var(--space-2);
}

.auth__actions .button {
  inline-size: 100%;
}

.auth__link {
  color: var(--text-secondary);
  font-size: var(--fs-label);
  line-height: var(--lh-label);
  text-align: center;
  text-decoration: underline;
  text-decoration-color: var(--steel);
  text-underline-offset: var(--space-1);
}

.auth__error {
  margin: 0;
  padding: var(--space-5);
  border: var(--border-width-default) solid color-mix(in srgb, var(--ember) 55%, transparent);
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--ember) 12%, transparent);
  color: var(--ember);
  font-size: var(--fs-label);
  line-height: var(--lh-body-s);
}

/* ==========================================================================
   Direction
   Arabic ships later; these rules exist so it does not need a rewrite.
   ========================================================================== */

/* Arabic copy takes the Arabic family. Numbers keep theirs: Doto, Geist Mono and the tabular
 * column all set their family explicitly, so they are unaffected. */
[dir="rtl"] body {
  font-family: var(--font-arabic);
}

/* The select chevron is drawn from inline-end plus block-end borders, so the rotation has to
 * flip with the direction or it points the wrong way. The lockup needs nothing: the pack has
 * a dedicated Arabic file and logo.html selects it. */
[dir="rtl"] .field__chevron {
  transform: translateY(-70%) rotate(-45deg);
}

/* Numeric columns stay right-aligned in RTL, as DESIGN.md §9 requires. `end` would put them
 * on the left there, so the RTL case asks for `start` — logical, and the same physical side. */
[dir="rtl"] .table .is-numeric {
  text-align: start;
}

/* Preview-only: lays component specimens out side by side. Not a product layout. */
.preview-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-6);
  align-items: start;
  margin-block-end: var(--space-8);
}

.preview-grid--three {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

.preview-stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  max-inline-size: min(64ch, 100%);
}

/* Vertically stacked blocks with one gap. */
.stack > * + * {
  margin-block-start: var(--space-6);
}

/* Two equal columns, for a pair of cards. */
.split {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-6);
}

.split--three {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-5);
}

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

/* A search bar: the control takes the room, the button stays its own width. */
.dirsearch {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  max-inline-size: min(32rem, 100%);
  margin-block-end: var(--space-6);
}

.dirsearch .field__control {
  flex: 1 1 auto;
  inline-size: auto;
}

.stackv {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

.swatches--five {
  grid-template-columns: repeat(5, minmax(0, 1fr));
}

/* Gallery sections stack inside one card body, so a label that follows a block needs the
 * gap the block above it does not provide. */
.card__body .nav-group__label:not(:first-child) {
  margin-block-start: var(--space-6);
}

/* HTMX: the indicator is present but collapsed until its request is in flight. Opacity
 * alone would leave a 4-bar hole in the page while nothing is loading. */
.htmx-indicator {
  display: none;
}

.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator {
  display: block;
}

/* ==========================================================================
   Responsive
   Breakpoints are media queries, which cannot read custom properties, so 1024 is the
   literal value of --bp-lg written once, here, and nowhere else.
   ========================================================================== */

@media (max-width: 1023.98px) {
  .shell {
    grid-template-columns: minmax(0, 1fr);
  }

  .sidebar {
    position: fixed;
    inset-block: 0;
    inset-inline-start: 0;
    z-index: 40;
    transform: translateX(calc(-100% * var(--sidebar-shift, 1)));
    transition: transform var(--motion-base) var(--ease-standard);
  }

  /* The drawer sits on the inline-start edge, so it leaves towards the opposite sign in RTL.
   * A transform is used rather than an inline offset so the nav does not reflow while it
   * moves; the sign is the only direction-dependent part. */
  [dir="rtl"] .sidebar {
    --sidebar-shift: -1;
  }

  body[data-sidebar="open"] .sidebar {
    transform: translateX(0);
  }

  .scrim {
    position: fixed;
    inset: 0;
    z-index: 30;
    background: color-mix(in srgb, var(--ink) 72%, transparent);
  }

  body[data-sidebar="open"] .scrim {
    display: block;
  }

  .topbar {
    gap: var(--space-5);
    padding-inline: var(--space-5);
  }

  .topbar__menu {
    display: inline-flex;
  }

  .topbar__date {
    display: none;
  }

  /* No mobile search state exists. A dead icon is worse than no icon, so it is hidden
   * until there is a route behind it. */
  .topbar__search {
    display: none;
  }

  .page {
    padding-block: var(--space-7);
    padding-inline: var(--space-5);
  }

  .page__head {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-5);
  }

  .page__actions {
    justify-content: flex-start;
  }

  .kpi-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

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

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

/* Four numbers in a row stop being readable before the card does, so the row folds to one
 * column below 640. There is no mobile KPI design to follow; this is the least surprising
 * arrangement that keeps the Doto figure on one line. */
@media (max-width: 639.98px) {
  .kpi-row {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Every two- and three-column arrangement collapses: a rail narrower than its content is
   * how a phone gets a horizontal scrollbar. */
  .cols,
  .split,
  .split--three,
  .form__grid {
    grid-template-columns: minmax(0, 1fr);
  }

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

  .gallery > * {
    grid-column: 1 / -1;
  }

  .dirsearch {
    max-inline-size: 100%;
  }

  /* Three columns fit a phone with tighter padding. */
  .table[data-columns="3"] {
    min-inline-size: 0;
  }

  .table[data-columns="3"] th,
  .table[data-columns="3"] td {
    padding-inline: var(--space-5);
  }

  /* Four or more do not fit, at any padding: one pill or one email pushes the last column
   * past the card and it is clipped. Rows stack into labelled blocks and the header row
   * goes, which keeps every value readable rather than hiding a column. */
  .table[data-columns="4"],
  .table[data-columns="5"],
  .table[data-columns="6"] {
    min-inline-size: 0;
  }

  .table[data-columns="4"] thead,
  .table[data-columns="5"] thead,
  .table[data-columns="6"] thead {
    display: none;
  }

  .table[data-columns="4"] tr,
  .table[data-columns="5"] tr,
  .table[data-columns="6"] tr {
    display: block;
    padding-block: var(--space-4);
  }

  .table[data-columns="4"] tbody tr + tr,
  .table[data-columns="5"] tbody tr + tr,
  .table[data-columns="6"] tbody tr + tr {
    border-block-start: var(--border-width-hairline) solid var(--border-hairline);
  }

  .table[data-columns="4"] td,
  .table[data-columns="5"] td,
  .table[data-columns="6"] td {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-5);
    block-size: auto;
    padding-block: var(--space-1);
    padding-inline: var(--space-5);
    border-block-start: 0;
    text-align: start;
  }

  .table[data-columns="4"] td::before,
  .table[data-columns="5"] td::before,
  .table[data-columns="6"] td::before {
    content: attr(data-label);
    flex: 0 0 auto;
    color: var(--text-dim);
    font-family: var(--font-mono);
    font-size: var(--fs-micro-s);
    line-height: var(--lh-micro-s);
    letter-spacing: var(--ls-micro-s);
    text-transform: uppercase;
  }
}

@keyframes row-in {
  from {
    opacity: 0;
    transform: translateY(var(--space-1));
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* ==========================================================================
   Arabic
   Arabic is a connected script. Three Latin assumptions break it: tracking pulls the
   letter joins apart, a line box of 1 clips the descenders and the dots below the
   baseline, and Geist Mono has no Arabic glyphs at all - so a label that names it
   silently falls back to whatever the machine happens to have.

   DESIGN.md 9 says IBM Plex Sans Arabic carries all Arabic copy and numbers stay in
   Geist and Doto. Every rule here is that sentence applied to one component. Sizes
   step from microS (9px) to micro (11px) because Arabic counters are smaller at the
   same px, and 9px Arabic is below the size this product should ever ask anyone to
   read. Layout and direction are not touched: the shell already does those.
   ========================================================================== */

:lang(ar) {
  letter-spacing: normal;
}

/* Labels: the components that name a mono face in Latin name the Arabic face here. */
:lang(ar) .nav-group__label,
:lang(ar) .kpi__label,
:lang(ar) .fact__label,
:lang(ar) .spec__label,
:lang(ar) .table th,
:lang(ar) .table td::before,
:lang(ar) .card__meta {
  font-family: var(--font-arabic);
  font-size: var(--fs-micro);
  line-height: 1.4;
  letter-spacing: normal;
  text-transform: none;
}

/* Running text: enough line box for the glyphs, and no tracking. */
:lang(ar) .nav-item,
:lang(ar) .nav-item__label,
:lang(ar) .kpi__unit,
:lang(ar) .kpi__caption,
:lang(ar) .fact__value,
:lang(ar) .field__label,
:lang(ar) .field__hint,
:lang(ar) .field__error,
:lang(ar) .field__control,
:lang(ar) .checkbox,
:lang(ar) .table td,
:lang(ar) .button,
:lang(ar) .card__title,
:lang(ar) .note__title,
:lang(ar) .note__body,
:lang(ar) .note__row,
:lang(ar) .empty__title,
:lang(ar) .empty__body,
:lang(ar) .error__text,
:lang(ar) .page__lede,
:lang(ar) .page__body,
:lang(ar) .page__subtitle,
:lang(ar) .sidebar__tenant,
:lang(ar) .sidebar__name,
:lang(ar) .topbar__crumb,
:lang(ar) .topbar__date,
:lang(ar) .topbar__search-input,
:lang(ar) .flash__message,
:lang(ar) .auth__title,
:lang(ar) .auth__lede,
:lang(ar) .auth__link,
:lang(ar) .auth__tenant,
:lang(ar) .auth__error {
  letter-spacing: normal;
  line-height: 1.5;
}

/* Controls name the UI face in Latin; in Arabic they name the Arabic face. */
:lang(ar) .button,
:lang(ar) .pill,
:lang(ar) .field__control,
:lang(ar) .topbar__search-input,
:lang(ar) .topbar__lang-btn {
  font-family: var(--font-arabic);
}

/* Headings take the Arabic family. The display face has no Arabic glyphs, so leaving it
 * in place is a fallback, not a choice. Leading opens to 1.4: the stack's 1.1 is drawn
 * for a Latin cap height and cuts the dots above an Arabic letter. */
:lang(ar) .page__title,
:lang(ar) .page__subtitle,
:lang(ar) .card__title,
:lang(ar) .note__title,
:lang(ar) .empty__title,
:lang(ar) .error__title,
:lang(ar) .auth__title,
:lang(ar) .spec__display {
  font-family: var(--font-arabic);
  font-weight: var(--weight-semibold);
  letter-spacing: normal;
  line-height: 1.4;
}

/* Numbers stay in their own faces in both languages: small figures in Geist, the one big
 * figure in Doto. Neither face carries Arabic letters, so this is the only place the
 * Arabic family is deliberately not used. */
:lang(ar) .kpi__number,
:lang(ar) .spec__numeric {
  font-family: var(--font-numeric);
}

:lang(ar) .table .is-numeric,
:lang(ar) .kpi__caption b {
  font-family: var(--font-ui);
  font-variant-numeric: tabular-nums;
}

/* A date field is a control, not copy. Its picker reads left to right even in an Arabic
 * page; forcing it back keeps the segments in the order the control expects. */
:lang(ar) input[type="date"],
:lang(ar) input[type="month"] {
  direction: ltr;
  text-align: end;
}
