/* ===========================================================================
   Application shell and components.
   No literal colour appears below this line - everything comes from tokens.css.
   =========================================================================== */

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

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

body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--fs-base);
  line-height: var(--lh);
  color: var(--text);
  background: var(--app-bg);
  background-image: var(--app-wash);
  background-attachment: fixed;
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 { margin: 0; font-weight: 600; line-height: var(--lh-tight); color: var(--text-strong); }
h1 { font-size: var(--fs-2xl); letter-spacing: -0.02em; }
h2 { font-size: var(--fs-xl); letter-spacing: -0.01em; }
h3 { font-size: var(--fs-lg); }
h4 { font-size: var(--fs-md); }
p  { margin: 0 0 var(--s-3); }
a  { color: var(--text-brand); text-decoration: none; }
a:hover { text-decoration: underline; }
img { max-width: 100%; height: auto; }
hr { border: 0; border-top: 1px solid var(--divider); margin: var(--s-5) 0; }

:focus-visible {
  outline: none;
  box-shadow: var(--ring);
  border-radius: var(--r-xs);
}

.icon { flex: none; vertical-align: -0.18em; }

/* ------------------------------------------------------------------ shell */

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

.sidebar {
  width: var(--sidebar-w);
  flex: none;
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--rail-bg);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  border-right: 1px solid var(--panel-border);
  z-index: 40;
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-4) var(--s-4);
  border-bottom: 1px solid var(--divider);
  min-height: var(--topbar-h);
}
.brand__emblem { width: 44px; height: auto; flex: none; }
.brand__text { min-width: 0; }
.brand__title {
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--text-strong);
  letter-spacing: -0.01em;
  line-height: 1.25;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.brand__sub {
  font-size: var(--fs-xs);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  margin-top: 2px;
}

.nav { flex: 1; overflow-y: auto; padding: var(--s-3) var(--s-2) var(--s-6); }
.nav__group { margin-bottom: var(--s-4); }
.nav__label {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  color: var(--text-subtle);
  padding: var(--s-2) var(--s-3);
  font-weight: 600;
}
.nav__link {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: 9px var(--s-3);
  border-radius: var(--r-sm);
  color: var(--text-muted);
  font-weight: 500;
  font-size: var(--fs-base);
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.nav__link:hover { background: var(--row-hover); color: var(--text); text-decoration: none; }
.nav__link.is-active {
  background: var(--brand-soft);
  color: var(--text-brand);
  font-weight: 600;
  box-shadow: inset 2px 0 0 var(--brand);
}
.nav__count {
  margin-left: auto;
  font-size: var(--fs-xs);
  font-weight: 600;
  background: var(--tint-neutral-bg);
  color: var(--tint-neutral);
  padding: 1px 7px;
  border-radius: var(--r-pill);
}
.nav__link.is-active .nav__count { background: var(--brand-soft-2); color: var(--text-brand); }

/* ------------------------------------------------------------------- main */

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

/* The bar is full-bleed so its tint and rule run edge to edge; its contents
   sit in the same box as .content below, so the search box and the avatar
   line up with the page panels instead of floating out to the window edge. */
.topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  min-height: var(--topbar-h);
  display: flex;
  background: var(--glass-tint-soft);
  backdrop-filter: blur(var(--glass-blur)) saturate(140%);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(140%);
  border-bottom: 1px solid var(--panel-border);
}
.topbar__inner {
  flex: 1;
  min-width: 0;
  width: 100%;
  max-width: var(--page-max);
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-2) var(--page-gutter);
}
.topbar__search { flex: 1; max-width: 420px; position: relative; }
.topbar__tools { display: flex; align-items: center; gap: 4px; }
/* Qualified with .btn: the base .btn rule sets display later in this file and
   would otherwise win the tie - the same trap that put the mobile hamburger on
   desktop. */
.btn.topbar__searchlink { display: none; }
.topbar__lang {
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
  margin-left: 5px;
}
.topbar__tools .btn--icon { width: auto; min-width: var(--btn-h); padding: 0 9px; }
.topbar__rule {
  width: 1px;
  height: 22px;
  background: var(--divider);
  margin: 0 var(--s-2);
}
/* The toggle shows the state it will move to, so the glyph is a promise
   rather than a description of where you already are. */
.theme-off { display: none; }
[data-theme="dark"] .theme-on { display: none; }
[data-theme="dark"] .theme-off { display: inline-flex; }

/* ---- account menu ------------------------------------------------------- */

.usermenu { position: relative; }
.usermenu__trigger {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: 4px 8px 4px 4px;
  border-radius: var(--r-control);
  cursor: pointer;
  list-style: none;
  transition: background var(--fast) var(--ease);
}
.usermenu__trigger::-webkit-details-marker { display: none; }
.usermenu__trigger:hover { background: var(--row-hover); }
.usermenu[open] .usermenu__trigger { background: var(--row-hover); }
.usermenu__trigger .avatar { width: 34px; height: 34px; }

.usermenu__id { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.usermenu__name { font-size: var(--fs-sm); font-weight: 600; color: var(--text-strong); white-space: nowrap; }
.usermenu__role,
.usermenu__mail { font-size: var(--fs-xs); color: var(--text-muted); white-space: nowrap; }
.usermenu__caret { color: var(--text-subtle); transition: transform var(--fast) var(--ease); }
.usermenu[open] .usermenu__caret { transform: rotate(180deg); }

.usermenu__panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 60;
  min-width: 248px;
  padding: var(--s-2);
  background: var(--panel-solid);
  border: 1px solid var(--panel-border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-3);
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.usermenu__head {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-3);
  margin-bottom: 4px;
  border-bottom: 1px solid var(--divider);
}
.usermenu__head .avatar { width: 38px; height: 38px; }
.usermenu__head .usermenu__name { white-space: normal; }
.usermenu__mail { overflow: hidden; text-overflow: ellipsis; }

