/* ==========================================================================
   hr-ats — DESIGN.md for the palette, Linear for the motion.

   COLOUR, RADII AND SPACING come from DESIGN.md (workspace root) and nothing else.
   Every token below is copied verbatim; `scripts/check_design_tokens.py` diffs this
   file against the document and fails if a value drifts.

   MOTION AND INTERACTION MECHANICS come from DESIGN2.md's subject, Linear, whose
   live stylesheets were read directly. Those values are attributed inline where
   they are used. Not one colour was taken from there.

   Three rules from DESIGN.md that shape everything:
     - The canvas is cream (#f5f1ec), never pure white. Cards LIFT onto white.
     - No drop shadows at rest. Depth is the white-on-cream change and a hairline.
     - Charcoal is the system primary. Fin Orange is not a CTA colour.

   Three deliberate departures, each with its reason:

     1. DESIGN.md is a MARKETING system: 16px body, 72px display, "lead every
        section with a product screenshot". This is a dense internal tool with seven
        columns of candidate cards. The palette, radii, spacing, hairlines and
        elevation rules are followed exactly. The TYPE uses the lower end of the
        same scale wherever data is dense. No size is invented.

     2. Fin Orange has exactly one job: an application approaching or past its SLA,
        and only ever as a RULE OR DOT, never as text — it measures 2.84:1 on cream
        and WCAG AA wants 4.5:1. Breach text uses semantic-error, which measures
        5.29:1 and passes. Two urgency levels, both from DESIGN.md's own palette.

     3. DESIGN.md forbids drop shadows. A card held under the cursor is physically
        lifted, so it — and only it — carries one, for the duration of the drag.
        See `.drag-ghost`. The token script permits the shadow on that rule alone
        and fails on any other, so this stays a decision rather than a drift.
   ========================================================================== */

:root {
  /* --- colors (DESIGN.md > colors) ------------------------------------- */
  --primary: #111111;
  --on-primary: #ffffff;
  --ink: #111111;
  --ink-muted: #626260;
  --ink-subtle: #7b7b78;
  --ink-tertiary: #9c9fa5;
  --canvas: #f5f1ec;
  --surface-1: #ffffff;
  --surface-2: #ebe7e1;
  --inverse-canvas: #000000;
  --inverse-surface-1: #313130;
  --inverse-ink: #ffffff;
  --inverse-ink-muted: #9c9fa5;
  --hairline: #d3cec6;
  --hairline-soft: #ebe7e1;
  --fin-orange: #ff5600;
  --report-orange: #fe4c02;
  --report-blue: #65b5ff;
  --report-green: #0bdf50;
  --report-pink: #ff2067;
  --report-lime: #b3e01c;
  --report-cyan: #03b2cb;
  --brand-blue: #0007cb;
  --semantic-error: #c41c1c;
  --semantic-success: #0bdf50;

  /* --- rounded (DESIGN.md > rounded) ----------------------------------- */
  --rounded-xs: 4px;
  --rounded-sm: 6px;
  --rounded-md: 8px;
  --rounded-lg: 12px;
  --rounded-xl: 16px;
  --rounded-xxl: 24px;
  --rounded-pill: 9999px;
  --rounded-full: 9999px;   /* avatars; same value, kept for completeness */

  /* --- spacing (DESIGN.md > spacing), 8px base ------------------------- */
  --space-xxs: 4px;
  --space-xs: 8px;
  --space-sm: 12px;
  --space-md: 16px;
  --space-lg: 24px;
  --space-xl: 32px;
  --space-xxl: 48px;
  --space-section: 96px;

  /* --- type (DESIGN.md > typography) ----------------------------------- */
  --font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --text-display-md: 40px;   --track-display-md: -0.8px;
  --text-headline: 28px;     --track-headline: -0.5px;
  --text-card-title: 22px;   --track-card-title: -0.3px;
  --text-subhead: 20px;      --track-subhead: -0.2px;
  --text-body-lg: 18px;      --track-body-lg: -0.1px;
  --text-body: 16px;
  --text-body-sm: 14px;
  --text-caption: 12px;
  --text-button: 15px;
  --text-eyebrow: 14px;
  --text-mono: 13px;

  /* --- motion -----------------------------------------------------------
     Read from Linear's own `index.DF8NERDv.css`, not invented. They are the
     Penner ease-out curves; quint is the one Linear uses for entrances and
     quad for controls. Durations from their Button (.16s) and Providers (.48s).

     Every duration is a variable so `prefers-reduced-motion` can neutralise all
     of them in one place, below, rather than rule by rule. ----------------- */
  --ease-out-quint: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-out-quart: cubic-bezier(0.165, 0.84, 0.44, 1);
  --ease-out-quad: cubic-bezier(0.25, 0.46, 0.45, 0.94);

  --t-micro: 120ms;     /* hover tints, colour shifts */
  --t-control: 160ms;   /* buttons, inputs, nav */
  --t-surface: 240ms;   /* panels, bars, card settle */
  --t-enter: 480ms;     /* page entrance */

  /* The hover tint. Charcoal at 3% over white reads as a shift, not a colour. */
  --tint-hover: 0.030;
}

