/*
 * Bilbilde operator UI. Hand-written CSS using the UI-SPEC tokens as custom
 * properties (UI-SPEC allows this in Phase 1 in place of the Tailwind
 * standalone build). Page CSS lives under /static/css/.
 *
 * 2026-10-07 restyle ("Ledgerix"-style dashboard): white cards with a hairline border and no
 * shadows, soft rectangles instead of pills, a top bar with an icon-only nav. Big numbers are
 * large and light. Later the same day the neutrals moved to the Gallardo Studio brand (logo
 * package v1, Even's own artwork): Grafitt #161616 for text, primary actions, the active nav and
 * inverted tiles; a warm Studiohvit #F2F0EB canvas with warm-grey borders; Aluminium #9EA3A8 for
 * decorative and inactive neutrals. Neon green (#75FB90) stays, but only as the small status
 * marker and highlight, never as a large area. The logo files live in /static/brand/.
 * Typeface: the self-hosted Urbanist variable font (SIL OFL 1.1, /static/fonts/OFL-Urbanist.txt),
 * the design's own face (Even, 2026-10-07). Manrope (SIL OFL 1.1,
 * /static/fonts/OFL.txt) stays loaded as the first fallback. Swapping typefaces is a one-line
 * change to --font-sans.
 * Every asset is same-origin: no external URL may appear in this file (CSP 'self').
 */

@font-face {
  font-family: "Manrope";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("/static/fonts/manrope-latin-wght-normal.woff2") format("woff2");
}

/* Urbanist (SIL OFL 1.1), the design's typeface. Latin subset of the variable font from Google
   Fonts (v18), vendored so no external URL is needed. */
@font-face {
  font-family: "Urbanist";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/static/fonts/urbanist-latin-wght-normal.woff2") format("woff2");
}

/* Metric-matched local fallback so the swap to Manrope does not shift the layout.
   Values measured against Arial from the vendored woff2 (advance width and ascent/descent). */
@font-face {
  font-family: "Manrope Fallback";
  src: local("Arial"), local("ArialMT"), local("Helvetica Neue"), local("Helvetica");
  size-adjust: 97.92%;
  ascent-override: 108.87%;
  descent-override: 30.64%;
  line-gap-override: 0%;
}