.usermenu__item {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: 9px var(--s-3);
  border-radius: var(--r-control);
  color: var(--text);
  font-size: var(--fs-sm);
  font-weight: 500;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.usermenu__item:hover { background: var(--row-hover); color: var(--text-strong); text-decoration: none; }
.usermenu__item .icon { color: var(--text-subtle); }
.usermenu__item:hover .icon { color: var(--brand); }
.usermenu__item--danger { margin-top: 4px; border-top: 1px solid var(--divider); border-radius: 0 0 var(--r-control) var(--r-control); }
.usermenu__item--danger:hover { background: var(--tint-danger-bg); color: var(--tint-danger); }
.usermenu__item--danger:hover .icon { color: var(--tint-danger); }

/* Below the search breakpoint the trigger keeps only the avatar and caret. */
@media (max-width: 860px) {
  .usermenu__trigger .usermenu__id { display: none; }
  .topbar__lang { display: none; }
}
.topbar__search .icon {
  position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
  color: var(--text-subtle); pointer-events: none;
}
.topbar__search input[type="search"] { padding-left: 38px; }
.topbar__spacer { flex: 1; }

/* Qualified with .btn on purpose: the base .btn rule sets display later in
   this file, so a bare .menu-btn selector loses the tie and the mobile
   hamburger renders on desktop, shoving the search box out of line with the
   page below. The media query at the foot of this file re-shows it. */
.btn.menu-btn { display: none; }

.content {
  flex: 1;
  width: 100%;
  max-width: var(--page-max);
  margin: 0 auto;
  padding: var(--s-6) var(--page-gutter) var(--s-9);
}

/* ------------------------------------------------------------ page header */

.page-head {
  display: flex;
  align-items: flex-end;
  gap: var(--s-4);
  flex-wrap: wrap;
  margin-bottom: var(--s-5);
}
.page-head__text { min-width: 0; flex: 1 1 260px; }
.page-head__eyebrow {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  color: var(--text-subtle);
  font-weight: 600;
  margin-bottom: 3px;
}
.page-head__desc { color: var(--text-muted); margin: 6px 0 0; font-size: var(--fs-md); }
.page-head__actions { display: flex; gap: var(--s-2); flex-wrap: wrap; }

.crumbs { display: flex; align-items: center; gap: 6px; font-size: var(--fs-sm); color: var(--text-subtle); margin-bottom: var(--s-2); }
.crumbs a { color: var(--text-muted); }

/* ------------------------------------------------------------------ panel */

.panel {
  background: var(--panel-bg);
  backdrop-filter: blur(var(--glass-blur)) saturate(135%);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(135%);
  border: 1px solid var(--panel-border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-glass);
  container-type: inline-size;
}
/* Spacing between stacked panels comes from the container's gap (.stack, .grid)
   or an explicit utility - never from a sibling margin, which would push every
   card but the first down inside a grid row. */
.panel--solid { background: var(--panel-solid); backdrop-filter: none; -webkit-backdrop-filter: none; }
.panel--flush { overflow: hidden; }

/* Cards sitting side by side in a grid: the body absorbs the slack so the
   footers line up even when the copy above them runs to different lengths. */
.panel--equal { display: flex; flex-direction: column; }
.panel--equal > .panel__body { flex: 1; }
.panel--equal .panel-blurb { min-height: 3.2em; }

.panel__head {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--divider);
  flex-wrap: wrap;
}
.panel__title { font-size: var(--fs-md); font-weight: 600; color: var(--text-strong); }
.panel__sub { font-size: var(--fs-sm); color: var(--text-muted); }
.panel__actions { margin-left: auto; display: flex; gap: var(--s-2); flex-wrap: wrap; }
.panel__body { padding: var(--s-5); }
.panel__body--tight { padding: var(--s-4); }
.panel__foot {
  padding: var(--s-4) var(--s-5);
  border-top: 1px solid var(--divider);
  display: flex;
  align-items: center;
  gap: var(--s-3);
  flex-wrap: wrap;
}

/* ------------------------------------------------------------------- grid */

.grid { display: grid; gap: var(--s-5); }
.grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.grid--sidebar { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
.grid--main { grid-template-columns: minmax(0, 1fr) 330px; align-items: start; }

@media (max-width: 1180px) {
  .grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grid--main, .grid--sidebar { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 860px) {
  .grid--2, .grid--3 { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 560px) {
  .grid--4 { grid-template-columns: minmax(0, 1fr); }
}

/* ------------------------------------------------------------------- stat */

.stat {
  background: var(--panel-bg);
  backdrop-filter: blur(var(--glass-blur)) saturate(135%);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(135%);
  border: 1px solid var(--panel-border);
  border-radius: var(--r-lg);
  padding: var(--s-4) var(--s-5);
  box-shadow: var(--shadow-glass);
  position: relative;
  overflow: hidden;
  min-width: 0;
}
.stat::after {
  content: "";
  position: absolute; inset: 0 0 auto 0; height: 3px;
  background: var(--brand-grad);
  opacity: 0.85;
}
.stat__label {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  color: var(--text-subtle);
  font-weight: 600;
  display: flex; align-items: center; gap: 6px;
}
.stat__value {
  font-size: var(--fs-2xl);
  font-weight: 700;
  color: var(--text-strong);
  letter-spacing: -0.02em;
  margin-top: 6px;
  line-height: 1.1;
  overflow-wrap: anywhere;
}
.stat__meta { margin-top: 6px; font-size: var(--fs-sm); color: var(--text-muted); display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.stat__delta { display: inline-flex; align-items: center; gap: 3px; font-weight: 600; }
.stat__delta--up { color: var(--tint-success); }
.stat__delta--down { color: var(--tint-danger); }
.stat__delta--flat { color: var(--text-subtle); }

/* compact strip above a list */
.stat-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--s-3);
  margin-bottom: var(--s-4);
}
.stat-strip .stat { padding: var(--s-3) var(--s-4); }
.stat-strip .stat__value { font-size: var(--fs-xl); }

/* -------------------------------------------------------------- buttons */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: var(--btn-h);
  padding: 0 var(--btn-pad-x);
  font-size: var(--fs-base);
  font-weight: 500;
  border-radius: var(--r-control);
  border: 1px solid var(--input-border);
  background: var(--input-bg);
  color: var(--text);
  font-family: inherit;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease),
              transform var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
  text-decoration: none;
}
.btn:hover { background: var(--panel-raised); border-color: var(--brand-ring); text-decoration: none; }
.btn:active { transform: translateY(1px); }
.btn[disabled], .btn.is-disabled { opacity: 0.5; pointer-events: none; }

/* Flat, solid, no border and no drop shadow: a primary button is a block of
   brand colour, not a raised object. The darker hover is the only state
   change, so the control sits still under the pointer. */
.btn--primary {
  background: var(--brand);
  border-color: transparent;
  color: var(--brand-ink);
  box-shadow: none;
}
.btn--primary:hover { background: var(--brand-strong); border-color: transparent; filter: none; }
.btn--primary:active { background: var(--brand-deep); }
.btn--ghost { background: transparent; border-color: transparent; color: var(--text-muted); }
.btn--ghost:hover { background: var(--row-hover); color: var(--text); }
.btn--soft { background: var(--brand-soft); border-color: transparent; color: var(--text-brand); }
.btn--danger { background: var(--tint-danger-bg); border-color: transparent; color: var(--tint-danger); }
.btn--danger:hover { background: var(--tint-danger-bg); filter: brightness(0.97); }
.btn--sm { height: var(--control-h-sm); padding: 0 12px; font-size: var(--fs-sm); }
.btn--icon { width: var(--control-h); padding: 0; }
.btn--icon.btn--sm { width: var(--control-h-sm); }
.btn--block { width: 100%; }

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

