/* Lincoln High School Recruitment — one stylesheet for both halves of the
   site: the public vacancy board a candidate lands on, and the staff area
   behind the sign-in. They share a palette and a set of components on
   purpose, so a candidate who is later a colleague recognises the place. */

:root {
  /* The school's own red, taken from its logo. Everything else on the page
     is a neutral chosen to sit under it: a warm grey rather than a cool one,
     because a blue-grey turns #a6192e slightly purple. */
  --accent: #a6192e;
  --accent-dark: #8a1526;
  --accent-darker: #6b0f1d;
  --accent-soft: rgba(166, 25, 46, 0.07);
  --accent-line: rgba(166, 25, 46, 0.22);

  --bg: #f4f2f1;
  --ink: #221f20;
  --muted: #6d6669;
  --muted-soft: #928a8d;
  --card: #ffffff;
  --line: #e0dbda;
  --line-soft: #efebea;

  /* One warning colour and one settled colour, both pulled towards the red
     so a row of pills reads as one family. */
  --gold: #b07d1a;
  --gold-soft: rgba(176, 125, 26, 0.13);
  --danger: #a6192e;
  --danger-dark: #6b0f1d;
  --danger-soft: rgba(166, 25, 46, 0.08);
  --success: #2f6b46;
  --success-soft: rgba(47, 107, 70, 0.11);

  --radius: 12px;
  --radius-sm: 8px;
  --radius-xs: 6px;

  --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
    sans-serif;
  /* Headings, the brand wordmark and the vacancy titles. Work Sans is served
     from this site (see public/vendor/work-sans/) with Verdana behind it —
     both are wide and open, so a heading doesn't reflow to a different shape
     while the webfont arrives. */
  --font-display: "Work Sans", Verdana, Geneva, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;

  /* Spacing scale — stick to these so the rhythm stays consistent. */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  --sp-7: 48px;

  --font-base: 16px;

  --shadow-sm: 0 1px 2px rgba(34, 31, 32, 0.05), 0 2px 6px rgba(34, 31, 32, 0.05);
  --shadow: 0 2px 4px rgba(34, 31, 32, 0.05), 0 8px 24px rgba(34, 31, 32, 0.09);
  --shadow-lg: 0 4px 8px rgba(34, 31, 32, 0.06), 0 18px 48px rgba(34, 31, 32, 0.14);
  --ring: 0 0 0 3px rgba(166, 25, 46, 0.24);

  /* One timing for every hover that lifts something, so a row of cards
     settles together rather than one at a time. */
  --lift: 0.18s cubic-bezier(0.2, 0, 0.2, 1);
}

* {
  box-sizing: border-box;
}

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

html {
  font-size: var(--font-base);
}

body {
  margin: 0;
  /* A short page — one vacancy, or none — should still put its footer at the
     bottom of the window rather than halfway up it. */
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

body.modal-open {
  overflow: hidden;
}

h1,
h2,
h3,
h4 {
  margin: 0 0 var(--sp-3);
  /* Every heading in the display face, not just the big one — two sans
     faces mixed at random reads as a mistake rather than a choice. */
  font-family: var(--font-display);
  line-height: 1.25;
  color: var(--accent-dark);
  font-weight: 700;
}

h1 {
  font-size: 1.75rem;
}
h2 {
  font-size: 1.3rem;
}
h3 {
  font-size: 1.1rem;
}
h4 {
  font-size: 0.95rem;
}

p {
  margin: 0 0 var(--sp-3);
}

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

.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;
}

/* ---------- Scrollbars ---------- */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
}

::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

::-webkit-scrollbar-thumb {
  background: var(--line);
  border-radius: 999px;
}

::-webkit-scrollbar-track,
::-webkit-scrollbar-corner {
  background: transparent;
}

/* ---------- The brand mark ---------- */
/* The school's logo is white artwork on the school's red, so it lives on a
   red bar and nowhere else — on white it would be an invisible rectangle.
   That decides the chrome: a red strip across the top of both halves of the
   site, and the red used as an accent everywhere below it.

   Until public/logo.png is in place the <img> fails and the wordmark behind
   it takes over, so the site is never showing a broken image — see the
   onerror in the markup. */
.brandmark {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  text-decoration: none;
  color: #fff;
  min-width: 0;
}

.brandmark .logo {
  height: 52px;
  width: auto;
  max-width: 260px;
  object-fit: contain;
  display: block;
}