:root {
  /* Brand palette (Gallardo Studio logo package v1) plus the green status marker */
  --palette-green: #75fb90; /* status markers and small highlights only */
  --palette-dark: #161616; /* Grafitt */
  --palette-studio-white: #f2f0eb; /* Studiohvit */
  --palette-gray: #9ea3a8; /* Aluminium: decorative, never body text on white (2.5:1) */
  --palette-white: #ffffff;
  --palette-light-gray: #dcd8cf; /* warm grey that sits with Studiohvit */

  /* Spacing */
  --space-xs: 4px;
  --space-sm: 8px;
  --space-md: 16px;
  --space-lg: 24px;
  --space-xl: 32px;
  --space-2xl: 48px;
  --space-3xl: 64px;

  /* Fixed dimensions */
  --shell-gutter: 32px;
  --shell-topbar-height: 80px;
  --sidebar-width: 0px; /* the sidebar became the top bar; kept so old calc() rules stay valid */
  --topbar-height: 56px; /* in-page toolbars (viewer) */
  --chrome-height: calc(var(--shell-topbar-height) + var(--space-lg));
  --control-height: 40px;
  --control-height-touch: 44px;
  --nav-item-size: 44px; /* Even, 2026-10-08: top-bar icons 25 px (were 20) in a 44 px square */
  --nav-icon-size: 25px;
  --table-row-min-height: 60px;
  --badge-height: 26px;
  --dropzone-min-height: 160px;
  --dropzone-compact-min-height: 96px;
  --tile-min-width: 240px;
  --content-max-width: 1440px;
  --side-panel-width: 384px;
  --login-card-width: 400px;
  --stat-icon-size: 36px;
  --marker-size: 8px;

  /* Radii: soft rectangles. --radius-pill keeps its name for the page CSS that uses it, but the
     design has no fully rounded pills, so it is now a control-sized rounding. */
  --radius-frame: 20px;
  --radius-panel: 16px;
  --radius-card: 16px;
  --radius-control: 10px;
  --radius-small: 6px;
  --radius-pill: 10px;
  --radius-chip: 8px;

  /* Typography. The design tops out at SemiBold, so "bold" is 600 here. */
  --font-sans: "Urbanist", "Manrope", "Manrope Fallback", ui-sans-serif, system-ui, -apple-system, "Segoe UI",
    Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  /* Even, 2026-10-08: all running text two px larger than the first design */
  --text-small: 14px;
  --text-label: 15px;
  --text-body: 17px;
  --text-heading: 20px;
  --text-title: 24px;
  --text-stat: 40px;
  --text-display: 32px;
  --leading-label: 1.4;
  --leading-body: 1.5;
  --leading-heading: 1.25;
  --leading-display: 1.15;
  --tracking-display: -0.03em;
  --tracking-heading: -0.015em;
  --tracking-body: -0.005em;
  --tracking-stat: -0.04em;
  --weight-light: 300;
  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-bold: 600;

  /* Colour: warm Studiohvit canvas, white cards, Grafitt primary, green status marker */
  --color-canvas: var(--palette-studio-white);
  --color-frame: var(--palette-dark);
  --color-frame-raised: #232322;
  --color-frame-border: #33322f;
  --color-frame-text: var(--palette-white);
  --color-frame-text-soft: #e6e3dc;
  --color-frame-text-muted: var(--palette-gray);
  --color-dominant: var(--color-canvas);
  --color-secondary: var(--palette-white);
  --color-accent: var(--palette-dark);
  --color-accent-hover: #2c2b29;
  --color-destructive: #c2392b;
  --color-destructive-hover: #a32d21;
  --color-text: var(--palette-dark);
  /* Body-size secondary text, warm grey: 5.6:1 on white, 4.9:1 on the Studiohvit canvas, 4.6:1 on
     the thumbnail grey. Aluminium (#9ea3a8, 2.5:1 on white) is only for large or decorative
     elements: inactive icons, disabled states, markers. Grafitt text is 18.1:1 on white and
     15.9:1 on the canvas. */
  --color-text-muted: #6b6760;
  --color-text-faint: var(--palette-gray);
  --color-border: #eae7e0;
  --color-border-strong: var(--palette-light-gray);
  --color-card-border: #e4e1d9;
  --color-green: var(--palette-green);
  --color-lime: var(--palette-green);
  --color-lime-strong: #4fe06d;
  --color-lavender: var(--palette-gray);
  --color-coral: #f26b5b;
  --color-amber: #f5b53d;
  --color-thumb-bg: #ece9e2;
  --color-viewer-canvas: #27272a;
  --color-row-hover: #f8f7f3;
  --color-dropzone-active-bg: #effef2;
  --color-focus: var(--palette-dark);
  --color-focus-on-dark: var(--palette-green);

  /* Status tones: text, background, border, marker */
  --tone-neutral-text: #3d3a35;
  --tone-neutral-bg: var(--palette-studio-white);
  --tone-neutral-border: #e4e1d9;
  --tone-neutral-marker: var(--palette-gray);
  --tone-progress-text: var(--color-text);
  --tone-progress-bg: var(--palette-white);
  --tone-progress-border: var(--palette-light-gray);
  --tone-progress-marker: var(--palette-dark);
  --tone-success-text: #12622a;
  --tone-success-bg: #effef2;
  --tone-success-border: #bdf5c8;
  --tone-success-marker: var(--palette-green);
  --tone-warning-text: #8a5300;
  --tone-warning-bg: #fff7e8;
  --tone-warning-border: #f7dca6;
  --tone-warning-marker: var(--color-amber);
  --tone-danger-text: #a3352a;
  --tone-danger-bg: #fff1ef;
  --tone-danger-border: #f8c9c2;
  --tone-danger-marker: var(--color-coral);

  --color-over-budget-bg: #fffaf0;
  --color-over-budget-border: var(--color-amber);

  /* Bake-off backdrops */
  --backdrop-grey: #808080;
  --backdrop-checker-light: #ffffff;
  --backdrop-checker-dark: #d4d4d8;
  --backdrop-white: #ffffff;
  --backdrop-black: #000000;

  accent-color: var(--color-accent);
}