/* --------------------------------------------------------------- badges */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.01em;
  white-space: nowrap;
  background: var(--tint-neutral-bg);
  color: var(--tint-neutral);
}
.badge--success { background: var(--tint-success-bg); color: var(--tint-success); }
.badge--warning { background: var(--tint-warning-bg); color: var(--tint-warning); }
.badge--danger  { background: var(--tint-danger-bg);  color: var(--tint-danger); }
.badge--info    { background: var(--tint-info-bg);    color: var(--tint-info); }
.badge--neutral { background: var(--tint-neutral-bg); color: var(--tint-neutral); }
.badge--brand   { background: var(--brand-soft);      color: var(--text-brand); }

.dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; flex: none; }

/* ------------------------------------------------------ permission grid */
/* A role's permissions: a matrix, not a form field, so it does not go through
   the matched-row engine. Checkboxes rather than toggles - the product has no
   toggle switches, and a checkbox is what a multi-select actually is. */

.permgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: var(--s-5);
}

.permgrid__group {
  border: 1px solid var(--panel-border);
  border-radius: var(--r-lg);
  padding: var(--s-3) var(--s-4) var(--s-4);
  margin: 0;
  min-width: 0;
}

.permgrid__legend {
  padding: 0 var(--s-2);
  margin-left: calc(var(--s-2) * -1);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--text-muted);
}

.permgrid__item {
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
  padding: 7px 0;
  min-width: 0;
}

.permgrid__item input[type="checkbox"] {
  width: 18px;
  height: 18px;
  flex: none;
  margin: 1px 0 0;
  accent-color: var(--brand);
  cursor: pointer;
}

label.permgrid__item { cursor: pointer; border-radius: var(--r-sm); }
label.permgrid__item:hover .permgrid__name { color: var(--text-strong); }
label.permgrid__item:focus-within {
  outline: 2px solid var(--ring);
  outline-offset: 2px;
}

.permgrid__text { display: grid; gap: 1px; min-width: 0; }
.permgrid__name { font-size: var(--fs-sm); color: var(--text); line-height: var(--lh-tight); }
.permgrid__key {
  font-size: var(--fs-xs);
  color: var(--text-subtle);
  font-variant-numeric: tabular-nums;
}

/* Read-only: the tick says granted, the cross says not, and the whole row
   dims when it is not - so a glance down the column reads as a shape. */
.permgrid__item--read { color: var(--text-subtle); }
.permgrid__item--read > svg { flex: none; margin-top: 2px; }
.permgrid__item--read .permgrid__name { color: var(--text-muted); }
.permgrid__item--read.is-on { color: var(--tint-success); }
.permgrid__item--read.is-on .permgrid__name { color: var(--text-strong); font-weight: 500; }

@media (max-width: 720px) {
  .permgrid { gap: var(--s-4); }
}

/* ---------------------------------------------------------------- table */

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

table.data {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-base);
  min-width: 640px;
}
table.data th {
  text-align: left;
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  /* --text-subtle is only 3.5:1 on the header tint, and these are links. */
  color: var(--text-muted);
  font-weight: 600;
  padding: var(--s-3);
  border-bottom: 1px solid var(--divider);
  white-space: nowrap;
  background: var(--glass-tint-soft);
  position: sticky;
  top: 0;
  z-index: 2;
}
table.data th a { color: inherit; display: inline-flex; align-items: center; gap: 4px; }
table.data th.is-sorted { color: var(--text-brand); }
table.data td {
  padding: var(--s-3);
  border-bottom: 1px solid var(--divider);
  vertical-align: middle;
  height: var(--row-h);
}
table.data tbody tr { transition: background var(--fast) var(--ease); }
table.data tbody tr:hover { background: var(--row-hover); }
table.data tbody tr:last-child td { border-bottom: 0; }
table.data td.num, table.data th.num { text-align: right; font-variant-numeric: tabular-nums; }
table.data td.nowrap { white-space: nowrap; }
table.data .check-col { width: 42px; }

.cell-main { display: flex; align-items: center; gap: var(--s-2); min-width: 152px; }
.cell-main__text { min-width: 0; }
/* break-word, not anywhere: a long single token may break, but a person's
   name must never be split down the middle because the column got squeezed. */
.cell-title { font-weight: 600; color: var(--text-strong); display: block; overflow-wrap: break-word; }
.cell-sub { font-size: var(--fs-sm); color: var(--text-muted); display: block; overflow-wrap: break-word; }

.avatar {
  width: 38px; height: 38px; border-radius: var(--r-sm);
  object-fit: cover; flex: none;
  background: var(--brand-soft);
  color: var(--text-brand);
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: var(--fs-sm);
  border: 1px solid var(--panel-border);
}
.avatar--lg { width: 64px; height: 64px; font-size: var(--fs-lg); border-radius: var(--r-md); }
.avatar--xl { width: 104px; height: 104px; font-size: var(--fs-2xl); border-radius: var(--r-md); }

.row-actions { display: flex; gap: 2px; justify-content: flex-end; opacity: 0.35; transition: opacity var(--fast) var(--ease); }
tr:hover .row-actions, tr:focus-within .row-actions { opacity: 1; }
@media (hover: none) { .row-actions { opacity: 1; } }

/* ------------------------------------------------------------- toolbars */

.toolbar {
  display: flex;
  gap: var(--s-2);
  align-items: center;
  flex-wrap: wrap;
  padding: var(--s-3) var(--s-4);
  border-bottom: 1px solid var(--divider);
}
/* The search takes the slack but is capped: uncapped it swallowed the row and
   left every select pinned at its minimum, which is what made the filter bar
   look unbalanced. Selects share what is left evenly; a date field asks for
   only what a date needs. */
.toolbar__search { flex: 3 1 240px; min-width: 190px; max-width: 460px; position: relative; }
.toolbar__field { flex: 1 1 190px; min-width: 165px; }
.toolbar__field--date { flex: 0 1 172px; min-width: 150px; }
/* A filter row is one line of controls, so its buttons take the control
   height rather than the standalone button height - 40 next to 44 reads as a
   misalignment, not as a hierarchy. */
.toolbar > .btn { flex: none; height: var(--control-h); }
.toolbar__search .icon { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--text-subtle); pointer-events: none; }
.toolbar__search input[type="search"] { padding-left: 38px; }

.segmented {
  display: inline-flex;
  padding: 3px;
  gap: 2px;
  background: var(--input-bg);
  border: 1px solid var(--input-border);
  border-radius: var(--r-sm);
  flex-wrap: wrap;
}
.segmented a {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 0 12px; height: 34px;
  border-radius: var(--r-xs);
  font-size: var(--fs-sm); font-weight: 500;
  color: var(--text-muted);
}
.segmented a:hover { background: var(--row-hover); text-decoration: none; color: var(--text); }
/* Solid, not --brand-grad: that gradient runs from blue-400 to blue-600, and
   no single ink contrasts with both ends - the dark-theme tab measured 2.6:1.
   A gradient is fine behind decoration, never behind text. */