/* --- Inter, vendored as a single variable file: 48 KB for every weight, versus
   24 KB each for two static cuts, and it renders a true 500 rather than
   synthesising one. DESIGN.md names Inter as the closest free substitute for
   Saans. Served from our own Lambda — no external request, so Google never sees
   an HR user's IP. --------------------------------------------------------- */
@font-face {
  font-family: "Inter";
  src: url("/static/fonts/Inter-Variable.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("/static/fonts/JetBrainsMono-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ==========================================================================
   Reduced motion — one block, every duration, no exceptions.

   Not a nicety: vestibular disorders are real and a board that slides cards
   around is exactly the pattern that triggers them. Neutralising the tokens
   handles every transition written against them; the wildcard catches anything
   that slips through, including the JS animations.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  :root {
    --t-micro: 1ms;
    --t-control: 1ms;
    --t-surface: 1ms;
    --t-enter: 1ms;
  }
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }
}

/* ==========================================================================
   Base
   ========================================================================== */

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

/* Any author `display` declaration beats the user-agent [hidden] rule, so without
   this the `hidden` attribute silently does nothing on .bulk, .column-empty and
   anything else that sets display. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--canvas);
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--text-body-sm);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Figures never reflow as they change: a day count ticking 9→10 must not shove
     the tag beside it. Free with Inter, and the single cheapest craft win here. */
  font-variant-numeric: tabular-nums;
}

a {
  color: var(--ink);
  text-decoration: none;
  transition: color var(--t-micro) var(--ease-out-quad);
}
a:hover { text-decoration: underline; }

/* One focus ring for the whole interface. `:focus-visible`, not `:focus`, so a
   mouse click never draws it but a Tab always does. There was no visible focus
   state at all before this: the interface was unusable by keyboard. */
:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
  border-radius: var(--rounded-xs);
}

h1 {
  font-size: var(--text-headline);
  font-weight: 500;
  letter-spacing: var(--track-headline);
  line-height: 1.2;
  margin: 0 0 var(--space-xs);
}
h2 {
  font-size: var(--text-subhead);
  font-weight: 500;
  letter-spacing: var(--track-subhead);
  line-height: 1.25;
  margin: 0 0 var(--space-sm);
}
h3 {
  font-size: var(--text-body);
  font-weight: 500;
  margin: 0 0 var(--space-xs);
}

/* Sentence case, weight 500, no tracked caps — DESIGN.md is explicit about this. */
.eyebrow {
  font-size: var(--text-eyebrow);
  font-weight: 500;
  color: var(--ink-muted);
  line-height: 1.3;
  margin: 0;
}
.muted { color: var(--ink-muted); }
/* ink-muted, not ink-subtle: 5.44:1 vs 3.78:1 on cream. Helper text is meant
   to be read. ink-tertiary (2.36:1) never carries text anywhere in this file. */
.subtle { color: var(--ink-muted); font-size: var(--text-caption); }
.error { color: var(--semantic-error); }
code { font-family: var(--font-mono); font-size: var(--text-mono); }