/* ------------------------------------------------------------------ base */

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

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

body {
  min-height: 100vh;
  min-height: 100dvh;
  margin: 0;
  background: var(--color-canvas);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-size: var(--text-body);
  font-weight: var(--weight-regular);
  letter-spacing: var(--tracking-body);
  line-height: var(--leading-body);
  -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3,
p {
  margin: 0;
}

a {
  color: var(--color-text);
  text-decoration: underline;
  text-decoration-color: var(--palette-light-gray);
  text-underline-offset: 3px;
}

a:hover {
  text-decoration-color: currentColor;
}

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

[hidden] {
  display: none !important;
}

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

.display {
  font-size: var(--text-display);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-display);
  line-height: var(--leading-display);
}

.heading {
  font-size: var(--text-heading);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-heading);
  line-height: var(--leading-heading);
}

.label {
  font-size: var(--text-label);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-label);
}

.meta {
  color: var(--color-text-muted);
  font-size: var(--text-label);
  line-height: var(--leading-label);
}

.mono {
  font-family: var(--font-mono);
  letter-spacing: 0;
  text-transform: uppercase;
}

.num {
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.icon {
  flex: none;
  vertical-align: middle;
}

.icon--20 {
  width: 20px;
  height: 20px;
}

.icon--24 {
  width: 24px;
  height: 24px;
}

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

.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: grid;
  /* Brand and actions take their own width; the nav is centred in what is left, so the larger
     icons never run under the customer picker */
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-md);
  min-height: var(--shell-topbar-height);
  padding: 0 var(--shell-gutter);
  background: var(--color-canvas);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  justify-self: start;
  min-width: 0;
  color: var(--color-text);
  text-decoration: none;
}

/* The real logo (horizontal: symbol + outlined wordmark) from /static/brand/. The SVG carries its
   own clear space around the symbol, so it needs no extra padding. Never stretched: the height is
   fixed and the width follows the 1072:256 drawing. */
.brand__logo {
  display: block;
  flex: none;
  width: auto;
  height: 48px; /* Even, 2026-10-08: logo and dealer name 20 % larger (was 40 px) */
}

/* Tenant name: muted, and after a hairline divider when it sits next to the logo */
.brand__tenant {
  color: var(--color-text-muted);
  font-size: 17px;
  line-height: var(--leading-label);
  white-space: nowrap;
}

.brand > .brand__tenant {
  padding-left: 14px;
  border-left: 1px solid var(--color-border-strong);
}

/* Legacy CSS stand-in for the mark, kept only for the static sketches under .planning/sketches
   (their markup predates the logo package). Templates use the SVGs in /static/brand/. */
.brand__mark {
  flex: none;
  width: 36px;
  height: 36px;
  background: var(--palette-dark);
  border-radius: var(--radius-control);
}

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

.brand__name {
  overflow: hidden;
  font-size: 18px;
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-heading);
  line-height: 1.2;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Icon-only nav: a white pill group; the active page is a solid black rounded square */
.nav {
  position: relative;
  justify-self: center;
  display: flex;
  gap: var(--space-xs);
  padding: var(--space-xs);
  background: var(--color-secondary);
  border: 1px solid var(--color-card-border);
  border-radius: 14px;
}