.segmented a.is-active { background: var(--brand); color: var(--brand-ink); }
.segmented .count {
  font-size: var(--fs-xs); font-weight: 700;
  background: var(--tint-neutral-bg); color: var(--tint-neutral);
  padding: 0 6px; border-radius: var(--r-pill);
}
/* The pill simply inverts the tab: the tab's ink becomes the fill and the
   tab's own background becomes the number. Solid, no outline, and it cannot
   disagree with the tab behind it in either theme - 5.0:1 light, 5.9:1 dark.
   (A translucent white fill would look the part but lands at 3.2:1.) */
.segmented a.is-active .count {
  background: var(--brand-ink);
  color: var(--brand);
}

.bulkbar {
  display: none;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  background: var(--brand-soft);
  border-bottom: 1px solid var(--panel-border);
}
.bulkbar.is-open { display: flex; }
.bulkbar__count { font-weight: 600; color: var(--text-brand); }

/* ----------------------------------------------------------- pagination */

.pagination {
  display: flex; align-items: center; gap: var(--s-2);
  padding: var(--s-3) var(--s-4);
  border-top: 1px solid var(--divider);
  flex-wrap: wrap;
}
.pagination__info { color: var(--text-muted); font-size: var(--fs-sm); margin-right: auto; }
.pagination a, .pagination span.page-num {
  min-width: 34px; height: 34px;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0 8px;
  border-radius: var(--r-xs);
  font-size: var(--fs-sm); font-weight: 500;
  color: var(--text-muted);
  border: 1px solid transparent;
}
.pagination a:hover { background: var(--row-hover); text-decoration: none; color: var(--text); }
/* Qualified to match the specificity of `.pagination span.page-num` above,
   which otherwise keeps its muted colour and leaves grey text on brand blue
   at 1.2:1. */
.pagination a.is-current,
.pagination span.page-num.is-current {
  background: var(--brand);
  color: var(--brand-ink);
  font-weight: 600;
}

/* ---------------------------------------------------------------- empty */

.empty { text-align: center; padding: var(--s-9) var(--s-5); }
.empty__icon {
  width: 62px; height: 62px; margin: 0 auto var(--s-4);
  border-radius: var(--r-lg);
  display: grid; place-items: center;
  background: var(--brand-grad-soft);
  color: var(--text-brand);
  border: 1px solid var(--panel-border);
}
.empty__title { font-weight: 600; color: var(--text-strong); font-size: var(--fs-lg); }
.empty__text { color: var(--text-muted); margin-top: 6px; }
.empty__action { margin-top: var(--s-4); }

/* ---------------------------------------------------------------- forms */

.form-panel { container-type: inline-size; }

label.field-label {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: var(--fs-base);
  font-weight: 500;
  color: var(--text);
  margin-bottom: var(--field-label-gap);
  line-height: 1.3;
}
.field-label__text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.field-label .req { color: var(--tint-danger); margin-left: 1px; }
.field-label .opt {
  color: var(--text-subtle);
  font-weight: 500;
  font-size: var(--fs-xs);
  flex: none;
}

/* A tip is the sentence a clerk would ask for out loud. It hangs off the
   label rather than sitting under the control, so it costs no vertical
   rhythm and the row below stays where it is. */
.field-tip {
  display: inline-flex;
  align-items: center;
  color: var(--text-subtle);
  cursor: help;
  flex: none;
}
.field-tip:hover, .field-tip:focus-visible { color: var(--brand); }

.field-foot { min-height: 0; }
.field-hint, .field-error {
  display: flex;
  align-items: flex-start;
  gap: 4px;
  font-size: var(--fs-xs);
  line-height: 1.4;
  margin-top: var(--field-foot-gap);
}
.field-hint { color: var(--text-subtle); }
.field-error { color: var(--tint-danger); font-weight: 500; }
.field-hint .icon, .field-error .icon { margin-top: 1px; }

input[type="text"], input[type="email"], input[type="password"], input[type="number"],
input[type="date"], input[type="tel"], input[type="url"], input[type="search"],
select, textarea {
  width: 100%;
  height: var(--control-h);
  padding: 0 var(--control-pad-x);
  font-family: inherit;
  font-size: var(--fs-base);
  font-weight: 400;
  line-height: 20px;
  color: var(--text);
  background: var(--input-bg);
  border: 1px solid var(--input-border);
  border-radius: var(--r-control);
  transition: border-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
  appearance: none;
}
textarea {
  height: auto;
  min-height: 116px;
  padding: 11px var(--control-pad-x);
  line-height: var(--lh);
  resize: vertical;
}
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--input-focus);
  box-shadow: var(--ring);
}
input::placeholder, textarea::placeholder { color: var(--text-subtle); }
input[readonly], input[disabled], select[disabled], textarea[disabled] {
  background: var(--tint-neutral-bg);
  color: var(--text-muted);
  cursor: not-allowed;
}
select { padding-right: 34px; }

input:hover:not(:focus):not([readonly]):not([disabled]),
textarea:hover:not(:focus):not([disabled]) { border-color: var(--ice-400); }

/* ---- the control shell: a leading icon and the error state -------------
   The icon is painted over the control, never inside its box, so the input
   keeps its own geometry and a field with an icon still lines up exactly
   with the field beside it that has none. */
.control { position: relative; display: block; }
.control__icon {
  position: absolute;
  left: 12px;
  top: calc(var(--control-h) / 2);
  transform: translateY(-50%);
  color: var(--text-subtle);
  pointer-events: none;
  z-index: 2;
  transition: color var(--fast) var(--ease);
}
.control--icon input,
.control--icon .combo__button { padding-left: var(--field-icon-pad); }

.control:focus-within .control__icon { color: var(--brand); }

/* A trailing action lives inside the control box - a reveal, a clear, a
   pick. It keeps clear of the text by reserving padding on the input. */
.control__action {
  position: absolute;
  right: 6px;
  top: calc(var(--control-h) / 2);
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  border-radius: var(--r-xs);
  background: transparent;
  color: var(--text-subtle);
  cursor: pointer;
  z-index: 2;
  transition: color var(--fast) var(--ease), background var(--fast) var(--ease);
}
.control__action:hover { color: var(--text); background: var(--row-hover); }
.control__action[aria-pressed="true"] { color: var(--brand); }
/* The button shows the eye while hidden and the struck-through eye while
   shown, so the glyph states what a click will undo. */
.control__action .reveal-off,
.control__action[aria-pressed="true"] .reveal-on { display: none; }
.control__action[aria-pressed="true"] .reveal-off { display: inline-flex; }
.control__action > span { display: inline-flex; }
.control--action input { padding-right: 40px; }

