/* Design tokens first, so a colour is changed in one place.

   What this replaced: Bootstrap 5 plus a Font Awesome kit plus a 13-line
   stylesheet, with every colour written as style="color: #7099ca" on the
   element - about sixty times on the landing page alone. Changing the brand
   blue meant sixty edits, and two of them would have been missed.

   Light only, deliberately: there is no theme switcher, and a dark palette that
   nothing can select is dead code. Add one here if a toggle is ever built. */
:root {
  /* The logo's blue, measured off the original artwork rather than eyeballed:
     logo.png is one ink, #004CA2, painted at about 57% alpha, which composites
     on white to #769FCD with the paler parts landing on #B9D7EA. Those are the
     two values tools/build_brand.py draws the mark in, so the stylesheet and
     the SVG cannot disagree about the brand.

     Neither can carry text: white on #769FCD measures 2.9:1 and #769FCD on
     white 3.0:1, against the 4.5:1 a label needs. So the interface takes the
     logo's hue at a step dark enough to read (6.4:1 on white) and the logo's
     own colours stay where they are only ever a fill: the tints below, and the
     hero's wash. */
  --brand: #2c5f92;
  --brand-dark: #245079;
  --brand-light: #dce9f5;
  --brand-tint: #f2f7fc;
  --logo-blue: #769fcd;
  --logo-blue-pale: #b9d7ea;

  --ink: #161d26;
  --ink-muted: #66737f;
  --ink-faint: #96a2ad;

  --surface: #ffffff;
  --canvas: #f6f8fb;
  --line: #e5e9ef;
  --line-strong: #d2d9e2;
  --line-soft: #eef1f5;

  --ok: #157347;
  --ok-bg: #e6f4ec;
  --warn: #b45309;
  --warn-ink: #92400e;
  --warn-bg: #fdf6ec;
  --danger: #b42318;
  --danger-bg: #fdf1f0;

  --radius: 14px;
  --radius-sm: 9px;
  --gap: 20px;
  --shadow: 0 1px 2px rgb(16 24 40 / 0.04), 0 1px 3px rgb(16 24 40 / 0.06);
  --shadow-lg: 0 12px 30px rgb(16 24 40 / 0.12);

  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* The reading column. One number, so the header, the footer and every section
     line up down the page instead of each choosing its own width. */
  --measure: 1180px;
}

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

body {
  margin: 0;
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.6;
  color: var(--ink);
  background: var(--surface);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 { line-height: 1.25; margin: 0 0 8px; font-weight: 650; letter-spacing: -0.01em; }
h1 { font-size: clamp(1.9rem, 1.3rem + 2vw, 3rem); }
h2 { font-size: clamp(1.4rem, 1.1rem + 1.1vw, 2rem); }
h3 { font-size: 1.12rem; }
p { margin: 0 0 12px; }

a { color: var(--brand); text-decoration: none; }
a:hover { text-decoration: underline; }
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible,
textarea:focus-visible, summary:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: 4px;
}

code { font-family: var(--mono); font-size: 0.92em; background: var(--canvas); padding: 1px 5px; border-radius: 4px; }

.muted { color: var(--ink-muted); }
.tiny { font-size: 0.82rem; }
.mono { font-family: var(--mono); font-size: 0.92em; }
.lede { font-size: 1.08rem; color: var(--ink-muted); }
.center { text-align: center; }

/* The standard clip-out-of-view rule. `display:none` would take the text out of
   the accessibility tree too, which is the opposite of what it is for. */
.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* --- Icons -------------------------------------------------------------------
   overflow: visible is not decoration. Most Bootstrap glyphs are drawn flush to
   the edge of their 0 0 16 16 viewBox, and an <svg> clips at its viewport by
   default - so at a fractional em size the outermost sliver of a circle is cut
   rather than antialiased, and a ring loses its bottom edge. */
.icon {
  width: 1em; height: 1em;
  fill: currentColor;
  flex: none;
  vertical-align: -0.125em;
  overflow: visible;
}

/* A flag in the switcher and the language tabs. Fixed aspect, a hairline border
   so a white flag on a white ground still has an edge. */
.flag {
  width: 18px; height: 12.6px; flex: none;
  border-radius: 2px;
  box-shadow: 0 0 0 1px rgb(16 24 40 / 0.12);
}