.nav__item {
  position: relative;
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: var(--nav-item-size);
  height: var(--nav-item-size);
  border-radius: var(--radius-control);
  color: var(--color-text-muted);
  text-decoration: none;
}

.nav__item .icon {
  width: var(--nav-icon-size);
  height: var(--nav-icon-size);
}

.nav__item:hover {
  background: var(--color-canvas);
  color: var(--color-text);
}

/* Gliding hover indicator (nav-indicator.js). The script adds .nav--js; from then on the
   indicator draws the hover square instead of each item's own background, and it slides
   between items. Items sit above it; the black active square is unchanged. */
.nav__indicator {
  position: absolute;
  top: 0;
  left: 0;
  width: var(--nav-item-size);
  height: var(--nav-item-size);
  border-radius: var(--radius-control);
  background: var(--color-canvas);
  opacity: 0;
  pointer-events: none;
  transform: translate(var(--nav-indicator-x, 0), var(--nav-indicator-y, 0));
  transition:
    transform 180ms cubic-bezier(0.2, 0.8, 0.2, 1),
    opacity 120ms ease;
}

.nav--indicating .nav__indicator {
  opacity: 1;
}

.nav--js .nav__item:not(.nav__item--active):hover {
  background: transparent;
}

.nav--js .nav__item {
  z-index: 1;
}

/* The black active square as its own element, so it can glide from the previous page's item.
   With .nav--js the active item itself draws no background; the square sits under it. While it
   is gliding (.nav--gliding) the active icon keeps the muted colour, so it never shows white
   on the light canvas. */
.nav__active-indicator {
  position: absolute;
  top: 0;
  left: 0;
  width: var(--nav-item-size);
  height: var(--nav-item-size);
  border-radius: var(--radius-control);
  background: var(--palette-dark);
  opacity: 0;
  pointer-events: none;
  transform: translate(var(--nav-active-x, 0), var(--nav-active-y, 0));
}

.nav--active-ready .nav__active-indicator {
  opacity: 1;
}

.nav--animate .nav__active-indicator {
  transition: transform 200ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

.nav--active-ready .nav__item--active,
.nav--active-ready .nav__item--active:hover {
  background: transparent;
}

.nav--gliding .nav__item--active,
.nav--gliding .nav__item--active:hover {
  color: var(--color-text-muted);
}

.nav__item--active,
.nav__item--active:hover {
  background: var(--palette-dark);
  color: var(--palette-white);
}

.nav__item--active:focus-visible {
  outline-color: var(--palette-dark);
}

/* The label is the link's accessible name; visually it is a tooltip on hover and focus */
.nav__item > span,
.topbar__logout > span {
  position: absolute;
  top: calc(100% + 8px);
  left: 50%;
  z-index: 30;
  padding: 4px 8px;
  background: var(--palette-dark);
  border-radius: var(--radius-small);
  color: var(--palette-white);
  font-size: var(--text-small);
  font-weight: var(--weight-medium);
  line-height: 1.4;
  letter-spacing: 0;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, -2px);
  transition:
    opacity 120ms ease,
    transform 120ms ease;
}

.nav__item:hover > span,
.nav__item:focus-visible > span,
.topbar__logout:hover > span,
.topbar__logout:focus-visible > span {
  opacity: 1;
  transform: translate(-50%, 0);
}

@media (prefers-reduced-motion: reduce) {
  .nav__item > span,
  .topbar__logout > span,
  .nav__indicator,
  .nav--animate .nav__active-indicator {
    transition: none;
  }
}

.topbar__actions {
  display: flex;
  align-items: center;
  justify-self: end;
  gap: var(--space-sm);
}

.version-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-sm);
  height: var(--control-height);
  padding: 0 14px;
  background: var(--color-secondary);
  border: 1px solid var(--color-card-border);
  border-radius: var(--radius-control);
  color: var(--color-text);
  font-family: var(--font-mono);
  font-size: var(--text-small);
  font-weight: var(--weight-medium);
  letter-spacing: 0;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
}