/* A date field carries one calendar, ours, on the left. The native indicator
   is stretched over the whole control and made invisible, so clicking
   anywhere still opens the browser's picker - the affordance survives, the
   duplicate glyph does not. Firefox draws no indicator and is unaffected. */
.control--icon input[type="date"] { position: relative; }
.control--icon input[type="date"]::-webkit-calendar-picker-indicator {
  position: absolute;
  inset: 0;
  width: 100%;
  height: auto;
  margin: 0;
  padding: 0;
  opacity: 0;
  cursor: pointer;
}

.field.is-error input,
.field.is-error select,
.field.is-error textarea,
.field.is-error .combo__button { border-color: var(--tint-danger); }
.field.is-error input:focus,
.field.is-error textarea:focus { box-shadow: 0 0 0 3px var(--tint-danger-bg); }
.field.is-error .control__icon { color: var(--tint-danger); }

/* Matched rows: a row holds one kind of control, and each field borrows the
   row's label / control / hint tracks so a two-line hint under one field can
   never shrink the control beside it. */
.field-rows { display: flex; flex-direction: column; gap: var(--field-gap-y); }

/* Row gap is zero on purpose. These three tracks are one field's own label,
   control and hint - they are held together by the label's margin and the
   hint's, not by the grid. The gap between one field and the next comes from
   .field-rows above; the gap between fields side by side is the column gap.
   Giving the grid a row gap would space a field's own parts as widely as it
   spaces whole fields, which is what made the form read as loose boxes. */
.field-row {
  display: grid;
  gap: 0 var(--field-gap-x);
  grid-template-columns: repeat(var(--cols, 1), minmax(0, 1fr));
  grid-template-rows: auto auto auto;
  align-items: start;
}
.field {
  display: grid;
  grid-row: span 3;
  grid-template-rows: subgrid;
  min-width: 0;
}
@supports not (grid-template-rows: subgrid) {
  .field { grid-row: auto; grid-template-rows: auto auto auto; }
}
.field--full { grid-column: 1 / -1; }

/* Stacked, there is nothing to align across, so the field stops borrowing the
   row's tracks and becomes an ordinary grid item - which lets the row gap do
   what it cannot do under subgrid: separate one field from the next without
   also prising apart a field's own label, control and hint. */
@container (max-width: 720px) {
  .field-row {
    grid-template-columns: minmax(0, 1fr);
    /* One track, not three. The three-track template exists so fields can
       borrow it through subgrid; once a field stops borrowing it, the two
       spare tracks would still contribute their row gaps and leave 32px of
       dead space inside every field. */
    grid-template-rows: auto;
    row-gap: var(--field-gap-y);
  }
  .field { grid-row: auto; grid-template-rows: auto auto auto; }
}

/* A fieldset's own heading needs air above it, but not when it opens the
   panel - the panel padding already provides that. */
.field-rows + .fieldset__legend,
.field-row + .fieldset__legend { margin-top: var(--s-5); }

.fieldset { border: 0; margin: 0 0 var(--s-6); padding: 0; }
.fieldset__legend {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  color: var(--text-subtle);
  font-weight: 600;
  padding: 0 0 var(--s-3);
  display: block;
  width: 100%;
  border-bottom: 1px solid var(--divider);
  margin-bottom: var(--s-4);
}

/* file picker */
.filefield {
  display: flex; align-items: center; gap: var(--s-3);
  border: 1px dashed var(--input-border);
  border-radius: var(--r-sm);
  padding: 9px 12px;
  background: var(--input-bg);
  min-height: var(--control-h);
}
.filefield__preview {
  width: 34px; height: 34px; border-radius: var(--r-xs);
  object-fit: cover; flex: none;
  background: var(--brand-soft); color: var(--text-brand);
  display: grid; place-items: center;
}
.filefield__name { flex: 1; min-width: 0; font-size: var(--fs-sm); color: var(--text-muted); overflow-wrap: anywhere; }
.filefield input[type="file"] { display: none; }

/* money and prefixed inputs */
.input-affix { display: flex; align-items: stretch; }
.input-affix__pre {
  display: inline-flex; align-items: center; padding: 0 12px;
  background: var(--tint-neutral-bg); color: var(--text-muted);
  border: 1px solid var(--input-border); border-right: 0;
  border-radius: var(--r-sm) 0 0 var(--r-sm);
  font-weight: 600; font-size: var(--fs-sm);
}
.input-affix input { border-radius: 0 var(--r-sm) var(--r-sm) 0; }

/* -------------------------------------------------------------- stepper */

.stepper { display: grid; grid-template-columns: 236px minmax(0, 1fr); align-items: start; }
@media (max-width: 900px) { .stepper { grid-template-columns: minmax(0, 1fr); } }

.steprail {
  padding: var(--s-5);
  border-right: 1px solid var(--divider);
  position: sticky;
  top: calc(var(--topbar-h) + var(--s-4));
}
@media (max-width: 900px) {
  .steprail { border-right: 0; border-bottom: 1px solid var(--divider); position: static; }
}
.steprail__bar { height: 4px; border-radius: var(--r-pill); background: var(--tint-neutral-bg); overflow: hidden; margin-bottom: var(--s-4); }
.steprail__fill { height: 100%; background: var(--brand-grad); border-radius: var(--r-pill); transition: width var(--normal) var(--ease); }
.steprail__list { display: flex; flex-direction: column; gap: 2px; }
@media (max-width: 900px) { .steprail__list { flex-direction: row; overflow-x: auto; } }
.steprail__item {
  display: flex; align-items: center; gap: var(--s-3);
  padding: 8px 10px; border-radius: var(--r-sm);
  background: none; border: 0; font: inherit; text-align: left;
  color: var(--text-muted); cursor: pointer; width: 100%;
  white-space: nowrap;
}
.steprail__item:hover { background: var(--row-hover); }
.steprail__item.is-active { background: var(--brand-soft); color: var(--text-brand); font-weight: 600; }
.steprail__num {
  width: 24px; height: 24px; border-radius: 50%;
  display: grid; place-items: center; flex: none;
  font-size: var(--fs-xs); font-weight: 700;
  background: var(--tint-neutral-bg); color: var(--tint-neutral);
}
.steprail__item.is-active .steprail__num { background: var(--brand); color: var(--brand-ink); }
.steprail__item.is-done .steprail__num { background: var(--tint-success-bg); color: var(--tint-success); }

.steppanel { padding: var(--s-5); display: none; }
.steppanel.is-active { display: block; }
.steppanel__title { margin-bottom: var(--s-4); }

.form-foot {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-4) var(--s-5);
  border-top: 1px solid var(--divider);
  flex-wrap: wrap;
}
.form-foot__spacer { flex: 1; }

/* ------------------------------------------------------------- detail UI */