/* The fallback: the wordmark without the crest, which is most of the logo
   and reads as deliberate rather than broken. */
.brandmark .wordmark {
  display: none;
  flex-direction: column;
  line-height: 1.15;
}

.brandmark.no-logo .logo {
  display: none;
}

.brandmark.no-logo .wordmark {
  display: flex;
}

.wordmark .name {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.15rem;
  letter-spacing: -0.01em;
  color: #fff;
}

.wordmark .maori {
  font-size: 0.78rem;
  color: rgba(255, 255, 255, 0.82);
}

/* "Vacancies" / "Recruitment" beside the logo, divided from it by a rule so
   it reads as this site's name rather than part of the school's. */
.brand-sub {
  font-family: var(--font-display);
  padding-left: var(--sp-3);
  border-left: 1px solid rgba(255, 255, 255, 0.35);
  font-size: 0.74rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.92);
  font-weight: 700;
  white-space: nowrap;
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding: 9px 18px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--card);
  color: var(--ink);
  font: inherit;
  font-weight: 600;
  line-height: 1.2;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s, transform var(--lift);
  text-decoration: none;
}

.btn:hover:not(:disabled) {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.btn:active:not(:disabled) {
  transform: translateY(1px);
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

.btn.primary:hover:not(:disabled) {
  background: var(--accent-dark);
  border-color: var(--accent-dark);
}

.btn.danger {
  border-color: var(--danger);
  color: var(--danger);
  background: var(--card);
}

.btn.danger:hover:not(:disabled) {
  background: var(--danger);
  border-color: var(--danger);
  color: #fff;
}

.btn.link {
  border-color: transparent;
  background: transparent;
  color: var(--accent);
  padding: 9px 10px;
  font-weight: 600;
}

.btn.link:hover:not(:disabled) {
  background: var(--accent-soft);
  border-color: transparent;
  text-decoration: underline;
}

/* Destructive, sitting beside the action somebody actually came for. The
   school's colour is red, so a red link reads as "this is the brand" rather
   than "be careful" — these stay grey until the cursor is on them, and the
   dialog behind them spells out the consequence anyway. */
.btn.link.danger {
  border-color: transparent;
  background: transparent;
  color: var(--muted);
}

.btn.link.danger:hover:not(:disabled) {
  background: var(--danger-soft);
  border-color: transparent;
  color: var(--danger-dark);
}

.btn.small {
  padding: 5px 11px;
  font-size: 0.85rem;
}

.btn.block {
  width: 100%;
}

/* ---------- Cards ---------- */
.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--sp-5);
  box-shadow: var(--shadow-sm);
}

.card + .card {
  margin-top: var(--sp-4);
}

.section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  flex-wrap: wrap;
  margin-bottom: var(--sp-4);
}

.section-head h2,
.section-head h3 {
  margin: 0;
}

.muted {
  color: var(--muted);
}

.small {
  font-size: 0.85rem;
}

.empty {
  padding: var(--sp-6) var(--sp-4);
  text-align: center;
  color: var(--muted);
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  background: var(--card);
}

/* ---------- Forms ---------- */
.stack {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

label {
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--ink);
}

input[type="text"],
input[type="email"],
input[type="tel"],
input[type="date"],
input[type="number"],
input[type="search"],
input:not([type]),
select,
textarea {
  width: 100%;
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--card);
  color: var(--ink);
  font: inherit;
  transition: border-color 0.15s;
}

input:hover:not(:disabled),
select:hover:not(:disabled),
textarea:hover:not(:disabled) {
  border-color: var(--muted-soft);
}

input:focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--ring);
}

textarea {
  min-height: 110px;
  resize: vertical;
  line-height: 1.5;
}

input[type="file"] {
  width: 100%;
  padding: 9px 12px;
  border: 1px dashed var(--line);
  border-radius: var(--radius-sm);
  background: var(--card);
  font: inherit;
  font-size: 0.9rem;
}

.form-row {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}

.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--sp-3);
}

.form-hint {
  margin: 0;
  font-size: 0.82rem;
  color: var(--muted);
}

.required-mark {
  color: var(--danger);
  font-weight: 700;
}

.choice-group {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-4);
}

.check-label {
  display: inline-flex;
  align-items: flex-start;
  gap: var(--sp-2);
  font-weight: 500;
  font-size: 0.92rem;
  cursor: pointer;
}