.version-chip::before {
  width: var(--marker-size);
  height: var(--marker-size);
  background: var(--palette-green);
  border-radius: 2px;
  content: "";
}

.version-chip:hover {
  border-color: var(--color-text);
}

.button.topbar__logout {
  position: relative;
  width: var(--control-height);
  padding: 0;
  background: var(--color-secondary);
  border-color: var(--color-card-border);
  color: var(--color-text);
}

.button.topbar__logout:hover {
  border-color: var(--color-text);
}

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

.page {
  width: 100%;
  max-width: var(--content-max-width);
  margin: 0 auto;
  padding: var(--space-sm) var(--shell-gutter) var(--space-2xl);
}

.shell-breadcrumb,
.breadcrumb {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-bottom: var(--space-sm);
  color: var(--color-text-muted);
  font-size: var(--text-label);
}

.shell-breadcrumb > span:last-child,
.breadcrumb [aria-current] {
  color: var(--color-text);
  font-weight: var(--weight-medium);
}

.breadcrumb a {
  color: var(--color-text-muted);
  text-decoration: none;
}

.breadcrumb a:hover {
  color: var(--color-text);
  text-decoration: underline;
}

/* Pages with their own breadcrumb (detail pages) and the full-bleed viewer drop the shell one */
.page:has(.breadcrumb) > .shell-breadcrumb,
.page:has(> .viewer) > .shell-breadcrumb {
  display: none;
}

@media (max-width: 1023px) {
  :root {
    --shell-gutter: var(--space-lg);
  }

  .brand__tenant {
    display: none;
  }
}

/* The operator bar has the most nav items and the most actions: between 720 and 1279 px its nav
   moves to a centred second row instead of squeezing between brand and actions */
@media (min-width: 720px) and (max-width: 1279px) {
  body:has(.topbar--operator) {
    --shell-topbar-height: 144px;
  }

  .topbar--operator {
    grid-template-columns: minmax(0, 1fr) auto;
    row-gap: 12px;
    padding-top: 12px;
    padding-bottom: 12px;
  }

  .topbar--operator .nav {
    grid-column: 1 / -1;
    grid-row: 2;
  }
}

/* Below 720 px the bar wraps: brand and actions on top, the nav scrolls sideways underneath */
@media (max-width: 719px) {
  :root {
    --shell-gutter: var(--space-md);
    --shell-topbar-height: 132px;
    --nav-item-size: 42px;
    --nav-icon-size: 24px;
  }

  .topbar {
    position: static;
    grid-template-columns: minmax(0, 1fr) auto;
    row-gap: 12px;
    padding: 12px var(--shell-gutter);
  }

  .nav {
    grid-column: 1 / -1;
    grid-row: 2;
    justify-self: stretch;
    justify-content: space-between;
    overflow-x: auto;
    scrollbar-width: thin;
  }

  /* Tooltips would be clipped by the scrolling nav, and touch has no hover */
  .nav__item > span {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    border: 0;
    opacity: 1;
  }

  .version-chip {
    display: none;
  }

  /* Still above the 120 px minimum width for the horizontal logo; the symbol draws at ~26 px */
  .brand__logo {
    height: 38px;
  }
}

.page-header {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-md);
  margin-bottom: var(--space-lg);
}

.page-header__title {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}

.card {
  background: var(--color-secondary);
  border: 1px solid var(--color-card-border);
  border-radius: var(--radius-card);
}

/* Inverted card: black surface, white text, green accents */
.card--dark {
  background: var(--color-frame);
  border-color: var(--color-frame);
  color: var(--color-frame-text);
}

.card--dark .meta,
.card--dark .table th {
  color: var(--color-frame-text-muted);
}

.card--dark a {
  color: var(--color-frame-text);
}

.card--dark :focus-visible {
  outline-color: var(--color-focus-on-dark);
}

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