.brand-logo { display: block; height: 38px; width: auto; max-width: 100%; }
@media (max-width: 720px) { .brand-logo { height: 30px; } }

/* --- Buttons ----------------------------------------------------------------
   One shape for links and buttons alike, so "visit the site" and "save" are not
   two different-looking things doing the same job. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 10px 18px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--ink);
  font: inherit; font-size: 0.92rem; font-weight: 560;
  cursor: pointer; white-space: nowrap;
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.08s ease, box-shadow 0.15s ease;
}
.btn:hover { background: var(--brand-tint); border-color: var(--brand-light); text-decoration: none; }
/* Presses down rather than growing: a button that gets bigger under the cursor
   moves the thing next to it. */
.btn:active { transform: translateY(1px); }
.btn[disabled], .btn.is-disabled { opacity: 0.5; cursor: not-allowed; }

/* Both ends of the gradient clear 6.4:1 against the white label, so the sheen
   costs nothing in legibility. */
.btn-primary {
  background: linear-gradient(180deg, var(--brand), var(--brand-dark));
  border-color: var(--brand-dark);
  color: #fff;
  box-shadow: 0 1px 2px rgb(36 80 121 / 0.25);
}
.btn-primary:hover { background: var(--brand-dark); border-color: var(--brand-dark); box-shadow: 0 4px 12px rgb(36 80 121 / 0.28); }
.btn-ghost { border-color: transparent; background: transparent; }
.btn-ghost:hover { background: var(--brand-tint); }
.btn-danger { color: var(--danger); border-color: #e8c4c1; }
.btn-danger:hover { background: var(--danger-bg); border-color: #e8c4c1; }
.btn-block { width: 100%; }
.btn-sm { padding: 6px 12px; font-size: 0.84rem; }
.btn-lg { padding: 13px 24px; font-size: 1rem; }

/* --- Cards ------------------------------------------------------------------ */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.card.narrow { max-width: 520px; }
.card-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 15px 20px; border-bottom: 1px solid var(--line);
  background: linear-gradient(180deg, var(--brand-tint), var(--surface));
  border-radius: var(--radius) var(--radius) 0 0;
}
.card-head h2 { font-size: 1rem; margin: 0; display: flex; align-items: center; gap: 8px; }
.card-body { padding: 20px; }
.card-body.tight { padding: 0; }

/* --- Chips ------------------------------------------------------------------ */
.chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 9px; border-radius: 999px;
  background: var(--canvas); border: 1px solid var(--line);
  font-size: 0.74rem; font-weight: 600; letter-spacing: 0.02em;
  color: var(--ink-muted);
}
.chip-live { background: var(--ok-bg); border-color: #bfe3cd; color: var(--ok); }
.chip-draft { background: var(--warn-bg); border-color: #f0dcc0; color: var(--warn-ink); }
.chip-warn { background: var(--warn-bg); border-color: #f0dcc0; color: var(--warn-ink); }
a.chip:hover { text-decoration: none; border-color: var(--brand-light); }

/* --- Forms ------------------------------------------------------------------ */
.field { margin-bottom: 16px; }
.field > label {
  display: flex; align-items: center; gap: 7px;
  font-size: 0.86rem; font-weight: 600; margin-bottom: 6px; color: var(--ink);
}
.field-icon { color: var(--ink-faint); }
.req { color: var(--danger); }
.control, input[type="text"], input[type="email"], input[type="password"],
input[type="search"], input[type="url"], input[type="tel"],
input[type="datetime-local"], input[type="date"], select, textarea {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font: inherit; font-size: 0.95rem;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.control:focus, input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-light);
}
textarea { resize: vertical; min-height: 96px; line-height: 1.6; }
.field.has-error .control, .field.has-error input, .field.has-error textarea { border-color: var(--danger); }
.field-help { font-size: 0.79rem; color: var(--ink-muted); margin: 5px 0 0; }
.field-error {
  display: flex; align-items: flex-start; gap: 6px;
  font-size: 0.8rem; color: var(--danger); margin: 5px 0 0;
}
/* A checkbox reads left to right: the input is inside its own label. */
.field input[type="checkbox"] { width: auto; margin: 0; }
/* A tag list rendered as checkboxes: a column of them is taller than the panel
   it sits in, so they wrap as chips instead. */
.field ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.field ul li label {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 11px; border: 1px solid var(--line-strong); border-radius: 999px;
  font-size: 0.84rem; cursor: pointer;
}
.field-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 16px; }
@media (max-width: 620px) { .field-row { grid-template-columns: 1fr; } }
.form-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 8px; }