.deflist { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--s-4) var(--s-5); }
.def__label { font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: var(--tracking-caps); color: var(--text-subtle); font-weight: 600; }
.def__value { margin-top: 3px; color: var(--text); overflow-wrap: anywhere; }
.def__value--strong { font-weight: 600; color: var(--text-strong); }

.record-head {
  display: flex; gap: var(--s-5); align-items: flex-start; flex-wrap: wrap;
  padding: var(--s-5);
}
.record-head__text { flex: 1 1 260px; min-width: 0; }
.record-head__meta { display: flex; gap: var(--s-3); flex-wrap: wrap; margin-top: var(--s-3); color: var(--text-muted); font-size: var(--fs-sm); }
.record-head__meta span { display: inline-flex; align-items: center; gap: 5px; }

.tabs { display: flex; gap: 2px; padding: 0 var(--s-5); border-bottom: 1px solid var(--divider); overflow-x: auto; }
.tabs a {
  padding: 11px 14px; font-weight: 500; color: var(--text-muted);
  border-bottom: 2px solid transparent; white-space: nowrap;
}
.tabs a:hover { color: var(--text); text-decoration: none; }
.tabs a.is-active { color: var(--text-brand); border-bottom-color: var(--brand); }

.timeline { display: flex; flex-direction: column; gap: var(--s-4); }
.timeline__item { display: flex; gap: var(--s-3); }
.timeline__dot {
  width: 30px; height: 30px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: var(--brand-soft); color: var(--text-brand);
}
.timeline__body { min-width: 0; }
.timeline__title { font-weight: 600; color: var(--text-strong); }
.timeline__meta { font-size: var(--fs-sm); color: var(--text-muted); }

/* A short numbered procedure, as on the permit form's receipt lookup. */
.steps-list {
  list-style: none;
  margin: 0; padding: 0;
  counter-reset: step;
  display: flex; flex-direction: column; gap: var(--s-3);
}
.steps-list li {
  counter-increment: step;
  display: grid; grid-template-columns: 26px 1fr; gap: var(--s-3);
  align-items: start;
  color: var(--text-muted); font-size: var(--fs-sm); line-height: var(--lh);
}
.steps-list li::before {
  content: counter(step);
  width: 26px; height: 26px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--brand-soft); color: var(--text-brand);
  font-size: var(--fs-xs); font-weight: 700; font-variant-numeric: tabular-nums;
}
/* A step already taken. The number stays rather than becoming a tick: it is
   what the step is called everywhere else on the page. Same treatment the
   stepper rail gives a finished step. */
.steps-list li.is-done { color: var(--text); }
.steps-list li.is-done::before {
  background: var(--tint-success-bg);
  color: var(--tint-success);
}

/* The row you are already looking at, inside a history table. */
.data tbody tr.is-current > td { background: var(--brand-soft-2); }
.data tbody tr.is-current > td:first-child { box-shadow: inset 3px 0 0 var(--brand); }

.progress { height: 8px; border-radius: var(--r-pill); background: var(--tint-neutral-bg); overflow: hidden; }
.progress__fill { height: 100%; border-radius: var(--r-pill); background: var(--brand-grad); }
.progress__fill--success { background: var(--tint-success); }
.progress__fill--danger { background: var(--tint-danger); }

/* --------------------------------------------------------------- charts */

.chart { width: 100%; display: block; overflow: visible; }
.chart-wrap { position: relative; }
.chart text { font-family: var(--font); font-size: 11px; fill: var(--axis-text); }
.chart .grid-line { stroke: var(--grid-line); stroke-width: 1; }
.chart .axis-line { stroke: var(--grid-line); stroke-width: 1; }
.chart .bar { transition: opacity var(--fast) var(--ease); }
.chart .bar:hover { opacity: 0.82; }
.chart .line { fill: none; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.chart .area { stroke: none; }
.chart .point { stroke: var(--panel-solid); stroke-width: 2; }

.legend { display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-4); margin-top: var(--s-3); }
.legend__item { display: inline-flex; align-items: center; gap: 7px; font-size: var(--fs-sm); color: var(--text-muted); }
.legend__swatch { width: 10px; height: 10px; border-radius: 3px; flex: none; }

/* A flag sits on the text baseline beside the name it belongs to. */
.flag + * { margin-left: 2px; }

.ranked { display: flex; flex-direction: column; gap: var(--s-3); }
.ranked__row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--s-2) var(--s-3); align-items: center; }
.ranked__name { font-weight: 500; color: var(--text); min-width: 0; overflow-wrap: anywhere; }
.ranked__value { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--text-strong); }
.ranked__track {
  grid-column: 1 / -1;
  display: block;
  height: 6px;
  border-radius: var(--r-pill);
  background: var(--tint-neutral-bg);
  overflow: hidden;
}
.ranked__fill { display: block; height: 100%; border-radius: var(--r-pill); }

/* ---- nationality board -------------------------------------------------- */

/* One accent colour, one card size. The interest comes from the flags and from
   the numbers being easy to compare, not from twelve competing hues. */
.natboard {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--s-3);
  grid-template-columns: repeat(auto-fill, minmax(158px, 1fr));
}
.natboard__card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--s-4) var(--s-4) var(--s-5);
  border: 1px solid var(--panel-border);
  border-radius: var(--r-md);
  background: var(--panel-solid);
  overflow: hidden;
  transition: border-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease),
              transform var(--fast) var(--ease);
}
.natboard__card:hover {
  border-color: var(--brand-ring);
  box-shadow: var(--shadow-2);
  transform: translateY(-1px);
}

.natboard__top { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--s-3); }
.natboard__top .flag { box-shadow: 0 0 0 1px var(--glass-line), var(--shadow-1); border-radius: 3px; }
.natboard__noflag {
  display: inline-grid; place-items: center;
  width: 30px; height: 23px; border-radius: 3px;
  background: var(--tint-neutral-bg); color: var(--text-subtle);
}
.natboard__rank {
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--text-subtle);
}
.natboard__rank::before { content: "#"; opacity: 0.55; }

.natboard__name {
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--text-muted);
  line-height: 1.3;
  overflow-wrap: anywhere;
}
.natboard__figures { display: flex; align-items: baseline; gap: var(--s-2); }
.natboard__count {
  font-size: var(--fs-xl);
  font-weight: 700;
  line-height: 1.15;
  color: var(--text-strong);
  font-variant-numeric: tabular-nums;
}
.natboard__share { font-size: var(--fs-xs); color: var(--text-subtle); font-variant-numeric: tabular-nums; }

/* Scaled to the leader, so a row of near-full meters correctly reads as an
   evenly spread workforce rather than as a ranking with a clear winner. */
.natboard__meter {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 3px;
  background: var(--tint-neutral-bg);
}
.natboard__fill { display: block; height: 100%; background: var(--brand); }

/* ---- dot plot ----------------------------------------------------------- */