/* ==========================================================================
   Icons — one inline <symbol> sprite in base.html, referenced by <use>.
   No library, no HTTP request, no build step. currentColor throughout, so an
   icon is always the colour of the text it sits beside.
   ========================================================================== */

.icon {
  width: 16px;
  height: 16px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  vertical-align: -3px;
}
.icon-sprite { display: none; }

/* ==========================================================================
   Top navigation — DESIGN.md > components > top-nav: cream, 56px, body-sm
   ========================================================================== */

header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  height: 56px;
  padding: 0 var(--space-lg);
  /* Plain colour first: a browser without color-mix drops that declaration and
     would otherwise be left with a transparent bar over scrolling cards. */
  background: var(--canvas);
  background: color-mix(in srgb, var(--canvas) 88%, transparent);
  /* Cards scroll under the bar rather than disappearing at a hard edge. */
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--hairline);
  position: sticky;
  top: 0;
  z-index: 20;
}
nav { display: flex; gap: var(--space-xs); align-items: center; }
nav a {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xxs);
  font-size: var(--text-body-sm);
  color: var(--ink-muted);
  padding: var(--space-xxs) var(--space-xs);
  border-radius: var(--rounded-sm);
  position: relative;
  transition: color var(--t-control) var(--ease-out-quad),
              background-color var(--t-control) var(--ease-out-quad);
}
nav a:hover { color: var(--ink); background: var(--surface-2); text-decoration: none; }
nav a.here {
  color: var(--ink);
  font-weight: 500;
  background: var(--surface-1);
  border: 1px solid var(--hairline);
  /* The border would otherwise shift the item 1px against its neighbours. */
  padding: 3px calc(var(--space-xs) - 1px);
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  font-size: var(--text-body);
  font-weight: 500;
  letter-spacing: -0.2px;
  color: var(--ink);
  margin-right: var(--space-sm);
}
.brand .icon { width: 18px; height: 18px; }
.who {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  font-size: var(--text-caption);
  color: var(--ink-muted);
}

main {
  padding: var(--space-lg);
  max-width: 1280px;
  margin: 0 auto;
  animation: page-in var(--t-enter) var(--ease-out-quint) both;
}
main.wide { max-width: none; }
/* Linear's own entrance: .48s on ease-out-quint. A short rise, not a slide — the
   page should feel like it settled, not like it flew in. */
@keyframes page-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
.page-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: var(--space-md);
  margin-bottom: var(--space-lg);
  flex-wrap: wrap;
}

/* ==========================================================================
   Surfaces — level 2 in DESIGN.md: white on cream, 1px hairline, no shadow
   ========================================================================== */

.panel {
  background: var(--surface-1);
  border: 1px solid var(--hairline);
  border-radius: var(--rounded-lg);
  padding: var(--space-lg);
  margin-bottom: var(--space-md);
  position: relative;
}
.panel.narrow { max-width: 420px; margin: var(--space-xxl) auto; }
.panel.flush { padding: 0; overflow: hidden; }
/* The result of an action that just ran. Surface-2 rather than a colour, because it
   reports an outcome rather than raising an alarm. Slides in so it is noticed. */
.panel.notice {
  background: var(--surface-2);
  padding: var(--space-sm) var(--space-md);
  animation: notice-in var(--t-surface) var(--ease-out-quart) both;
}
@keyframes notice-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}
.columns { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-md); }
@media (max-width: 1024px) { .columns { grid-template-columns: 1fr; } }

/* ==========================================================================
   Controls — charcoal primary, 8px radius, never pill
   ========================================================================== */

