/*
  Administration panel styling.
  Deliberately dependency free: no CSS framework, no web fonts, no external requests.
  Colour choices target a 4.5:1 contrast ratio in both light and dark schemes.
*/

:root {
  --admin-surface: #ffffff;
  --admin-surface-muted: #f4f5f7;
  --admin-border: #d0d5dd;
  --admin-text: #1a1d21;
  --admin-text-muted: #545b64;
  --admin-accent: #1b4f9c;
  --admin-accent-contrast: #ffffff;
  --admin-focus: #b45309;
  --admin-error: #9b1c1c;
  --admin-error-surface: #fdf2f2;
  --admin-notice: #14532d;
  --admin-notice-surface: #f0fdf4;
}

@media (prefers-color-scheme: dark) {
  :root {
    --admin-surface: #16191d;
    --admin-surface-muted: #1f2429;
    --admin-border: #39414a;
    --admin-text: #e8eaed;
    --admin-text-muted: #a3acb8;
    --admin-accent: #6ea8fe;
    --admin-accent-contrast: #10131a;
    --admin-focus: #fbbf24;
    --admin-error: #fca5a5;
    --admin-error-surface: #2a1616;
    --admin-notice: #86efac;
    --admin-notice-surface: #14231a;
  }
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  font-size: 16px;
  line-height: 1.5;
  color: var(--admin-text);
  background: var(--admin-surface-muted);
}

/* Visible focus is a hard requirement: the panel must be fully keyboard operable. */
:focus-visible {
  outline: 3px solid var(--admin-focus);
  outline-offset: 2px;
}

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

.admin-shell__header {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  padding: 0.875rem 1.5rem;
  background: var(--admin-accent);
  color: var(--admin-accent-contrast);
}

.admin-shell__brand {
  font-weight: 600;
  font-size: 1.0625rem;
  color: inherit;
  text-decoration: none;
}

.admin-shell__brand:hover {
  text-decoration: underline;
}

.admin-shell__role {
  font-size: 0.8125rem;
  opacity: 0.85;
}

.admin-shell__body {
  display: flex;
  flex: 1;
  align-items: stretch;
}

.admin-shell__main {
  flex: 1;
  padding: 1.75rem 2rem;
  max-width: 70rem;
}

.admin-shell__footer {
  padding: 0.75rem 1.5rem;
  font-size: 0.8125rem;
  color: var(--admin-text-muted);
  border-top: 1px solid var(--admin-border);
  background: var(--admin-surface);
}

.admin-nav {
  flex: 0 0 15rem;
  padding: 1.25rem 0.75rem;
  background: var(--admin-surface);
  border-right: 1px solid var(--admin-border);
}

.admin-nav__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}

.admin-nav__link {
  display: block;
  padding: 0.5rem 0.75rem;
  border-radius: 0.375rem;
  color: var(--admin-text);
  text-decoration: none;
}

.admin-nav__link:hover {
  background: var(--admin-surface-muted);
}

.admin-nav__link.active {
  background: var(--admin-accent);
  color: var(--admin-accent-contrast);
  font-weight: 600;
}

h1 {
  margin: 0 0 0.5rem;
  font-size: 1.625rem;
}

h2 {
  margin: 0 0 0.75rem;
  font-size: 1.125rem;
}

.admin-lede {
  margin: 0 0 1.5rem;
  color: var(--admin-text-muted);
  max-width: 60ch;
}

.admin-card {
  padding: 1.25rem 1.5rem;
  background: var(--admin-surface);
  border: 1px solid var(--admin-border);
  border-radius: 0.5rem;
  max-width: 40rem;
}

.admin-facts {
  display: grid;
  grid-template-columns: minmax(10rem, auto) 1fr;
  gap: 0.375rem 1.25rem;
  margin: 0 0 1.25rem;
}

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

.admin-facts dd {
  margin: 0;
  font-variant-numeric: tabular-nums;
}

.admin-button {
  padding: 0.5rem 1rem;
  font: inherit;
  color: var(--admin-accent-contrast);
  background: var(--admin-accent);
  border: 1px solid transparent;
  border-radius: 0.375rem;
  cursor: pointer;
}

.admin-button:hover {
  filter: brightness(1.08);
}