/* --- Alerts and toasts ------------------------------------------------------ */
.alert {
  display: flex; align-items: flex-start; gap: 9px;
  padding: 11px 14px; border-radius: var(--radius-sm);
  border: 1px solid var(--line); background: var(--canvas);
  font-size: 0.9rem; margin-bottom: 16px;
}
.alert-error { background: var(--danger-bg); border-color: #f0cfcc; color: var(--danger); }
.alert-warning { background: var(--warn-bg); border-color: #f0dcc0; color: var(--warn-ink); }

.toasts {
  position: fixed; top: 16px; right: 16px; z-index: 60;
  display: flex; flex-direction: column; gap: 10px;
  max-width: min(420px, calc(100vw - 32px));
}
.toast {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 12px 14px;
  background: var(--surface); border: 1px solid var(--line-strong);
  border-left: 3px solid var(--ink-faint);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-lg);
  font-size: 0.9rem;
}
.toast-success { border-left-color: var(--ok); }
.toast-success .toast-icon { color: var(--ok); }
.toast-error { border-left-color: var(--danger); }
.toast-error .toast-icon { color: var(--danger); }
.toast-warning { border-left-color: var(--warn); }
.toast-warning .toast-icon { color: var(--warn); }
.toast-info .toast-icon { color: var(--brand); }
.toast span { flex: 1; }
.toast-close {
  border: none; background: transparent; cursor: pointer;
  color: var(--ink-faint); padding: 2px; line-height: 1;
}
.toast-close:hover { color: var(--ink); }
.toast.is-going { opacity: 0; transform: translateX(12px); transition: opacity 0.3s ease, transform 0.3s ease; }

/* --- Tables ----------------------------------------------------------------- */
/* The wrapper scrolls, not the page: a wide table inside a card otherwise pushes
   the whole document sideways on a phone. */
.table-wrap { overflow-x: auto; }
.table { width: 100%; border-collapse: collapse; font-size: 0.92rem; }
.table th, .table td { padding: 11px 16px; text-align: left; vertical-align: middle; }
.table thead th {
  font-size: 0.76rem; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--ink-muted); background: var(--canvas);
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
.table tbody tr + tr td { border-top: 1px solid var(--line-soft); }
.table tbody tr:hover { background: var(--brand-tint); }
.row-actions { display: flex; gap: 6px; align-items: center; }
.row-actions form { margin: 0; }

/* --- Empty states ----------------------------------------------------------- */
.empty {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 48px 24px; text-align: center; color: var(--ink-muted);
}
.empty .icon { color: var(--ink-faint); }

/* --- The language switcher --------------------------------------------------
   A segmented control: a small group where every option is visible and the
   current one is lifted out of the trough. Same shape as the qrcode and
   invoices projects, so the three sites read as one family. */
.lang-switch { display: inline-flex; align-items: center; margin: 0; }
.lang-options {
  display: inline-flex; align-items: center; gap: 2px;
  padding: 3px; background: var(--canvas);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
}
.lang-option {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 8px; border: none; border-radius: 6px;
  background: transparent; color: var(--ink-muted);
  font: inherit; font-size: 0.74rem; font-weight: 700; letter-spacing: 0.04em;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.lang-option:hover { background: var(--brand-tint); color: var(--ink); }
.lang-option.is-active { background: var(--surface); color: var(--brand); box-shadow: var(--shadow); }

/* --- The cookie disclosure --------------------------------------------------
   A bar at the foot of the window rather than a modal over the page: it is a
   disclosure, and blocking the page to make somebody read one is a dark pattern
   in its own right. */
.cookie-notice {
  position: fixed; left: 12px; right: 12px; bottom: 12px; z-index: 70;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}
.cookie-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px; padding: 14px 18px;
  max-width: var(--measure); margin: 0 auto;
}
.cookie-text strong { display: flex; align-items: center; gap: 7px; font-size: 0.94rem; }
.cookie-text p { margin: 4px 0 0; font-size: 0.85rem; color: var(--ink-muted); }
.cookie-actions { display: flex; align-items: center; gap: 12px; flex: none; }
.cookie-actions form { display: flex; gap: 8px; margin: 0; }
.cookie-rechoose { display: flex; gap: 10px; }
@media (max-width: 780px) {
  .cookie-inner { flex-direction: column; align-items: stretch; }
  .cookie-actions { justify-content: space-between; }
}

/* Respect the system setting. Everything above uses transitions for feedback,
   not for meaning, so removing them costs nothing. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* --- The date and time picker --------------------------------------------------
   The popup for `core/js/datepicker.js`. Anchored to the field rather than to
   the page, so it follows the input inside a scrolling column.

   It replaced `<input type="datetime-local">` on the demo form, whose Chrome
   popup is a calendar with no clock on it - the time is a faint `--:-- --` that
   reads as decoration, so the field looked like it refused to take a time. */
.datepicker-wrap { position: relative; }
/* Room for the calendar button inside the field's own box. `pointer-events` stay
   on the button alone - the input keeps the rest of the width, so clicking the
   text still puts the caret where it was clicked. */
.datepicker-wrap .control { padding-right: 38px; }
.datepicker-toggle {
  position: absolute; top: 50%; right: 6px; transform: translateY(-50%);
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; padding: 0;
  border: none; border-radius: var(--radius-sm);
  background: transparent; color: var(--ink-faint); cursor: pointer;
}
.datepicker-toggle:hover { background: var(--brand-light); color: var(--brand); }
.datepicker-toggle .icon { width: 16px; height: 16px; }

.datepicker {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 20;
  width: 272px; padding: 12px;
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--radius); box-shadow: var(--shadow-lg);
}
.datepicker-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; margin-bottom: 8px; font-size: 0.9rem;
}
/* Intl gives "august 2026" in some locales and "August 2026" in others. */
.datepicker-head strong { text-transform: capitalize; }
/* Two steps each side: a month, and a year. The year arrows are the double
   chevrons, which is the one pairing people already read as "further". */