button, .button, input, select, textarea {
  font-family: var(--font);
  font-size: var(--text-button);
  line-height: 1.2;
}
button, .button {
  background: var(--ink);
  color: var(--on-primary);
  border: 1px solid var(--ink);
  border-radius: var(--rounded-md);
  padding: 10px 18px;
  font-weight: 500;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  min-height: 40px;               /* DESIGN.md: CTAs hold >= 40px tap height */
  position: relative;
  overflow: hidden;
  /* Linear's own transition-property list and .16s timing, from Button.css. */
  transition: background-color var(--t-control) var(--ease-out-quad),
              border-color var(--t-control) var(--ease-out-quad),
              color var(--t-control) var(--ease-out-quad),
              transform var(--t-micro) var(--ease-out-quad),
              opacity var(--t-control) var(--ease-out-quad);
}
button:hover, .button:hover { background: var(--inverse-canvas); text-decoration: none; }
/* A press that moves. One pixel is enough to feel; more reads as a bug. */
button:active, .button:active { transform: translateY(1px); }
button.secondary {
  background: var(--surface-1);
  color: var(--ink);
  border-color: var(--hairline);
}
button.secondary:hover, .button.secondary:hover {
  background: var(--surface-2);
  border-color: var(--ink-subtle);
}
button.danger { background: var(--semantic-error); border-color: var(--semantic-error); }
button.danger:hover { filter: brightness(0.88); }
/* Grey-on-grey, not white-on-grey: white on ink-tertiary measures 2.65:1 and the
   label cannot be read. WCAG exempts disabled controls from contrast, which is a
   reason it is not a violation, not a reason to ship it unreadable - a user still
   has to know what the button they cannot press would have done. */
button:disabled {
  background: var(--surface-2);
  color: var(--ink-muted);
  border-color: var(--hairline);
  cursor: not-allowed;
  transform: none;
}
button.small, .button.small { padding: 6px 12px; min-height: 32px; font-size: var(--text-body-sm); }

input, select, textarea {
  background: var(--surface-1);
  color: var(--ink);
  border: 1px solid var(--hairline);
  border-radius: var(--rounded-md);
  padding: 10px 14px;
  font-size: var(--text-body-sm);
  min-height: 40px;
  transition: border-color var(--t-control) var(--ease-out-quad);
}
input:hover, select:hover, textarea:hover { border-color: var(--ink-subtle); }
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--ink);
}
/* The field itself draws the ring, so it hugs the 8px radius instead of the
   generic focus outline boxing it. */
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 1px;
}
textarea { width: 100%; min-height: 96px; font-family: var(--font); resize: vertical; }
label { display: inline-flex; gap: var(--space-xs); align-items: center; font-size: var(--text-body-sm); }
input[type="checkbox"] {
  min-height: 0;
  width: 16px;
  height: 16px;
  accent-color: var(--ink);
  cursor: pointer;
}

form { display: flex; gap: var(--space-xs); align-items: center; flex-wrap: wrap; margin: 0 0 var(--space-sm); }
form:last-child { margin-bottom: 0; }
.filters { display: flex; gap: var(--space-xs); align-items: center; flex-wrap: wrap; }

/* Keyboard hint pills. Shape from Linear's KBD.css: 20px minimum, 4px radius,
   bordered, never pill. Shortcuts that are never shown are shortcuts nobody uses. */
kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  min-height: 20px;
  padding: 0 var(--space-xxs);
  font-family: var(--font);
  font-size: var(--text-caption);
  font-weight: 500;
  color: var(--ink-muted);
  background: var(--surface-1);
  border: 1px solid var(--hairline);
  border-radius: var(--rounded-xs);
}

/* ==========================================================================
   Tables
   ========================================================================== */

table { width: 100%; border-collapse: collapse; font-size: var(--text-body-sm); }
th, td { text-align: left; padding: var(--space-sm) var(--space-md); vertical-align: top; }
th {
  font-size: var(--text-caption);
  font-weight: 500;
  color: var(--ink-muted);
  border-bottom: 1px solid var(--hairline);
}
td { border-bottom: 1px solid var(--hairline-soft); }
tbody tr { transition: background-color var(--t-micro) var(--ease-out-quad); }
@media (any-hover: hover) { tbody tr:hover { background: var(--canvas); } }
tr:last-child td { border-bottom: none; }
dl { display: grid; grid-template-columns: 120px 1fr; gap: var(--space-xs) var(--space-md); margin: 0; font-size: var(--text-body-sm); }
/* ink-muted (5.44:1), not ink-subtle (3.78:1). These are field labels on the
   candidate record - "Email", "Phone", "CV" - and they have to be readable. */
dt { color: var(--ink-muted); }
dd { margin: 0; }