.admin-button--quiet {
  background: transparent;
  color: inherit;
  border-color: currentColor;
}

/* --- Skip link ------------------------------------------------------------ */
/*
  Kept in the tab order rather than hidden with display:none, so a keyboard user reaches it with the
  first Tab press and can jump past the navigation.
*/
.admin-skip-link {
  position: absolute;
  left: -100vw;
  top: 0;
  z-index: 10;
  padding: 0.5rem 1rem;
  background: var(--admin-surface);
  color: var(--admin-text);
  border: 1px solid var(--admin-border);
}

.admin-skip-link:focus {
  left: 0;
}

/* --- Account area --------------------------------------------------------- */
.admin-account {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-left: auto;
  font-size: 0.875rem;
  flex-wrap: wrap;
}

.admin-account__link {
  color: inherit;
}

.admin-account__form {
  margin: 0;
}

.admin-nav__heading {
  margin: 1.5rem 0 0.5rem;
  padding: 0 0.75rem;
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--admin-text-muted);
}

/* --- Forms ---------------------------------------------------------------- */
.admin-login {
  max-width: 26rem;
  margin: 3rem auto;
  padding: 1.75rem;
  background: var(--admin-surface);
  border: 1px solid var(--admin-border);
  border-radius: 0.5rem;
}

.admin-field {
  margin: 0 0 1rem;
}

.admin-field label {
  display: block;
  margin-bottom: 0.25rem;
  font-weight: 600;
}

.admin-field__help {
  margin: 0.375rem 0 0;
  font-size: 0.8125rem;
  color: var(--admin-text-muted);
}

.admin-input {
  width: 100%;
  padding: 0.5rem 0.625rem;
  font: inherit;
  color: var(--admin-text);
  background: var(--admin-surface);
  border: 1px solid var(--admin-border);
  border-radius: 0.375rem;
}

.admin-error,
.admin-validation ul {
  margin: 0 0 1rem;
  padding: 0.625rem 0.875rem;
  color: var(--admin-error);
  background: var(--admin-error-surface);
  border: 1px solid currentColor;
  border-radius: 0.375rem;
  list-style-position: inside;
}

.admin-validation ul:empty {
  display: none;
}

.admin-notice {
  margin: 0 0 1rem;
  padding: 0.625rem 0.875rem;
  color: var(--admin-notice);
  background: var(--admin-notice-surface);
  border: 1px solid currentColor;
  border-radius: 0.375rem;
}

.admin-button[disabled] {
  opacity: 0.65;
  cursor: progress;
}

.admin-link {
  color: var(--admin-accent);
}

.admin-field__optional {
  font-weight: 400;
  color: var(--admin-text-muted);
}

.admin-textarea {
  min-height: 6rem;
  font-family: ui-monospace, SFMono-Regular, "Cascadia Mono", Consolas, monospace;
  font-size: 0.875rem;
  resize: vertical;
}

.admin-card--wide {
  max-width: 60rem;
  margin-bottom: 1.25rem;
}

.admin-actions {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
}

/* --- Candidate list ------------------------------------------------------- */
.admin-toolbar {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1.25rem;
  flex-wrap: wrap;
}

.admin-filters {
  display: flex;
  align-items: flex-end;
  gap: 0.75rem;
  flex-wrap: wrap;
}

.admin-field--inline {
  margin: 0;
}

.admin-field--inline label {
  font-size: 0.8125rem;
  font-weight: 600;
}

.admin-field--inline .admin-input {
  width: auto;
  min-width: 8rem;
}

/*
  Wide content scrolls inside its own container. Without this the table would widen the page itself
  on a narrow screen, and every other element would scroll sideways with it.
*/
.admin-table-scroll {
  overflow-x: auto;
  background: var(--admin-surface);
  border: 1px solid var(--admin-border);
  border-radius: 0.5rem;
}

.admin-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9375rem;
}

.admin-table__caption {
  padding: 0.75rem 1rem;
  text-align: left;
  color: var(--admin-text-muted);
  font-size: 0.8125rem;
}

.admin-table th,
.admin-table td {
  padding: 0.625rem 1rem;
  text-align: left;
  border-top: 1px solid var(--admin-border);
  vertical-align: top;
}