.stat-card__head {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}

.stat-icon {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: var(--stat-icon-size);
  height: var(--stat-icon-size);
  background: var(--color-canvas);
  border-radius: var(--radius-control);
  color: var(--color-text);
}

.stat-icon .icon {
  width: 18px;
  height: 18px;
}

.card--dark .stat-icon {
  background: var(--color-frame-raised);
  color: var(--color-frame-text);
}

.stats {
  display: grid;
  /* auto-fit: a short row of tiles stretches across the card instead of leaving empty tracks */
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 12px;
  margin: 0;
}

.stat {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  min-width: 0;
  padding: 18px 20px 20px;
}

.stat__label {
  display: inline-flex;
  align-items: center;
  gap: var(--space-sm);
  color: var(--color-text-muted);
  font-size: var(--text-label);
  font-weight: var(--weight-medium);
  line-height: var(--leading-label);
}

/* Tiny green marker before a KPI label, as in the design */
.stat__label::before {
  flex: none;
  width: var(--marker-size);
  height: var(--marker-size);
  background: var(--palette-green);
  border-radius: 2px;
  content: "";
}

.stat__value {
  margin: 0;
  overflow-wrap: anywhere;
  font-size: var(--text-stat);
  font-variant-numeric: tabular-nums;
  font-weight: var(--weight-light);
  letter-spacing: var(--tracking-stat);
  line-height: 1.1;
}

.stat__unit {
  color: var(--color-text-muted);
  font-size: var(--text-label);
  font-weight: var(--weight-regular);
  letter-spacing: 0;
}

/* One inverted tile per stat row for emphasis, like the design's dark KPI card */
.stats > .stat:first-child {
  background: var(--color-frame);
  border-color: var(--color-frame);
  color: var(--color-frame-text);
}

.stats > .stat:first-child .stat__label,
.stats > .stat:first-child .stat__unit {
  color: var(--color-frame-text-muted);
}

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

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: var(--control-height);
  padding: var(--space-sm) var(--space-md);
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  font: inherit;
  font-size: var(--text-label);
  font-weight: var(--weight-semibold);
  letter-spacing: 0;
  line-height: var(--leading-label);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}

.button--primary {
  background: var(--color-accent);
  color: #ffffff;
}

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

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

.button--secondary:hover {
  background: var(--color-row-hover);
  border-color: var(--color-text);
}

.button--destructive {
  background: var(--color-destructive);
  color: #ffffff;
}

.button--destructive:hover {
  background: var(--color-destructive-hover);
}

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

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

.button--primary:disabled:hover,
.button--primary[aria-disabled="true"]:hover {
  background: var(--color-accent);
}

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

@media (max-width: 767px) {
  .button,
  .input {
    min-height: var(--control-height-touch);
  }
}

/* ---------------------------------------------------------------- inputs */

.input {
  display: block;
  width: 100%;
  min-height: var(--control-height);
  padding: var(--space-sm) 12px;
  background: var(--color-secondary);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-control);
  color: var(--color-text);
  font: inherit;
  font-size: 16px;
}

.input:hover {
  border-color: var(--palette-gray);
}

/* Black border plus a green halo: the border change alone meets the 3:1 focus contrast */
.input:focus-visible,
select.input:focus,
textarea.input:focus {
  border-color: var(--color-text);
  outline: none;
  box-shadow: 0 0 0 3px var(--palette-green);
}

.input--invalid {
  border-color: var(--color-destructive);
}

.form-error {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  color: var(--color-destructive);
  font-size: var(--text-label);
  line-height: var(--leading-label);
}

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

.page:has(> .login-card) {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  min-height: 100dvh;
  padding-top: var(--space-2xl);
}

.login-card {
  width: 100%;
  max-width: var(--login-card-width);
  margin: 0 auto;
  padding: var(--space-xl);
}

.login-card__mark {
  display: block;
  margin-bottom: var(--space-lg);
}