.check-label input {
  width: auto;
  margin-top: 3px;
  accent-color: var(--accent);
}

.msg {
  margin: var(--sp-3) 0 0;
  min-height: 1.4em;
  font-size: 0.9rem;
  color: var(--muted);
}

.msg.error,
.modal-error,
.form-error {
  color: var(--danger);
}

.msg.success {
  color: var(--success);
}

.notice {
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--accent-soft);
  font-size: 0.92rem;
}

.notice.warn {
  border-color: rgba(192, 138, 46, 0.4);
  background: var(--gold-soft);
}

.notice.danger {
  border-color: rgba(165, 52, 42, 0.35);
  background: var(--danger-soft);
  color: var(--danger-dark);
}

.notice.success {
  border-color: rgba(44, 107, 69, 0.3);
  background: var(--success-soft);
  color: var(--success);
}

/* ---------- Pills and tags ---------- */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  white-space: nowrap;
  border: 1px solid transparent;
}

/* Vacancy statuses walk from grey through the school's red and end at
   settled green, so a board of them reads as a progress bar. */
.pill.status-new {
  background: #f1eeed;
  color: #5e5457;
  border-color: #e0dbda;
}
.pill.status-advertised {
  background: rgba(166, 25, 46, 0.1);
  color: var(--accent);
  border-color: rgba(166, 25, 46, 0.25);
}
.pill.status-shortlisting {
  background: rgba(166, 25, 46, 0.16);
  color: var(--accent-dark);
  border-color: rgba(166, 25, 46, 0.32);
}
.pill.status-interviewing {
  background: var(--gold-soft);
  color: #8a6110;
  border-color: rgba(192, 138, 46, 0.4);
}
.pill.status-selected {
  background: var(--success-soft);
  color: var(--success);
  border-color: rgba(44, 107, 69, 0.3);
}
.pill.status-closed {
  background: #eae6e5;
  color: #7c7477;
  border-color: #ded8d7;
}

/* Candidate statuses. "Not suitable" is deliberately the quietest thing on
   the row — the candidate stays in the pool, they are just not in this
   conversation. */
.pill.cand-new {
  background: rgba(166, 25, 46, 0.12);
  color: var(--accent);
  border-color: rgba(166, 25, 46, 0.28);
}
.pill.cand-prescreened {
  background: #efebea;
  color: #5e5457;
  border-color: #e0dbda;
}
.pill.cand-shortlisted {
  background: var(--gold-soft);
  color: #8a6110;
  border-color: rgba(192, 138, 46, 0.4);
}
.pill.cand-offer {
  background: rgba(44, 107, 69, 0.14);
  color: var(--success);
  border-color: rgba(44, 107, 69, 0.32);
}
.pill.cand-accepted {
  background: var(--success);
  color: #fff;
  border-color: var(--success);
}
.pill.cand-not_suitable {
  background: #f1eeed;
  color: #8695a4;
  border-color: #e6e1e0;
}

.tag {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 9px;
  border-radius: var(--radius-xs);
  border: 1px solid var(--line);
  background: #faf8f8;
  color: var(--muted);
  font-size: 0.76rem;
  font-weight: 600;
  white-space: nowrap;
}

.tag.channel-seek {
  border-color: rgba(166, 25, 46, 0.3);
  color: var(--accent);
  background: rgba(166, 25, 46, 0.06);
}

.tag.channel-gazette {
  border-color: rgba(192, 138, 46, 0.45);
  color: #8a6110;
  background: var(--gold-soft);
}

.tag-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

.count-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 22px;
  padding: 0 7px;
  border-radius: 999px;
  background: var(--accent);
  color: #fff;
  font-size: 0.75rem;
  font-weight: 700;
}

.count-chip.quiet {
  background: #e6e1e0;
  color: var(--muted);
}

/* ---------- Tables ---------- */
.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
}

/* As wide as the content needs and never narrower than the pane it sits in:
   a narrow table fills the width, and a wide one overflows into the
   wrapper's scroll rather than squeezing a column until it clips. */
table {
  width: max-content;
  min-width: 100%;
  border-collapse: collapse;
  font-size: 0.92rem;
}

thead th {
  position: sticky;
  top: 0;
  background: #faf8f8;
  text-align: left;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}