.admin-table thead th {
  background: var(--admin-surface-muted);
  font-size: 0.8125rem;
  white-space: nowrap;
}

.admin-table tbody th {
  font-weight: 600;
}

/*
  The badge carries a background, but the state is always spelled out in its text as well: colour is
  never the only signal.
*/
.admin-badge {
  display: inline-block;
  padding: 0.125rem 0.5rem;
  border: 1px solid currentColor;
  border-radius: 999px;
  font-size: 0.8125rem;
  white-space: nowrap;
}

.admin-badge--active {
  color: var(--admin-notice);
  background: var(--admin-notice-surface);
}

.admin-badge--inactive {
  color: var(--admin-text-muted);
  background: var(--admin-surface-muted);
}

.admin-pager {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-top: 1rem;
  font-size: 0.9375rem;
}

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

/*
  Candidate-supplied text. Line breaks are preserved by white-space rather than by converting them to
  markup, so nothing in a resume is ever interpreted as HTML.
*/
.admin-longtext {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  max-height: 32rem;
  overflow-y: auto;
  padding: 0.75rem 1rem;
  background: var(--admin-surface-muted);
  border: 1px solid var(--admin-border);
  border-radius: 0.375rem;
  font-size: 0.9375rem;
}

.admin-confirm {
  padding: 0.875rem 1rem;
  border: 1px solid var(--admin-error);
  border-radius: 0.375rem;
  background: var(--admin-error-surface);
}

.admin-confirm p {
  margin-top: 0;
}

/* --- AI providers --------------------------------------------------------- */
.admin-input--narrow {
  max-width: 8rem;
}

/*
  The credential section is set apart visually so that "replace the API key" and "remove the API
  key" are never mistaken for part of the ordinary settings form directly above them.
*/
.admin-card--sensitive {
  border-left: 4px solid var(--admin-accent);
}

.admin-card--sensitive .admin-actions {
  margin-top: 0.5rem;
}

@media (max-width: 48rem) {
  .admin-shell__header {
    flex-wrap: wrap;
  }

  .admin-account {
    margin-left: 0;
    width: 100%;
  }

  .admin-shell__body {
    flex-direction: column;
  }

  .admin-nav {
    flex: 1 1 auto;
    border-right: none;
    border-bottom: 1px solid var(--admin-border);
  }

  .admin-shell__main {
    padding: 1.25rem;
  }
}

/*
  Interview session pages.

  The expired badge reuses the error palette rather than a new colour, and it always carries the
  word "Expired" — the colour is decoration, never the only signal.
*/
.admin-badge--expired {
  color: var(--admin-error);
  background: var(--admin-error-surface);
}

/*
  The readiness list. Presented as an ordinary list with a heading rather than as a run of error
  banners: these are outstanding tasks, not failures, and an administrator configuring a new
  interview will usually see several at once.
*/
.admin-issues {
  margin: 0.5rem 0 0;
  padding-left: 1.25rem;
}

.admin-issues li {
  margin-bottom: 0.25rem;
}

/*
  The one-time session key.

  Monospace and generously spaced because this value gets read aloud, typed into a desktop
  application, or copied by hand — and Crockford Base32 already excludes the characters that are
  easy to confuse, so the font should not reintroduce the problem.
*/
.admin-key {
  width: 100%;
  max-width: 32rem;
  font-family: ui-monospace, SFMono-Regular, "Cascadia Mono", Consolas, monospace;
  font-size: 1.125rem;
  letter-spacing: 0.04em;
}

.admin-key__actions {
  display: flex;
  gap: 0.75rem;
  align-items: center;
  margin-top: 0.75rem;
  flex-wrap: wrap;
}

.admin-key__status {
  color: var(--admin-notice);
}

/*
  One question and answer on the review transcript.

  Each pair is its own article with a visible boundary, because a reviewer reading twenty of these in
  sequence needs to see where one ends and the next begins. The text itself renders through
  .admin-longtext, which is `white-space: pre-wrap` — a candidate's paragraph breaks survive, and
  nothing they typed is interpreted as formatting.
*/
.admin-qa {
  margin: 1.25rem 0;
  padding: 1rem 1.25rem;
  border: 1px solid var(--admin-border);
  border-radius: 0.5rem;
}