/* Stacked logo (symbol over outlined wordmark), centred on the card */
.login-card__title {
  display: flex;
  justify-content: center;
  margin-bottom: var(--space-md);
}

.login-card__logo {
  display: block;
  width: auto;
  height: 96px;
}

.login-card .meta {
  margin-top: var(--space-xs);
}

.login-card__title + .meta {
  text-align: center;
}

.login-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  margin-top: var(--space-lg);
}

.login-form .button {
  margin-top: var(--space-sm);
}

.login-card .banner {
  margin-top: var(--space-md);
}

/* ---------------------------------------------------------------- tables */

.table-card {
  overflow: hidden;
}

.table-toolbar {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-md);
  padding: 12px 20px;
  border-bottom: 1px solid var(--color-border);
}

.card--dark .table-toolbar {
  border-bottom-color: var(--color-frame-border);
}

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

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: 16px;
  font-variant-numeric: tabular-nums;
}

.table th {
  padding: 14px 20px 12px;
  color: var(--color-text-muted);
  font-size: var(--text-small);
  font-weight: var(--weight-medium);
  letter-spacing: 0.01em;
  line-height: var(--leading-label);
  text-align: left;
  white-space: nowrap;
}

.table th.num {
  text-align: right;
}

.table td {
  height: var(--table-row-min-height);
  padding: 12px 20px;
  border-top: 1px solid var(--color-border);
  vertical-align: middle;
}

.table td a {
  text-decoration: none;
  font-weight: var(--weight-medium);
}

.table td a:hover {
  text-decoration: underline;
}

.card--dark .table td {
  border-top-color: var(--color-frame-border);
}

.row-link {
  cursor: pointer;
}

.row-link:hover {
  background: var(--color-row-hover);
}

.table td.badges {
  white-space: nowrap;
}

.table tr.over-budget {
  background: var(--color-over-budget-bg);
  box-shadow: inset 3px 0 0 var(--color-over-budget-border);
}

.cost-cell {
  white-space: nowrap;
}

.cost-cell__amount {
  display: block;
}

.cost-cell__flag {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  color: var(--tone-warning-text);
  font-size: var(--text-small);
  font-weight: var(--weight-semibold);
}

.cost-cell__flag .icon--20 {
  width: 16px;
  height: 16px;
}

.budget-banner {
  margin-bottom: var(--space-md);
}

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-sm);
  max-width: 560px;
  margin: 0 auto;
  padding: var(--space-3xl) var(--space-md);
  color: var(--color-text-muted);
  text-align: center;
}

.empty-state .heading {
  color: var(--color-text);
}

.more-row td {
  text-align: center;
}

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

/* Chip style: white rounded rectangle, hairline border, a small square marker in the tone
   colour before the text. The text always carries the meaning, never the colour alone. */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: var(--badge-height);
  padding: 0 10px;
  background: var(--color-secondary);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-chip);
  color: var(--color-text);
  font-size: var(--text-small);
  font-weight: var(--weight-semibold);
  letter-spacing: 0;
  line-height: var(--leading-label);
  white-space: nowrap;
}

.badge::before {
  flex: none;
  width: var(--marker-size);
  height: var(--marker-size);
  background: var(--badge-marker, var(--tone-neutral-marker));
  border-radius: 2px;
  content: "";
}

/* Badges that bring their own icon or dot skip the generic marker */
.badge:has(> .icon, > .health-dot, > .badge__dot)::before {
  display: none;
}

.badge .icon--20 {
  width: 16px;
  height: 16px;
}

.badge + .badge {
  margin-left: var(--space-xs);
}

.badge--neutral {
  --badge-marker: var(--tone-neutral-marker);
  color: var(--tone-neutral-text);
}

.badge--progress {
  --badge-marker: var(--tone-progress-marker);
  color: var(--tone-progress-text);
}