tbody td {
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--line-soft);
  vertical-align: middle;
}

tbody tr:last-child td {
  border-bottom: none;
}

tbody tr.clickable {
  cursor: pointer;
}

tbody tr.clickable:hover {
  background: var(--accent-soft);
}

/* Not suitable, and staff who have left: still there, still readable, and
   plainly not part of what is going on now. Kept at 62% rather than lower —
   a row nobody can read is a row that may as well have been deleted, and
   the whole point is that the school comes back to these. */
tr.dimmed td {
  opacity: 0.62;
}

tr.dimmed td:first-child {
  box-shadow: inset 3px 0 0 var(--accent-line);
}

.cell-strong {
  font-weight: 600;
  color: var(--accent-dark);
}

.cell-actions {
  text-align: right;
}

/* A row's actions wrap within their own column rather than pushing the table
   wider than the screen. Four labelled buttons don't fit on one line beside
   six columns of detail, and dropping to icons alone would mean guessing at
   what "Reset 2FA" does from a shield. */
.row-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--sp-1) var(--sp-2);
  max-width: 15rem;
  margin-left: auto;
}

/* ---------- Modal ---------- */
.modal-root {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-4);
}

.modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(34, 31, 32, 0.48);
  backdrop-filter: blur(2px);
}

.modal-box {
  position: relative;
  width: min(560px, 100%);
  max-height: min(88vh, 900px);
  overflow-y: auto;
  background: var(--card);
  border-radius: var(--radius);
  padding: var(--sp-5);
  box-shadow: var(--shadow-lg);
}

.modal-root.wide-modal .modal-box {
  width: min(820px, 100%);
}

.modal-actions {
  display: flex;
  gap: var(--sp-2);
  justify-content: flex-end;
  flex-wrap: wrap;
  margin-top: var(--sp-4);
}

.modal-error {
  min-height: 1.2em;
  margin: var(--sp-2) 0 0;
  font-size: 0.9rem;
}

/* ---------- Boot ---------- */
.boot-view {
  min-height: 60vh;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted-soft);
}

.spinner {
  width: 26px;
  height: 26px;
  border: 3px solid var(--line);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}

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

/* ---------- Definition lists ---------- */
.detail-list {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: var(--sp-2) var(--sp-4);
  margin: 0;
  font-size: 0.93rem;
}

.detail-list dt {
  color: var(--muted);
}

.detail-list dd {
  margin: 0;
  font-weight: 600;
  overflow-wrap: anywhere;
}

/* Free text a candidate typed: their paragraphs are the shape of the
   answer, so they survive into the page. */
/* A vacancy summary, as a candidate reads it. It arrives as HTML built by
   richtext.js from the plain text an administrator typed — paragraphs, bold,
   italics and bullets, and nothing else — so it is styled rather than
   printed verbatim. */
.prose {
  overflow-wrap: anywhere;
  line-height: 1.6;
}

.prose p {
  margin: 0 0 var(--sp-3);
}

.prose p:last-child,
.prose ul:last-child {
  margin-bottom: 0;
}

.prose ul {
  margin: 0 0 var(--sp-3);
  padding-left: 1.25rem;
}

.prose li {
  margin-bottom: var(--sp-1);
}

.prose li::marker {
  color: var(--accent);
}

.prose strong {
  font-weight: 700;
  color: var(--ink);
}

/* Free text somebody typed that carries no formatting — a candidate's
   qualifications, their upcoming leave. Their line breaks are the shape of
   the answer, so they survive. */
.plain-text {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  line-height: 1.6;
}

/* ---------- The summary editor ---------- */
.editor {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--card);
  overflow: hidden;
}

.editor:focus-within {
  border-color: var(--accent);
  box-shadow: var(--ring);
}

.editor-toolbar {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2);
  background: #faf8f8;
  border-bottom: 1px solid var(--line);
}

.editor-toolbar .btn.small {
  min-width: 2rem;
  justify-content: center;
}