/* ==========================================================================
   The board
   Seven columns on cream; cards lift onto white. The board scrolls sideways
   rather than squeezing seven columns onto a laptop — DESIGN.md's grid guidance
   is for 3-up marketing cards and does not apply to a pipeline.
   ========================================================================== */

.board {
  display: flex;
  gap: var(--space-sm);
  overflow-x: auto;
  padding-bottom: var(--space-md);
  align-items: flex-start;
  /* Deliberately NOT scroll-behavior: smooth. Auto-scroll during a drag writes
     scrollLeft every frame, and smooth scrolling turns each of those writes into a
     new animation that fights the last one. */
  padding-top: var(--space-xxs);
}
.column {
  flex: 0 0 252px;
  background: var(--surface-2);
  border-radius: var(--rounded-lg);
  /* No TOP padding. In a scroll container, content scrolls up through the padding box
     and stays visible in it, so any top padding is a window above the sticky header
     that cards slide into and show through. The header supplies that space itself. */
  padding: 0 var(--space-sm) var(--space-sm);
  min-height: 120px;
  /* The column scrolls, not the page. Seven stages of unequal depth otherwise make
     the board as tall as its deepest column, and the other six are white space you
     scroll past to reach anything. */
  max-height: calc(100vh - 188px);
  overflow-y: auto;
  /* Reaching the end of a column must not start scrolling the board behind it. */
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--hairline) transparent;
  transition: background-color var(--t-surface) var(--ease-out-quart),
              opacity var(--t-surface) var(--ease-out-quart);
}
.column-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-xs);
  /* Sticky works now: `.column` has its own `overflow-y`, so IT is the scrollport
     rather than `.board`, and `top: 0` is measured from the column's own top. This
     was removed once for being a no-op; it earns its place now the column scrolls.
     The background is required - without one the cards scroll through the name. */
  position: sticky;
  top: 0;
  z-index: 2;
  /* Horizontal only. A negative TOP margin offsets the sticky margin box, which is
     what put the band lower than the scrollport edge and let cards appear above it. */
  margin: 0 calc(-1 * var(--space-sm));
  padding: var(--space-sm);
  background: var(--surface-2);
  border-radius: var(--rounded-lg) var(--rounded-lg) 0 0;
}
.column-head .name {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xxs);
  font-size: var(--text-body-sm);
  font-weight: 500;
  letter-spacing: -0.1px;
}
.column-head .count {
  font-size: var(--text-caption);
  color: var(--ink-muted);
  background: var(--surface-1);
  border-radius: var(--rounded-pill);
  padding: 1px var(--space-xs);
  min-width: 22px;
  text-align: center;
}
.column::-webkit-scrollbar { width: 8px; }
.column::-webkit-scrollbar-track { background: transparent; }
.column::-webkit-scrollbar-thumb {
  background: var(--hairline);
  border-radius: var(--rounded-pill);
}
.column-empty {
  font-size: var(--text-caption);
  color: var(--ink-muted);
  padding: var(--space-md) var(--space-xxs);
  text-align: center;
  border: 1px dashed var(--hairline);
  border-radius: var(--rounded-md);
}

/* A column this card's role does not use. Dimmed for the whole drag so an
   impossible drop looks impossible before it is attempted, not only refused
   afterwards. */
.board.dragging .column.invalid { opacity: 0.35; }
.board.dragging .column.valid { background: var(--hairline-soft); }
.column.over { background: var(--hairline); }
.column.over .column-head { background: var(--hairline); }
.board.dragging .column.valid .column-head { background: var(--hairline-soft); }

.card {
  background: var(--surface-1);
  border: 1px solid var(--hairline);
  border-radius: var(--rounded-md);
  padding: var(--space-sm);
  margin-bottom: var(--space-xs);
  position: relative;
  transition: border-color var(--t-micro) var(--ease-out-quad),
              opacity var(--t-surface) var(--ease-out-quart);
}
/* Linear's hover mechanic, from IssueCard.css: a tint overlay faded in, rather
   than a background swap. It composites instead of repainting, and it works on
   any surface colour. Wrapped in `any-hover` exactly as they do, so a touch
   device never leaves a card stuck in its hover state after a tap. */