.dots { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--s-3); }
.dots__row {
  display: grid;
  grid-template-columns: minmax(84px, 34%) minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s-3);
}
.dots__name { font-weight: 500; color: var(--text); min-width: 0; overflow-wrap: anywhere; }
.dots__plot { position: relative; height: 12px; display: block; }
.dots__plot::before {
  content: ""; position: absolute; left: 0; right: 0; top: 50%;
  height: 1px; background: var(--divider);
}
.dots__rule {
  position: absolute; left: 0; top: 50%; height: 2px;
  transform: translateY(-50%); border-radius: var(--r-pill);
  background: var(--ice-300);
}
.dots__dot {
  position: absolute; top: 50%; width: 11px; height: 11px; border-radius: 50%;
  transform: translate(-50%, -50%);
  box-shadow: 0 0 0 2px var(--panel-solid);
}
.dots__value { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--text-strong); }

/* ---- composition band --------------------------------------------------- */

/* Natural height on purpose: capping this to the panel would squeeze the key
   back into whatever the neighbouring panel happened to need. This one sets
   the row's height and the tiles beside it stretch to meet it. */
.composition { display: flex; flex-direction: column; }
.composition__bar {
  display: flex;
  height: 38px;
  border-radius: var(--r-control);
  overflow: hidden;
  background: var(--tint-neutral-bg);
  flex: none;
}
.composition__seg { display: block; height: 100%; min-width: 2px; }
.composition__key {
  list-style: none;
  margin: var(--s-6) 0 0;
  padding: 0;
  display: grid;
  gap: var(--s-3) var(--s-5);
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  align-content: start;
}
.composition__key li {
  display: grid;
  grid-template-columns: 10px minmax(0, 1fr) auto auto;
  align-items: center;
  gap: var(--s-2);
  font-size: var(--fs-sm);
}
.composition__swatch { width: 10px; height: 10px; border-radius: 3px; }
.composition__name { color: var(--text); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.composition__value { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--text-strong); }
.composition__pct { font-variant-numeric: tabular-nums; color: var(--text-subtle); min-width: 4ch; text-align: right; }

/* ---- heat tiles --------------------------------------------------------- */

/* Rows share whatever height the row's tallest panel sets, so the tiles fill
   the panel instead of leaving a band of empty card under them. */
.heat {
  display: grid;
  gap: var(--s-2);
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  grid-auto-rows: minmax(74px, 1fr);
  height: 100%;
}
.heat__tile {
  position: relative;
  padding: var(--s-3);
  border-radius: var(--r-control);
  background: color-mix(in srgb, var(--brand) calc(var(--heat) * 100%), var(--panel-solid));
  border: 1px solid var(--panel-border);
  min-height: 74px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  color: var(--text);
}
.heat__value {
  font-size: var(--fs-xl); font-weight: 700; line-height: 1;
  color: var(--text-strong); font-variant-numeric: tabular-nums;
}
/* Full-strength ink, not the muted token: the tile is tinted, so a muted grey
   drops under 3:1 against it at this size. */
.heat__name { font-size: var(--fs-xs); line-height: 1.3; color: var(--text); overflow-wrap: anywhere; }

.kpi-spark { height: 40px; width: 100%; display: block; margin-top: var(--s-2); }

/* ---------------------------------------------------------------- login */

/* =========================================================================
   Sign-in
   Two halves: the left says who issues these permits and what the system
   does, the right does one job. No card floats inside another card, and the
   heading belongs to the form rather than hovering above it.
   ========================================================================= */

.auth-body { margin: 0; }

.auth {
  min-height: 100vh;
  display: grid;
  grid-template-columns: minmax(0, 1.08fr) minmax(0, 1fr);
}

/* ---- brand side --------------------------------------------------------- */

.auth__brand {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: var(--s-8);
  padding: clamp(var(--s-7), 4vw, var(--s-9)) clamp(var(--s-6), 3.6vw, 72px);
  background:
    radial-gradient(900px 520px at 88% 8%, var(--brand-glow), transparent 62%),
    linear-gradient(158deg, var(--blue-700) 0%, var(--blue-900) 52%, var(--blue-950) 100%);
  color: var(--ice-0);
  /* The skyline is drawn as tall as 17.4% of the panel's width, and the panel
     is a little over half the window - so ~9vw. 11vw keeps the address clear
     of the rooftops, and the ceiling has to stay above 9vw at the widest
     screen we expect (2560px) or the two would meet again. */
  padding-bottom: clamp(var(--s-8), 11vw, 260px);
}
/* The arms themselves are the texture - not an abstract blob. Cropped by one
   edge only: clipped top and bottom at once reads as a mistake rather than a
   watermark. */
.auth__wash {
  position: absolute;
  right: -16%;
  bottom: 8%;
  width: clamp(360px, 44vw, 580px);
  opacity: 0.075;
  z-index: -1;
  pointer-events: none;
}

/* The city the ministry sits in, along the foot of the panel. It is a
   silhouette in one colour, so it reads as a horizon rather than competing
   with the arms washed in behind it. Finer detail than the emblem, so it
   carries a little more weight than that 7.5% and still sits under the type. */
.auth__skyline {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: -1;
  line-height: 0;
  pointer-events: none;
  color: var(--ice-0);
  opacity: 0.17;
}
.auth__skyline svg {
  display: block;
  width: 100%;
  height: auto;
}

.auth__lockup { display: flex; align-items: center; gap: var(--s-3); }
.auth__lockup-country {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  opacity: 0.72;
  font-weight: 500;
}
.auth__lockup-org { font-size: var(--fs-md); font-weight: 600; line-height: 1.3; }

.auth__hero { margin-top: auto; }
.auth__title {
  font-size: clamp(30px, 3.4vw, 44px);
  font-weight: 700;
  line-height: 1.12;
  letter-spacing: -0.025em;
  max-width: 14ch;
  color: var(--ice-0);
}
.auth__lead {
  margin: var(--s-4) 0 0;
  font-size: var(--fs-md);
  line-height: 1.6;
  opacity: 0.8;
  max-width: 48ch;
}

.auth__points {
  list-style: none;
  margin: var(--s-7) 0 0;
  padding: 0;
  display: grid;
  gap: var(--s-4);
  max-width: 46ch;
}
.auth__points li { display: flex; gap: var(--s-4); align-items: flex-start; }

/* The chip is a span, so the description rule below must be scoped to
   .auth__point-text - an unscoped `.auth__points span` also matches the chip
   and quietly turns its `display: grid` into `block`, which drops the glyph
   into the top-left corner and dims it to 72%. */
.auth__point-icon {
  flex: none;
  width: 42px;
  height: 42px;
  display: inline-grid;
  place-items: center;
  border-radius: 12px;
  background: var(--on-brand-fill);
  box-shadow: inset 0 0 0 1px var(--on-brand-line);
  color: var(--ice-0);
}
.auth__point-icon .icon { vertical-align: 0; }