.editor-hint {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  color: var(--muted-soft);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The box itself is contenteditable, so bold looks bold while it is being
   typed. It is styled as .prose as well, which is what makes what an
   administrator sees here and what a candidate sees on the board the same
   thing. What gets saved is neither — see public/richtext.js. */
.editor-box {
  min-height: 11rem;
  max-height: 22rem;
  overflow-y: auto;
  padding: var(--sp-3) var(--sp-4);
  outline: none;
  font-size: 0.95rem;
}

.editor-box.is-empty::before {
  content: attr(data-placeholder);
  color: var(--muted-soft);
  pointer-events: none;
}

/* A list typed in the box sits where a list on the board sits. */
.editor-box ul {
  padding-left: 1.25rem;
}

/* Contenteditable wraps each line in a bare <div> with no margin of its own,
   and leaves the very first line unwrapped — so the gap goes above every
   block but the first, which is the one arrangement that spaces all of them
   whatever the browser decided to wrap. Without it the box is tighter than
   the board it is previewing. */
.editor-box > div:not(:first-child),
.editor-box > p:not(:first-child),
.editor-box > ul:not(:first-child) {
  margin-top: var(--sp-3);
}

.editor-box > p {
  margin-bottom: 0;
}

/* ===========================================================================
   The public vacancy board
   =========================================================================== */

/* The red strip. Its colour is the logo's own background, so the artwork
   sits on it without a seam. */
.site-header,
.topbar {
  background: var(--accent);
  padding: var(--sp-3) var(--sp-5);
}

.site-header .inner {
  max-width: 1080px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  flex-wrap: wrap;
}

/* One band of red is enough. The introduction sits on a warm tint that fades
   into the page, with the red pointing rather than shouting. */
.hero {
  background: linear-gradient(180deg, #fbf6f6 0%, var(--bg) 100%);
  padding: var(--sp-6) var(--sp-5) var(--sp-7);
}

.hero .inner {
  max-width: 1080px;
  margin: 0 auto;
}

.hero .eyebrow {
  display: block;
  margin-bottom: var(--sp-2);
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
}

.hero h1 {
  color: var(--ink);
  font-family: var(--font-display);
  font-size: clamp(1.7rem, 4vw, 2.4rem);
  margin-bottom: var(--sp-3);
}

.hero p {
  max-width: 62ch;
  margin: 0;
  font-size: 1.02rem;
  color: var(--muted);
}

.page {
  max-width: 1080px;
  margin: 0 auto;
  padding: var(--sp-5) var(--sp-5) var(--sp-7);
}

/* The staff area is a desk, not a page of prose: it carries tables that are
   several columns wider than anything a candidate reads. */
.page.wide {
  max-width: 1400px;
}

/* The board starts straight under the introduction: with the hero fading
   into the page background there is no edge left to overlap. */
.page.overlap {
  padding-top: 0;
}

.filter-bar {
  display: flex;
  align-items: flex-end;
  gap: var(--sp-3);
  flex-wrap: wrap;
  padding: var(--sp-4);
  margin-bottom: var(--sp-4);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

.filter-bar .form-row {
  min-width: 170px;
  flex: 1 1 170px;
}

/* Search leads the row and gets the room: it is the one a person reaches for
   when they know what they are looking for, and the dropdowns are for when
   they don't. */
.filter-bar .form-row-search {
  flex: 2 1 240px;
}

/* A <select> and an <input> with the same padding are not the same height —
   the browser gives the input its own line-height — and the bar is aligned
   to the bottom of its controls, so the taller one drags its label up out of
   line with the rest. One height for everything in the row settles it. */
.filter-bar select,
.filter-bar input {
  height: 2.5rem;
}

/* Safari draws its own decoration on a search field that doesn't match
   anything else here. */
.filter-bar input[type="search"]::-webkit-search-decoration {
  -webkit-appearance: none;
}

.filter-bar .filter-count {
  margin-left: auto;
  font-size: 0.88rem;
  color: var(--muted);
  padding-bottom: 10px;
}

.job-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
  gap: var(--sp-4);
}

.job-card {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-5);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  text-align: left;
  font: inherit;
  color: inherit;
  cursor: pointer;
  transition: transform var(--lift), box-shadow var(--lift), border-color var(--lift);
}

.job-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow);
  border-color: var(--accent);
}

.job-card h3 {
  margin: 0;
  font-size: 1.12rem;
}