.card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: var(--ink);
  opacity: 0;
  transition: opacity var(--t-micro) var(--ease-out-quad);
}
@media (any-hover: hover) {
  .card:hover::after { opacity: var(--tint-hover); }
  .card:hover { border-color: var(--ink-subtle); }
}
/* Only on the board. /queue renders the same card with no drop target, and a grab
   cursor there is an affordance that does nothing. */
.board .card { cursor: grab; touch-action: none; }
.board .card:active { cursor: grabbing; }
.card:last-child { margin-bottom: 0; }

/* The card left behind while its ghost follows the cursor. It stays in the DOM so
   a failed move has somewhere to return to. */
.card.dragging { opacity: 0.35; }
.card.dragging::after { opacity: 0; }
.card.saving { opacity: 0.55; cursor: wait; }

/* The lifted copy under the cursor. THE ONE PLACE A SHADOW IS ALLOWED — the value
   is Linear's own softest light-theme shadow. A card held in the hand is lifted;
   nothing at rest in this file has a shadow. */
.drag-ghost {
  position: fixed;
  z-index: 100;
  pointer-events: none;
  margin: 0;
  box-shadow: 0 7px 24px #0000000f;
  transform: rotate(1.5deg) scale(1.02);
  cursor: grabbing;
}
.drag-ghost::after { opacity: 0; }

/* The gap that opens where the card will land. Animated so the column visibly
   makes room rather than snapping. */
.drop-slot {
  border: 1px dashed var(--ink-subtle);
  border-radius: var(--rounded-md);
  background: transparent;
  margin-bottom: var(--space-xs);
  animation: slot-open var(--t-surface) var(--ease-out-quart);
}
@keyframes slot-open {
  from { opacity: 0; transform: scaleY(0.6); }
  to   { opacity: 1; transform: none; }
}

.card .top {
  display: flex;
  align-items: flex-start;
  gap: var(--space-xs);
  min-width: 0;
}
/* min-width:0 is what actually lets the name ellipsis inside a flex row; without
   it a long name grows the card instead of truncating. */
.card .who-what { flex: 1; min-width: 0; }
.card .name {
  display: block;
  font-size: var(--text-body-sm);
  font-weight: 500;
  letter-spacing: -0.1px;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.card .meta {
  font-size: var(--text-caption);
  color: var(--ink-muted);
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Tags pin to the bottom whatever the name length, so a column of cards has one
   baseline instead of a ragged one. Straight from Linear's IssueCard. */
.card .row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-xs);
  margin-top: var(--space-xs);
}
.card input[type="checkbox"] { position: absolute; top: var(--space-sm); right: var(--space-sm); }
.card .top { padding-right: var(--space-lg); }

/* Monochrome initials. DESIGN.md's report palette is for analytics surfaces, so
   colouring avatars from it would be a misuse; grey initials also stay legible
   for the ~8% of men with a colour vision deficiency. */
.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 24px;
  height: 24px;
  border-radius: var(--rounded-full);
  background: var(--surface-2);
  color: var(--ink-muted);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
}

/* --- the two urgency levels ---------------------------------------------
   DESIGN.md gives Fin Orange a single job in its own system; here that job is an
   application against its SLA.

   The WHOLE ticket carries it - a tinted surface and a matching border - rather
   than a coloured rule down one edge. A 3px bar is a decoration bolted to the side
   of a card that is otherwise identical to every other card; tinting the surface is
   how a board actually says "this one".

   The tints are computed from the palette with color-mix rather than picked by eye,
   so they cannot drift from DESIGN.md and check_contrast.py can resolve them. Both
   land lighter than the cream canvas, so text on a tinted card is more legible than
   text on the page itself.

   Colour is never the only signal: each state also spells its word in the SLA line.
   Fin Orange measures 2.84:1 on cream and never carries text. */
.card.due {
  background: color-mix(in srgb, var(--fin-orange) 10%, var(--surface-1));
  border-color: color-mix(in srgb, var(--fin-orange) 45%, var(--hairline));
}
.card.overdue {
  background: color-mix(in srgb, var(--semantic-error) 10%, var(--surface-1));
  border-color: color-mix(in srgb, var(--semantic-error) 48%, var(--hairline));
}
.sla {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xxs);
  font-size: var(--text-caption);
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}
.sla .dot {
  width: 6px;
  height: 6px;
  border-radius: var(--rounded-full);
  background: var(--fin-orange);
  flex: none;
}
.sla.over { color: var(--semantic-error); font-weight: 500; }
.sla.over .dot { background: var(--semantic-error); }