.badge--success {
  --badge-marker: var(--tone-success-marker);
  color: var(--tone-success-text);
}

.badge--warning {
  --badge-marker: var(--tone-warning-marker);
  color: var(--tone-warning-text);
  background: var(--tone-warning-bg);
  border-color: var(--tone-warning-border);
}

.badge--danger {
  --badge-marker: var(--tone-danger-marker);
  color: var(--tone-danger-text);
  background: var(--tone-danger-bg);
  border-color: var(--tone-danger-border);
}

.badge .icon {
  color: var(--badge-marker, currentColor);
}

.badge--success .icon {
  color: var(--tone-success-text);
}

.card--dark .badge {
  background: var(--color-frame-raised);
  border-color: var(--color-frame-border);
  color: var(--color-frame-text);
}

/* In-progress marker: a pulsing black square */
.badge__dot {
  width: var(--marker-size);
  height: var(--marker-size);
  border-radius: 2px;
  background: var(--badge-marker, currentColor);
  animation: badge-pulse 1.2s ease-in-out infinite;
}

.card--dark .badge__dot {
  background: var(--palette-green);
}

@keyframes badge-pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.3;
  }
}

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

/* --------------------------------------------------------------- banners */

.banner {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 14px 18px;
  border: 1px solid;
  border-radius: var(--radius-control);
  font-size: var(--text-label);
  line-height: var(--leading-label);
}

.banner .heading {
  margin-bottom: 2px;
  font-size: var(--text-body);
}

.banner--warning {
  color: var(--tone-warning-text);
  background: var(--tone-warning-bg);
  border-color: var(--tone-warning-border);
}

.banner--danger {
  color: var(--tone-danger-text);
  background: var(--tone-danger-bg);
  border-color: var(--tone-danger-border);
}

.banner--success {
  color: var(--tone-success-text);
  background: var(--tone-success-bg);
  border-color: var(--tone-success-border);
}

.live-warning {
  margin-right: auto;
  padding: 6px 12px;
  border-radius: var(--radius-chip);
}

/* ------------------------------------------------------------------ htmx */

.htmx-indicator {
  display: none;
}

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

.spinner {
  width: 16px;
  height: 16px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .spinner {
    animation-duration: 2.4s;
  }
}

/* ------------------------------------------------------------- drop zone */

.dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  min-height: var(--dropzone-min-height);
  margin-bottom: var(--space-lg);
  padding: var(--space-lg);
  background: var(--color-secondary);
  border: 1.5px dashed var(--color-border-strong);
  border-radius: var(--radius-card);
  text-align: center;
}

.dropzone--compact {
  min-height: var(--dropzone-compact-min-height);
}

.dropzone--active {
  background: var(--color-dropzone-active-bg);
  border-color: var(--color-text);
}

/* Thin grey track; the fill is black so it reads against the track at any width */
.progress {
  width: 100%;
  height: 6px;
  overflow: hidden;
  background: var(--color-border-strong);
  border-radius: var(--radius-small);
}

.progress__fill {
  height: 100%;
  background: var(--palette-dark);
  border-radius: var(--radius-small);
}

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

.image-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--tile-min-width), 1fr));
  gap: var(--space-md);
}

/* Thumbnails sit inset in the card on the neutral letterbox colour, never tinted */
.tile {
  display: flex;
  flex-direction: column;
  padding: var(--space-sm);
  background: var(--color-secondary);
  border: 1px solid var(--color-card-border);
  border-radius: var(--radius-card);
}

.tile__thumb {
  position: relative;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  background: var(--color-thumb-bg);
  border-radius: var(--radius-control);
}

.tile__thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.tile__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  padding: 12px var(--space-sm) var(--space-sm);
}

.tile__name {
  overflow: hidden;
  font-family: var(--font-mono);
  font-size: var(--text-label);
  letter-spacing: 0;
  line-height: var(--leading-label);
  text-overflow: ellipsis;
  white-space: nowrap;
}