.job-card .department {
  font-size: 0.86rem;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* Four lines of the summary, so one wordy vacancy doesn't set the height of
   every card beside it. */
.job-card .summary {
  margin: 0;
  color: var(--muted);
  font-size: 0.92rem;
  display: -webkit-box;
  -webkit-line-clamp: 4;
  line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.job-card .foot {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-2);
  margin-top: auto;
  padding-top: var(--sp-3);
  border-top: 1px solid var(--line-soft);
  font-size: 0.85rem;
  color: var(--muted);
}

.closing-soon {
  color: var(--danger);
  font-weight: 600;
}

/* ---------- One vacancy, and the form under it ---------- */
.job-detail {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--sp-6);
  box-shadow: var(--shadow-sm);
}

.job-detail .department {
  font-size: 0.86rem;
  font-weight: 700;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: var(--sp-2);
}

.job-detail h1 {
  font-family: var(--font-display);
  margin-bottom: var(--sp-3);
}

.job-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-5);
  padding: var(--sp-3) 0 var(--sp-4);
  margin-bottom: var(--sp-4);
  border-bottom: 1px solid var(--line-soft);
  font-size: 0.9rem;
  color: var(--muted);
}

.job-meta strong {
  color: var(--ink);
}

.apply-form fieldset {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--sp-4) var(--sp-5) var(--sp-5);
  margin: 0 0 var(--sp-4);
}

.apply-form legend {
  padding: 0 var(--sp-2);
  font-weight: 700;
  color: var(--accent-dark);
  font-size: 0.95rem;
}

.back-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-bottom: var(--sp-4);
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--accent);
  text-decoration: none;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
  font-family: inherit;
}

.back-link:hover {
  text-decoration: underline;
}

.submitted-panel {
  text-align: center;
  padding: var(--sp-7) var(--sp-5);
}

.submitted-panel .tick {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 62px;
  height: 62px;
  margin-bottom: var(--sp-4);
  border-radius: 50%;
  background: var(--success-soft);
  color: var(--success);
  font-size: 1.8rem;
  font-weight: 700;
}

/* ===========================================================================
   The staff area
   =========================================================================== */

.login-view {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-5);
}

.login-card {
  width: min(430px, 100%);
  text-align: center;
  overflow: hidden;
}

/* The card wears the red strip too, so the page a staff member bookmarks is
   recognisably the same site as the board. */
.login-card .card-banner {
  margin: calc(var(--sp-5) * -1) calc(var(--sp-5) * -1) var(--sp-5);
  padding: var(--sp-4) var(--sp-5);
  background: var(--accent);
  display: flex;
  justify-content: center;
}

.login-card .card-banner .logo {
  height: 54px;
  max-width: 100%;
}

.login-card h1 {
  font-family: var(--font-display);
  font-size: 1.35rem;
  margin-bottom: var(--sp-1);
}

.login-card .tagline {
  color: var(--muted);
  font-size: 0.92rem;
  margin-bottom: var(--sp-5);
}

.login-card form,
.login-card .stack {
  text-align: left;
}

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
}

.topbar .who {
  text-align: right;
  font-size: 0.82rem;
  line-height: 1.35;
  color: #fff;
}

.topbar .who .name {
  font-weight: 700;
  display: block;
}

.topbar .who .role {
  color: rgba(255, 255, 255, 0.78);
  display: block;
}

.topbar-right {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}

/* ---------- The menu under the signed-in name ---------- */
.user-menu {
  position: relative;
}

.user-menu-button {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 6px 10px;
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: var(--radius-sm);
  background: transparent;
  color: #fff;
  font: inherit;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
}

.user-menu-button:hover,
.user-menu-button[aria-expanded="true"] {
  background: rgba(255, 255, 255, 0.14);
  border-color: rgba(255, 255, 255, 0.45);
}

.user-menu-button > .fa-circle-user {
  font-size: 1.15rem;
  opacity: 0.9;
}

.user-menu-button .chevron {
  font-size: 0.7rem;
  opacity: 0.8;
  transition: transform 0.15s;
}

.user-menu-button[aria-expanded="true"] .chevron {
  transform: rotate(180deg);
}

.user-menu-panel {
  position: absolute;
  top: calc(100% + var(--sp-2));
  right: 0;
  z-index: 40;
  min-width: 13rem;
  padding: var(--sp-1);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-lg);
}

.user-menu-item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  padding: var(--sp-2) var(--sp-3);
  border: none;
  border-radius: var(--radius-xs);
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-weight: 600;
  font-size: 0.9rem;
  text-align: left;
  cursor: pointer;
}

.user-menu-item:hover {
  background: var(--accent-soft);
  color: var(--accent-dark);
}