.datepicker-navs { display: inline-flex; gap: 2px; }
.datepicker-nav {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: var(--radius-sm);
  border: 1px solid var(--line); background: var(--surface); color: var(--ink-muted);
  font: inherit; line-height: 1; cursor: pointer;
}
.datepicker-nav .icon { width: 13px; height: 13px; }
.datepicker-nav:hover { background: var(--brand-tint); color: var(--brand); border-color: var(--brand-light); }

/* Seven columns, so the weekday row and the days share one grid and a month that
   starts on a Thursday cannot drift out of line with its own header. */
.datepicker-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.datepicker-weekday {
  text-align: center; padding: 4px 0;
  font-size: 0.66rem; font-weight: 600; letter-spacing: 0.02em;
  text-transform: uppercase; color: var(--ink-faint);
}
.datepicker-day {
  padding: 6px 0; border: none; border-radius: var(--radius-sm);
  background: transparent; color: var(--ink);
  font: inherit; font-size: 0.82rem; cursor: pointer;
  font-variant-numeric: tabular-nums;
}
.datepicker-day:hover { background: var(--brand-tint); }
/* Today is outlined, the chosen day is filled: one is a reference point and the
   other is an answer, and they have to be told apart when they are the same day. */
.datepicker-day.is-today { box-shadow: inset 0 0 0 1px var(--line-strong); }
.datepicker-day.is-chosen { background: var(--brand); color: #fff; font-weight: 600; }

.datepicker-time {
  display: flex; align-items: center; gap: 6px;
  margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line);
}
/* `min-width: 0` as well as `flex: 1` - a <select> has an intrinsic minimum
   width that otherwise pushes the Done button out of the popup. */
.datepicker-time select {
  flex: 1; min-width: 0; padding: 6px 8px;
  font: inherit; font-size: 0.85rem;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink);
}
.datepicker-colon { color: var(--ink-faint); }
.datepicker-time > .icon { color: var(--ink-faint); flex: none; }
/* One button, and it confirms. Emptying the field is what the keyboard is for -
   a Clear beside a Done is a second decision on a row that has one. */
.datepicker-done {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 32px; height: 32px; padding: 0;
}
.datepicker-done .icon { width: 15px; height: 15px; }