.admin-qa__heading {
  display: flex;
  gap: 0.75rem;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 0;
  font-size: 1.0625rem;
}

.admin-qa__label {
  margin-bottom: 0.25rem;
  font-weight: 600;
  font-size: 0.875rem;
  color: var(--admin-text-muted);
}

/*
  Blazor reconnection overlay.

  The markup lives in App.razor and the class names below are the framework's own. It exists so that
  `style-src 'self'` can stay free of 'unsafe-inline': Blazor's default overlay injects a <style>
  element, which the policy blocks, and a blocked overlay means an administrator sits on a page that
  has silently stopped responding. Supplying the element makes the framework toggle classes on it
  instead. See SecurityHeaderPolicy.

  Hidden until Blazor adds one of its state classes, so nothing appears on a healthy page.
*/
.admin-reconnect {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 1000;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background: rgba(0, 0, 0, 0.55);
}

.admin-reconnect.components-reconnect-show,
.admin-reconnect.components-reconnect-retrying,
.admin-reconnect.components-reconnect-failed,
.admin-reconnect.components-reconnect-rejected,
.admin-reconnect.components-reconnect-paused,
.admin-reconnect.components-reconnect-resume-failed {
  display: flex;
}

/* Blazor adds this when the circuit comes back. Explicit, so it wins over the state classes above. */
.admin-reconnect.components-reconnect-hide {
  display: none;
}

.admin-reconnect__panel {
  max-width: 30rem;
  padding: 1.5rem;
  border: 1px solid var(--admin-border);
  border-radius: 0.5rem;
  background: var(--admin-surface);
  color: var(--admin-text);
  box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.3);
}

.admin-reconnect__heading {
  margin-top: 0;
  font-size: 1.125rem;
}

/*
  Both lines are hidden by default and each is revealed by the state that makes it true, so the
  overlay never shows a countdown for an attempt that will not happen or an apology while it is still
  trying.
*/
.admin-reconnect__line {
  display: none;
  margin-bottom: 0;
}

.components-reconnect-show .admin-reconnect__line--retrying,
.components-reconnect-retrying .admin-reconnect__line--retrying,
.components-reconnect-paused .admin-reconnect__line--retrying {
  display: block;
}

.components-reconnect-failed .admin-reconnect__line--failed,
.components-reconnect-rejected .admin-reconnect__line--failed,
.components-reconnect-resume-failed .admin-reconnect__line--failed {
  display: block;
}

/*
  A reduced-motion preference does not apply here — there is no animation — but the overlay must not
  trap a keyboard user behind a dialog they cannot dismiss, so it is not focus-trapped and the page
  beneath keeps its own focus order.
*/

/* --- Question bank -------------------------------------------------------- */

/*
  A checkbox and its label sit on one line, with the help text below spanning both. The label follows
  the input rather than preceding it, which is the one arrangement where clicking the text and
  clicking the box are obviously the same control.
*/
.admin-field--check {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 0.5rem;
}

.admin-field--check label {
  margin: 0;
  font-weight: 500;
}

.admin-field--check .admin-field__help {
  grid-column: 1 / -1;
  margin-top: 0;
}

.admin-check {
  width: 1rem;
  height: 1rem;
  margin: 0;
  accent-color: var(--admin-accent);
}

/*
  Question text in a list cell. Without a width the excerpt column takes whatever the longest row
  needs and pushes every action button off the visible area.
*/
.admin-table__wrap {
  min-width: 18rem;
  max-width: 32rem;
  white-space: normal;
}

/*
  Each action in a table row is its own form — a state change must be a POST — so the row would
  otherwise stack them vertically and triple its own height.
*/
.admin-actions--inline {
  gap: 0.5rem;
  flex-wrap: nowrap;
}

.admin-actions--inline form {
  margin: 0;
}

/* --- Fixed question selection -------------------------------------------- */
.admin-fieldset {
  margin: 1.25rem 0;
  padding: 1rem 1.25rem;
  border: 1px solid var(--admin-border);
  border-radius: 0.5rem;
}

.admin-fieldset legend {
  padding: 0 0.5rem;
  font-weight: 600;
}

.admin-checklist {
  list-style: none;
  margin: 0.75rem 0 0;
  padding: 0;
}