.user-menu-item .fa-solid {
  width: 1rem;
  text-align: center;
  color: var(--accent);
  font-size: 0.9em;
}

.topbar .btn.link {
  color: rgba(255, 255, 255, 0.92);
}

.topbar .btn.link:hover:not(:disabled) {
  background: rgba(255, 255, 255, 0.14);
  color: #fff;
  text-decoration: none;
}

/* Under the red strip rather than part of it: the active tab is marked in
   the school's red, which is enough colour for a dashboard somebody has
   open all day. */
.tabs {
  display: flex;
  gap: var(--sp-1);
  padding: 0 var(--sp-5);
  background: var(--card);
  border-bottom: 1px solid var(--line);
  overflow-x: auto;
}

.tab {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  border: none;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-weight: 600;
  font-size: 0.92rem;
  cursor: pointer;
  border-bottom: 3px solid transparent;
  margin-bottom: -1px;
  white-space: nowrap;
}

.tab:hover {
  color: var(--accent);
}

.tab.active {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

.panel {
  display: none;
}

.panel.active {
  display: block;
}

.subtabs {
  display: flex;
  gap: var(--sp-1);
  margin-bottom: var(--sp-4);
  border-bottom: 1px solid var(--line);
  overflow-x: auto;
}

.subtab {
  padding: var(--sp-2) var(--sp-4);
  border: none;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-weight: 600;
  font-size: 0.9rem;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  white-space: nowrap;
}

.subtab:hover {
  color: var(--accent);
}

.subtab.active {
  color: var(--accent-dark);
  border-bottom-color: var(--accent);
}

.subpanel {
  display: none;
}

.subpanel.active {
  display: block;
}

/* ---------- The vacancy list, staff side ---------- */
.job-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--sp-3) var(--sp-4);
  align-items: start;
  padding: var(--sp-4) var(--sp-5);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  margin-bottom: var(--sp-3);
  box-shadow: var(--shadow-sm);
  transition: border-color var(--lift), box-shadow var(--lift);
}

.job-row:hover {
  border-color: var(--accent);
  box-shadow: var(--shadow);
}

/* The left edge says where a vacancy is before a word of it is read: grey
   while it is being written up, the school's red once it is out in the world
   and running, and pale again once it is finished. */
.job-row {
  border-left: 3px solid var(--line);
}

.job-row.status-advertised,
.job-row.status-shortlisting,
.job-row.status-interviewing,
.job-row.status-selected {
  border-left-color: var(--accent);
}

.job-row.is-closed {
  border-left-color: var(--line-soft);
}

.job-row.is-closed {
  background: #faf8f8;
}

.job-row.is-closed .job-row-title {
  color: var(--muted);
}

.job-row-main {
  min-width: 0;
}

.job-row-title {
  font-family: var(--font-display);
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--accent-dark);
  margin-bottom: var(--sp-1);
}

.job-row-sub {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-4);
  font-size: 0.86rem;
  color: var(--muted);
  margin-bottom: var(--sp-2);
}

/* Across rather than down: five stacked buttons made every row as tall as
   its longest action list, whatever was in the row itself. */
.job-row-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: flex-end;
  gap: var(--sp-2);
  max-width: 24rem;
}

/* The status stepper: one button that moves a vacancy to the next thing
   that happens to it, rather than a dropdown of six that has to be read. */
.stepper {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
}

/* ---------- Candidates ---------- */
.candidate-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  flex-wrap: wrap;
  margin-bottom: var(--sp-4);
}

.status-filters {
  display: flex;
  gap: var(--sp-2);
  flex-wrap: wrap;
}

.status-filter {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--card);
  color: var(--muted);
  font: inherit;
  font-size: 0.82rem;
  font-weight: 600;
  cursor: pointer;
}

.status-filter:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.status-filter.active {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

.doc-links {
  display: flex;
  gap: var(--sp-2);
  flex-wrap: wrap;
}

.doc-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-xs);
  background: #faf8f8;
  color: var(--accent);
  font-size: 0.82rem;
  font-weight: 600;
  text-decoration: none;
}

.doc-link:hover {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.winner-mark {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--success);
  font-weight: 700;
  font-size: 0.8rem;
}

/* ---------- Security / 2FA ---------- */
.qr-box {
  display: flex;
  gap: var(--sp-5);
  flex-wrap: wrap;
  align-items: flex-start;
  padding: var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #faf8f8;
}