.auth__point-text { padding-top: 2px; }
.auth__point-text strong { display: block; font-size: var(--fs-base); font-weight: 600; letter-spacing: -0.005em; }
.auth__point-text span { display: block; font-size: var(--fs-sm); line-height: 1.55; opacity: 0.72; margin-top: 2px; }

.auth__brand-foot { margin-top: auto; font-size: var(--fs-sm); line-height: 1.7; opacity: 0.6; }

/* ---- form side ---------------------------------------------------------- */

.auth__panel {
  position: relative;
  display: grid;
  grid-template-rows: auto 1fr auto;
  padding: var(--s-5) clamp(var(--s-5), 3vw, var(--s-8));
  background: var(--app-bg);
  background-image: var(--app-wash);
}
.auth__tools { display: flex; justify-content: flex-end; gap: var(--s-2); }

.auth__form {
  width: 100%;
  max-width: 452px;
  margin: 0 auto;
  align-self: center;
  padding: var(--s-6) 0;
}

/* The form is the one object on this half, so it is the one thing raised off
   the surface - a solid panel with a hairline and a soft shadow. The heading
   lives inside it: a heading floating above a box is what made the earlier
   version look unfinished. */
.auth__card {
  background: var(--panel-solid);
  border: 1px solid var(--panel-border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-2);
  padding: clamp(var(--s-5), 4vw, var(--s-7));
}

/* Repeats the authority on the half where the brand panel is hidden. */
.auth__brand-sm { display: none; align-items: center; gap: var(--s-3); margin-bottom: var(--s-6); }
.auth__brand-sm span { font-size: var(--fs-sm); font-weight: 600; color: var(--text-strong); line-height: 1.3; }

.auth__heading {
  font-size: var(--fs-2xl);
  font-weight: 700;
  letter-spacing: -0.025em;
  color: var(--text-strong);
}
.auth__sub { margin: 6px 0 0; color: var(--text-muted); font-size: var(--fs-base); }
.auth__flashes { margin-top: var(--s-5); }
.auth__fields { margin-top: var(--s-6); }
.auth__submit { margin-top: var(--s-5); height: 46px; }

.auth__secure {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin: var(--s-4) 0 0;
  font-size: var(--fs-xs);
  line-height: 1.5;
  color: var(--text-subtle);
}
.auth__secure .icon { margin-top: 1px; flex: none; }

.auth__aside {
  margin-top: var(--s-5);
  padding: 0 var(--s-2);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px var(--s-2);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}
.auth__aside a {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-weight: 600;
  color: var(--text-brand);
}

.auth__legal { text-align: center; font-size: var(--fs-xs); color: var(--text-subtle); }

/* ---- narrow ------------------------------------------------------------- */

@media (max-width: 980px) {
  .auth { grid-template-columns: minmax(0, 1fr); }
  .auth__brand { display: none; }
  .auth__brand-sm { display: flex; }
}
@media (max-width: 420px) {
  .auth__panel { padding-inline: var(--s-4); }
}

/* --------------------------------------------------------------- verify */

.verify-page { max-width: 640px; margin: 0 auto; padding: var(--s-8) var(--s-5); }
.verify-result { display: flex; gap: var(--s-4); align-items: flex-start; padding: var(--s-5); border-radius: var(--r-lg); }
.verify-result--success { background: var(--tint-success-bg); color: var(--tint-success); }
.verify-result--danger  { background: var(--tint-danger-bg);  color: var(--tint-danger); }
.verify-result--warning { background: var(--tint-warning-bg); color: var(--tint-warning); }
.verify-result__title { font-size: var(--fs-lg); font-weight: 700; }

/* ------------------------------------------------------------ utilities */

.muted { color: var(--text-muted); }
.subtle { color: var(--text-subtle); }
.strong { font-weight: 600; color: var(--text-strong); }
/* A reference number: a permit, receipt or certificate serial. Poppins with
   tabular figures, so a column of them still lines up digit for digit. */
.mono {
  font-family: var(--font-ref);
  font-variant-numeric: tabular-nums;
  font-weight: 500;
  letter-spacing: 0.01em;
}
.nums { font-variant-numeric: tabular-nums; }
.caps { text-transform: uppercase; letter-spacing: var(--tracking-caps); font-size: var(--fs-xs); font-weight: 600; }
.right { text-align: right; }
.center { text-align: center; }
.nowrap { white-space: nowrap; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hide { display: none !important; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.stack { display: flex; flex-direction: column; gap: var(--s-4); }
.stack--sm { gap: var(--s-2); }
.row { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; }
.row--tight { gap: var(--s-2); }
.spacer { flex: 1; }
.mt-0 { margin-top: 0; } .mt-2 { margin-top: var(--s-2); } .mt-3 { margin-top: var(--s-3); }
.mt-4 { margin-top: var(--s-4); } .mt-5 { margin-top: var(--s-5); } .mt-6 { margin-top: var(--s-6); }
.mb-0 { margin-bottom: 0; } .mb-3 { margin-bottom: var(--s-3); } .mb-4 { margin-bottom: var(--s-4); }
.mb-5 { margin-bottom: var(--s-5); }

.notice {
  display: flex; gap: var(--s-3); align-items: flex-start;
  padding: var(--s-3) var(--s-4); border-radius: var(--r-sm);
  background: var(--tint-info-bg); color: var(--tint-info);
  font-size: var(--fs-sm);
}
.notice--warning { background: var(--tint-warning-bg); color: var(--tint-warning); }
.notice--danger  { background: var(--tint-danger-bg);  color: var(--tint-danger); }
.notice--success { background: var(--tint-success-bg); color: var(--tint-success); }
.notice strong { color: inherit; }

/* --------------------------------------------------------- small screens */

@media (max-width: 1000px) {
  :root { --sidebar-w: 0px; }
  .sidebar {
    position: fixed; left: 0; top: 0; bottom: 0;
    width: 272px;
    transform: translateX(-100%);
    transition: transform var(--normal) var(--ease);
    box-shadow: var(--shadow-3);
  }
  .sidebar.is-open { transform: none; }
  .btn.menu-btn { display: inline-flex; }
  .content { padding: var(--s-5) var(--s-4) var(--s-8); }
  .scrim-nav {
    position: fixed; inset: 0; background: var(--scrim); z-index: 35;
    opacity: 0; pointer-events: none; transition: opacity var(--normal) var(--ease);
  }
  .scrim-nav.is-open { opacity: 1; pointer-events: auto; }
}

@media (max-width: 620px) {
  .topbar__search { display: none; }
  .btn.topbar__searchlink { display: inline-flex; }
  .content { padding: var(--s-4) var(--s-3) var(--s-8); }
  .panel__body { padding: var(--s-4); }
  .panel__head { padding: var(--s-3) var(--s-4); }
  h1 { font-size: var(--fs-xl); }
}

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