/*
  Checkbox, label and the question text below it. The grid keeps the text aligned with the label
  rather than with the box, so a long question does not wrap underneath the tick.
*/
.admin-checklist__item {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.25rem 0.5rem;
  padding: 0.6rem 0;
  border-top: 1px solid var(--admin-border);
}

.admin-checklist__item:first-child {
  border-top: 0;
}

.admin-checklist__item label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin: 0;
  cursor: pointer;
}

.admin-checklist__label {
  font-weight: 600;
}

.admin-checklist__text {
  grid-column: 2;
  margin: 0;
  font-size: 0.875rem;
  color: var(--admin-text-muted);
}

/*
  The fixed questions on an interview's details page. Numbered, because the number is the order the
  candidate is asked in and that order is part of what the administrator decided.
*/
.admin-ordered {
  margin: 0.75rem 0 0;
  padding-left: 1.5rem;
}

.admin-ordered li {
  margin-bottom: 0.75rem;
}

.admin-ordered .admin-badge {
  margin-left: 0.5rem;
}

/* --- Live monitoring ------------------------------------------------------ */

/*
  A candidate's answer as it stands on the monitoring page. Indented and ruled so it reads as a
  quotation rather than as more of the platform's own prose — these are somebody else's words, and
  `pre-wrap` keeps the paragraphing they typed rather than collapsing it into one block.
*/
.admin-transcript__answer {
  margin: 0.5rem 0 0;
  padding-left: 0.75rem;
  border-left: 3px solid var(--admin-border);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/*
  A captured screen. Bounded rather than natural size: a 4K capture at full width would push the
  page's own controls off the bottom, and what an administrator needs is to see the whole screen at
  once rather than part of it life-size.
*/
.admin-capture {
  display: block;
  max-width: 100%;
  height: auto;
  margin-top: 0.75rem;
  border: 1px solid var(--admin-border);
  border-radius: 4px;
  background: var(--admin-surface-muted, #000);
}

/* --- Agent centre --------------------------------------------------------- */

/*
  Separates the title form from the logo controls inside one card. They write the same row, which is
  why they share a card rather than being two; they are edited independently, which is why there is a
  line between them.
*/
.admin-rule {
  margin: 1.75rem 0 1.25rem;
  border: 0;
  border-top: 1px solid var(--admin-border);
}

.admin-logo {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  align-items: flex-start;
  margin: 0.75rem 0 1.25rem;
}

/*
  Bounded in both directions. The stored image can legitimately be 4096 pixels on a side, and a
  preview that renders at its natural size would push the form it belongs to off the screen. The
  chequerboard shows through a transparent PNG, so a white logo on a white card is still visible.
*/
.admin-logo__image {
  max-width: 16rem;
  max-height: 8rem;
  padding: 0.5rem;
  border: 1px solid var(--admin-border);
  border-radius: 0.5rem;
  background-color: #fff;
  background-image:
    linear-gradient(45deg, #eceff3 25%, transparent 25%),
    linear-gradient(-45deg, #eceff3 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, #eceff3 75%),
    linear-gradient(-45deg, transparent 75%, #eceff3 75%);
  background-size: 1rem 1rem;
  background-position: 0 0, 0 0.5rem, 0.5rem -0.5rem, -0.5rem 0;
}

/* --- Security log --------------------------------------------------------- */
/*
  A destructive submit, and the only red thing in the panel. Reserved for actions that lose data
  irreversibly — currently one, clearing the whole security log. Colour is not the only signal: the
  button says what it does, and it sits behind its own form with its own explanation.
*/
.admin-button--danger {
  background: var(--admin-danger, #b3261e);
  color: #fff;
}

/*
  Per-row detail. Collapsed by default so the table stays scannable: a security log is read by
  skimming for the row that matters and then opening that one.
*/
.admin-details {
  margin-top: 0.5rem;
}

.admin-details > summary {
  cursor: pointer;
  color: var(--admin-text-muted);
  font-size: 0.8125rem;
}

/*
  User agents arrive as one unbroken 200-character token and would otherwise widen the table until
  the page scrolls sideways. Breaking anywhere is right for a value nobody reads as words.
*/
.admin-wrap {
  overflow-wrap: anywhere;
  word-break: break-word;
}