.qr-box svg {
  border-radius: var(--radius-sm);
  background: #fff;
}

.secret-code {
  font-family: var(--font-mono);
  font-size: 0.95rem;
  letter-spacing: 2px;
  word-break: break-all;
  padding: var(--sp-2) var(--sp-3);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-xs);
}

.recovery-codes {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
  gap: var(--sp-2);
  margin: var(--sp-3) 0;
  padding: var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #faf8f8;
  font-family: var(--font-mono);
  font-size: 0.95rem;
  letter-spacing: 1px;
}

/* ---------- Logs ---------- */
.log-time {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: var(--muted);
  white-space: nowrap;
}

.log-action {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: var(--accent);
}

.status-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: 6px;
  background: var(--muted-soft);
}

.status-dot.sent {
  background: var(--success);
}
.status-dot.failed {
  background: var(--danger);
}

/* ---------- Icons ---------- */
/* Font Awesome, used the same way everywhere: solid weight, on the left of
   the label, sized relative to the text it sits beside, and always
   aria-hidden in the markup — an icon repeats a label here, it never
   replaces one. */
.btn .fa-solid {
  font-size: 0.92em;
}

.btn.small .fa-solid {
  font-size: 0.9em;
}

.tab .fa-solid {
  font-size: 0.9em;
  opacity: 0.85;
}

h2 .fa-solid,
h3 .fa-solid,
h4 .fa-solid,
legend .fa-solid {
  margin-right: var(--sp-2);
  color: var(--accent);
  font-size: 0.82em;
}

.subtab .fa-solid {
  margin-right: 6px;
  font-size: 0.88em;
  opacity: 0.8;
}

.pill .fa-solid,
.tag .fa-solid {
  font-size: 0.82em;
}

thead th .fa-solid {
  margin-right: 5px;
  opacity: 0.55;
}

/* Notices lead with an icon in a column of its own, so a message that wraps
   doesn't run back underneath it. */
.notice {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
}

.notice > .fa-solid {
  margin-top: 3px;
  font-size: 1.05em;
  flex-shrink: 0;
  color: var(--accent);
}

.notice.warn > .fa-solid {
  color: var(--gold);
}

.notice.success > .fa-solid {
  color: var(--success);
}

.notice.danger > .fa-solid {
  color: var(--danger);
}

/* An empty state is the one place an icon is allowed to be large: it is
   doing the work of the picture that isn't there. */
.empty .fa-solid {
  display: block;
  margin: 0 auto var(--sp-3);
  font-size: 1.9rem;
  color: var(--line);
}

/* A label with an icon beside it — a closing date, a department, a
   reference. Used across the public cards and the staff rows so the same
   fact looks the same in both. */
.meta-item {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

.meta-item .fa-solid {
  color: var(--accent);
  font-size: 0.86em;
  opacity: 0.75;
}

.doc-link .fa-solid {
  font-size: 0.9em;
}

.status-filter .fa-solid {
  font-size: 0.85em;
  opacity: 0.85;
}

.submitted-panel .tick .fa-solid {
  font-size: 1.7rem;
}

/* ---------- Phones ---------- */
@media (max-width: 720px) {
  .page {
    padding: var(--sp-4) var(--sp-4) var(--sp-6);
  }

  .hero {
    padding: var(--sp-5) var(--sp-4) var(--sp-6);
  }

  .site-header,
  .topbar {
    padding: var(--sp-3) var(--sp-4);
  }

  .tabs {
    padding: 0 var(--sp-2);
  }

  .job-detail {
    padding: var(--sp-4);
  }

  .job-row {
    grid-template-columns: 1fr;
    padding: var(--sp-4);
  }

  .job-row-actions {
    justify-content: flex-start;
    max-width: none;
  }

  .topbar .who {
    display: none;
  }

  /* On a phone the topbar has the logo, the site's name and the account menu
     competing for 390 pixels, and the name loses: the logo already says
     whose site this is and the tab strip underneath says which one. */
  .topbar .brand-sub {
    display: none;
  }

  .topbar .logo {
    height: 40px;
  }

  .detail-list {
    grid-template-columns: 1fr;
    gap: var(--sp-1) 0;
  }

  .detail-list dt {
    font-size: 0.82rem;
  }

  .detail-list dd {
    margin-bottom: var(--sp-2);
  }
}