.tag {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xxs);
  font-size: var(--text-caption);
  background: var(--canvas);
  color: var(--ink-muted);
  border: 1px solid var(--hairline-soft);
  border-radius: var(--rounded-xs);
  padding: 1px var(--space-xs);
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tag.held { background: var(--surface-2); }
/* Blocked on someone else rather than on you. */
.tag.waiting {
  background: var(--surface-2);
  border-color: var(--hairline);
  color: var(--ink-muted);
}

/* The right-hand end of a card's bottom row. Wraps rather than squeezing, because a
   candidate can have a resume, a pending scorecard and a drive tag at once. */
.chips {
  display: flex;
  align-items: center;
  gap: var(--space-xxs);
  flex-wrap: wrap;
  justify-content: flex-end;
  min-width: 0;
}

/* The resume link. DESIGN.md's brand-blue, which is the palette's only link colour and
   measures 11.09:1 on white - the point being that it must be unmistakably a link.
   Everything else in this interface is charcoal, so blue reads as "this navigates". */
.cv {
  color: var(--brand-blue);
  background: var(--surface-1);
  font-size: var(--text-caption);
  font-weight: 500;
  border: 1px solid color-mix(in srgb, var(--brand-blue) 25%, var(--hairline));
  border-radius: var(--rounded-xs);
  padding: 1px var(--space-xs);
  white-space: nowrap;
  transition: background-color var(--t-micro) var(--ease-out-quad),
              border-color var(--t-micro) var(--ease-out-quad);
}
.cv:hover {
  text-decoration: none;
  background: color-mix(in srgb, var(--brand-blue) 8%, var(--surface-1));
  border-color: var(--brand-blue);
}
/* The same treatment at body size, for the record where it is a primary action rather
   than a chip. Plain underlined text there read as prose, so nobody clicked it. */
.cv.wide {
  font-size: var(--text-body-sm);
  padding: 6px var(--space-sm);
  border-radius: var(--rounded-md);
  display: inline-flex;
  align-items: center;
  gap: var(--space-xxs);
  min-height: 32px;
}
.tag .icon { width: 11px; height: 11px; }

/* Bulk bar — reject only. Advancing is dragging now. */
.bulk {
  position: sticky;
  bottom: 0;
  display: flex;
  gap: var(--space-xs);
  align-items: center;
  flex-wrap: wrap;
  background: var(--surface-1);
  border: 1px solid var(--hairline);
  border-radius: var(--rounded-lg);
  padding: var(--space-sm) var(--space-md);
  margin-top: var(--space-md);
  animation: bulk-in var(--t-surface) var(--ease-out-quart);
}
@keyframes bulk-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
.bulk .count-selected { font-weight: 500; }
/* The bar is stuck to the bottom of the viewport and sits over the board whenever
   anything is selected, so a drop released on it would hit the bar instead of the
   column under it. Nobody can use the bar mid-drag anyway. `.board` and `.bulk` are
   siblings inside #bulk-form, so this needs no state on the body. */
.board.dragging ~ .bulk { pointer-events: none; }

.list { display: grid; grid-template-columns: repeat(auto-fill, minmax(244px, 1fr)); gap: var(--space-xs); }

/* Left-aligned, one line. Not a centred icon above a bold headline above a grey
   subtitle: that arrangement is the most recognisable machine-written pattern
   there is, and it turns "nothing here" into a full-height ceremony. */
.empty {
  padding: var(--space-lg) 0;
  color: var(--ink-muted);
  max-width: 62ch;
}

/* ==========================================================================
   The candidate drawer — the record over the board, instead of a page away from it
   ========================================================================== */

#drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: min(960px, 94vw);
  background: var(--canvas);
  border-left: 1px solid var(--hairline);
  overflow-y: auto;
  overscroll-behavior: contain;
  z-index: 60;
  padding: var(--space-lg);
  scrollbar-width: thin;
  scrollbar-color: var(--hairline) transparent;
  animation: drawer-in var(--t-surface) var(--ease-out-quart);
}
/* Empty is closed. No state class to keep in step with the content, so a swap that
   script did not observe cannot leave the drawer stuck open. */
#drawer:empty { display: none; }
@keyframes drawer-in {
  from { opacity: 0; transform: translateX(24px); }
  to   { opacity: 1; transform: none; }
}

.drawer-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 55;
  background: var(--inverse-canvas);
  opacity: 0.28;
}
body:has(#drawer:not(:empty)) .drawer-backdrop { display: block; }

.record-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--space-md);
  margin-bottom: var(--space-lg);
  flex-wrap: wrap;
}
.record-actions { display: flex; gap: var(--space-xs); align-items: center; }
/* Closing means something only inside the drawer; the full page has Back. */
[data-close-drawer] { display: none; }
#drawer [data-close-drawer] { display: inline-flex; }

.interview {
  border-top: 1px solid var(--hairline-soft);
  padding: var(--space-sm) 0;
}
.interview:first-of-type { border-top: none; padding-top: 0; }
.interview p { margin: 0 0 var(--space-xxs); }
.scores {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xxs) var(--space-md);
  font-size: var(--text-caption);
  color: var(--ink-muted);
  align-items: center;
}
.scores b {
  color: var(--ink);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

/* Live region for drag results — announced to screen readers, visible to everyone. */
.toast {
  position: fixed;
  left: 50%;
  bottom: var(--space-lg);
  background: var(--inverse-canvas);
  color: var(--inverse-ink);
  font-size: var(--text-body-sm);
  padding: var(--space-sm) var(--space-md);
  border-radius: var(--rounded-md);
  z-index: 50;
  max-width: 520px;
  transform: translate(-50%, 0);
  /* A status message is not a target. Without this it sat over the bottom of the
     board for five seconds after every move, eating the next drop and any click on
     a card underneath it. */
  pointer-events: none;
  animation: toast-in var(--t-surface) var(--ease-out-quart);
}
@keyframes toast-in {
  from { opacity: 0; transform: translate(-50%, 12px); }
  to   { opacity: 1; transform: translate(-50%, 0); }
}
.toast:empty { opacity: 0; padding: 0; }

/* ==========================================================================
   Funnel — the one place the report palette belongs. DESIGN.md is explicit that
   those colours are in-product analytics colours, not marketing surfaces, and a
   funnel is exactly an in-product analytics surface.
   ========================================================================== */

.bar {
  height: 6px;
  border-radius: var(--rounded-pill);
  background: var(--report-blue);
  min-width: 2px;
  transform-origin: left center;
  animation: bar-grow var(--t-enter) var(--ease-out-quint) both;
}
/* The bar's own width stays an inline style: it is a computed value per row, which
   is data rather than styling. These two are the styling, so they live here. */
.chart-col { width: 32%; }
input.tiny { width: 68px; }

/* The pipeline picker. A fieldset so the seven checkboxes read as one control with one
   label, rather than seven unrelated toggles that happen to sit together. */
.stage-picker {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs) var(--space-md);
  border: 1px solid var(--hairline);
  border-radius: var(--rounded-md);
  padding: var(--space-sm) var(--space-md);
  margin: 0;
  background: var(--surface-1);
}
.stage-picker legend {
  font-size: var(--text-caption);
  color: var(--ink-muted);
  padding: 0 var(--space-xxs);
}
@keyframes bar-grow {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

/* ==========================================================================
   Responsive — DESIGN.md breakpoints
   ========================================================================== */

@media (max-width: 768px) {
  header { padding: 0 var(--space-md); }
  nav { gap: var(--space-xxs); overflow-x: auto; }
  nav a span { display: none; }         /* icons only; the labels do not fit */
  nav a .icon { width: 18px; height: 18px; }
  main { padding: var(--space-md); }
  h1 { font-size: var(--text-card-title); letter-spacing: var(--track-card-title); }
  dl { grid-template-columns: 1fr; }
}
