/* ==========================================================================
   Design system aplikacji Matchtly, przeniesiony z ~/matchtly/frontend/assets/css/main.css
   Dodane tylko wartości, które w aplikacji dostarcza Tailwind i Nuxt UI.
   Plik ładowany wyłącznie w ramce demo (app-demo.html), nie na landingu.
   ========================================================================== */
:root {
  --color-white: #ffffff;
  --color-violet-50: #f5f3ff;  --color-violet-100: #ede9fe; --color-violet-200: #ddd6fe;
  --color-violet-300: #c4b5fd; --color-violet-400: #a78bfa; --color-violet-500: #8b5cf6;
  --color-violet-600: #7c3aed; --color-violet-700: #6d28d9; --color-violet-800: #5b21b6;
  --color-violet-900: #4c1d95; --color-violet-950: #2e1065;
  --color-fuchsia-300: #f0abfc; --color-fuchsia-400: #e879f9;
  --color-fuchsia-500: #d946ef; --color-fuchsia-600: #c026d3;
  --color-gray-50: #f9fafb; --color-gray-200: #e5e7eb; --color-gray-600: #4b5563; --color-gray-900: #111827;

  /* tokeny, które w aplikacji wystawia Nuxt UI */
  --ui-bg: #ffffff;
  --ui-bg-muted: #f7f8fa;
  --ui-text-highlighted: #1b1f2a;
  --ui-primary: #7c3aed;
}

/* --- tokeny projektowe aplikacji (z @theme static) --- */
:root {
  /* Brand — violet ramp aliased as primary */
  --color-primary-50:  var(--color-violet-50);
  --color-primary-100: var(--color-violet-100);
  --color-primary-200: var(--color-violet-200);
  --color-primary-300: var(--color-violet-300);
  --color-primary-400: var(--color-violet-400);
  --color-primary-500: var(--color-violet-500);
  --color-primary-600: var(--color-violet-600);
  --color-primary-700: var(--color-violet-700);
  --color-primary-800: var(--color-violet-800);
  --color-primary-900: var(--color-violet-900);
  --color-primary-950: var(--color-violet-950);

  /* Accent — fuchsia ramp for gradients */
  --color-accent-300: var(--color-fuchsia-300);
  --color-accent-400: var(--color-fuchsia-400);
  --color-accent-500: var(--color-fuchsia-500);
  --color-accent-600: var(--color-fuchsia-600);

  /*
   * Neutral ramp — `ink`. Replaces Tailwind's `zinc` as Nuxt UI's neutral
   * (see app.config.ts). Calibrated against ClickUp's greys, then nudged a
   * few degrees cooler: the pure-grey original reads clinical next to the
   * violet brand, whereas a hint of blue in the mid-tones lets the two sit
   * together without the interface looking tinted.
   *
   * Nuxt UI derives every --ui-* surface and text token from this ramp, so
   * changing these eleven values re-skins the whole application.
   */
  --color-ink-50:  #f7f8fa;
  --color-ink-100: #f2f3f6;
  --color-ink-200: #ebedf1;
  --color-ink-300: #e3e5ea;
  --color-ink-400: #c4c8d2;
  --color-ink-500: #8b91a1;
  --color-ink-600: #6b7280;
  --color-ink-700: #3d4453;
  --color-ink-800: #2a3040;
  --color-ink-900: #1b1f2a;
  --color-ink-950: #12151d;

  /* Surface / text shorthands */
  --color-surface:        var(--color-white);
  --color-surface-muted:  var(--color-gray-50);
  --color-border-subtle:  var(--color-gray-200);
  --color-text-strong:    var(--color-gray-900);
  --color-text-muted:     var(--color-gray-600);

  /* Brand gradients */
  --gradient-brand: linear-gradient(135deg, var(--color-primary-600), var(--color-accent-500));
  --gradient-hero:  linear-gradient(160deg, var(--color-primary-900), var(--color-primary-800), var(--color-primary-950));
  --gradient-soft:  linear-gradient(135deg, var(--color-primary-50), var(--color-primary-100));

  /*
   * Typography — the makieta's stack, and only the makieta's stack.
   *
   * The mock-up names Inter first but never loads it, so every screen we
   * signed off on was actually rendered in the platform UI font: SF Pro on
   * macOS, Segoe UI on Windows. The application did download Inter, and Inter
   * is wider and has a taller x-height than either, so at identical px values
   * the same interface came out heavier and roughly a column wider than the
   * mock-up it was copied from.
   *
   * Keeping Inter in the list here would re-download it (@nuxt/fonts picks up
   * families declared in this file), so it is deliberately absent. If Inter is
   * ever adopted as the brand face, add it back here AND re-tune the type
   * scale — the two decisions belong together.
   */
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, ui-sans-serif, sans-serif;

  /*
   * Type scale, one step tighter than Tailwind's default. The application is a
   * data tool — a recruiter scans tables and boards, they don't read prose — so
   * 14px browser-default body text wastes a row of vertical space per record.
   * Rescaling the ramp rather than shrinking the root font-size keeps every
   * rem-based padding, gap and icon size exactly where it was; only glyphs move.
   */
  --text-xs:   0.6875rem;  /* 11px — uppercase labels */
  --text-xs--line-height:   1rem;
  --text-sm:   0.8125rem;  /* 13px — UI baseline */
  --text-sm--line-height:   1.125rem;
  --text-base: 0.875rem;   /* 14px — record names */
  --text-base--line-height: 1.25rem;
  --text-lg:   1rem;       /* 16px — section headings */
  --text-lg--line-height:   1.5rem;
  --text-xl:   1.125rem;   /* 18px */
  --text-xl--line-height:   1.625rem;
  --text-2xl:  1.25rem;    /* 20px — page titles */
  --text-2xl--line-height:  1.75rem;

  /*
   * Radii — a four-step scale: tags, then anything you click, then anything
   * that contains other things, then the few large panels.
   *
   * One step softer than the makieta's 4/6/8/12. At the makieta's values every
   * corner in the application read as a hard angle once they were all on screen
   * together; two extra pixels on the container steps is enough to take that
   * off without turning small controls into pills.
   */
  --radius-tag:  0.3125rem; /* 5px  */
  --radius-btn:  0.4375rem; /* 7px  */
  --radius-card: 0.625rem;  /* 10px */
  --radius-panel: 0.875rem; /* 14px */

  /* Shell dimensions — makieta --rail-w / --panel-w / --bar-h */
  --rail-width:   3.5rem;    /* 56px  — icon rail */
  --panel-width:  14.75rem;  /* 236px — contextual panel */
  --sidebar-width: 15rem;    /* 240px — mobile drawer only */
}

/*
 * Semantic overrides on top of Nuxt UI's own token layer.
 *
 * Nuxt UI derives --ui-border from neutral-200, which at this ramp is the same
 * value as --ui-bg-accented — hairlines would disappear against hover states.
 * Bumping the border tokens one step up restores the separation.
 */
:root {
  --ui-radius: 0.375rem;
  --ui-border: var(--color-ink-300);
  --ui-border-muted: var(--color-ink-200);
  --ui-border-accented: var(--color-ink-400);

  /*
   * Text ladder, pinned to the makieta's three levels rather than to Nuxt UI's
   * derivation from the neutral ramp. --text (#5a6172) is one step lighter
   * than ink-700 and --text-3 (#8b91a1) serves as both muted and dimmed —
   * in the makieta they are genuinely the same value.
   */
  --ui-text: #5a6172;
  --ui-text-toned: #5a6172;
  --ui-text-muted: #8b91a1;
  --ui-text-dimmed: #8b91a1;

  /*
   * Navigation rail — the brand gradient, deepened.
   *
   * It has to stay dark enough that white icons hold their contrast and the
   * rail never competes with the data, so this is the violet ramp's bottom
   * half rather than the bright 135° brand gradient: a touch of fuchsia at the
   * top edge, violet-950 at the bottom.
   *
   * The angle is deliberately vertical (180deg) rather than diagonal. The
   * shell paints this same gradient behind the content column, so the rounded
   * corners where the content sits on the rail reveal the exact colour the
   * rail has at that height — a diagonal would show a seam there.
   */
  --sidebar-bg: linear-gradient(
    180deg,
    color-mix(in oklab, var(--color-primary-800) 86%, var(--color-accent-600)) 0%,
    var(--color-primary-900) 44%,
    var(--color-primary-950) 100%
  );

  /* Hover / pressed washes — makieta --hover / --pressed */
  --wash-hover: rgb(24 26 34 / 0.04);
  --wash-pressed: rgb(24 26 34 / 0.07);

  /* Shadows — makieta --sh-1 / --sh-2 / --sh-3 */
  --sh-1: 0 0 0 1px rgb(16 24 40 / 0.05), 0 1px 2px rgb(16 24 40 / 0.04);
  --sh-2: 0 0 0 1px rgb(16 24 40 / 0.05), 0 4px 10px -2px rgb(16 24 40 / 0.08);
  --sh-3: 0 0 0 1px rgb(16 24 40 / 0.05), 0 12px 28px -6px rgb(16 24 40 / 0.14);

  /* Density — one place to trade comfort for rows-on-screen. */
  --row-h: 38px;         /* data row */
  --control-h: 30px;     /* toolbar button / input */
  --bar-h: 46px;         /* toolbar band */
  --row-py: 0.4375rem;   /* 7px top/bottom → 38px rows at 13px text */
  --row-px: 0.625rem;    /* 10px — makieta cell padding */

  /* Row hover — a half-step off white, not the muted canvas. */
  --row-hover: #fcfcfd;

  /*
   * Status palette. Data-bearing labels (stage, availability, contract type)
   * pick one of these eight; the brand ramp stays out of it so a violet chip
   * always means "brand", never "some category".
   */
  --st-neutral-bg: #eff0f3; --st-neutral-fg: #5a6172;
  --st-blue-bg:    #e9f2ff; --st-blue-fg:    #1257b0;
  --st-green-bg:   #e6f8ee; --st-green-fg:   #12734a;
  --st-amber-bg:   #fff4d6; --st-amber-fg:   #8a5a1a;
  --st-red-bg:     #ffeef0; --st-red-fg:     #b3282e;
  --st-purple-bg:  #f0f0ff; --st-purple-fg:  #4f3fc4;
  --st-magenta-bg: #fdeffb; --st-magenta-fg: #93268f;
  --st-teal-bg:    #e4f7f4; --st-teal-fg:    #0d6f66;
}

/*
 * Baseline type. The makieta sets the document to 13px/1.45 — the application
 * is a data tool, and every step above that costs a row of vertical space per
 * record. Set on <body> rather than on :root so rem-based spacing is untouched.
 */
body {
  font-size: 0.8125rem;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
}

/*
 * ---------------------------------------------------------------------------
 * Makieta primitives
 * ---------------------------------------------------------------------------
 * Small, fixed-geometry building blocks lifted verbatim from the mock-up
 * (matchtly-redesign/makieta.html). They are plain CSS rather than Tailwind
 * utility strings because their whole point is exact, repeated geometry:
 * a pill is 20px tall everywhere, a toolbar control is 30px everywhere. Stated
 * once here, they cannot drift between the six screens that use them.
 */

/*
 * Application shell.
 *
 * `.m-shell` is the full-viewport frame and carries the rail's gradient across
 * its whole width; `.m-rail` sits on it transparently. `.m-canvas` is
 * everything to the right of the rail — contextual panel plus content — and it
 * is what actually paints the working surface. Because it is rounded on its
 * left corners, the gradient shows through at top-left and bottom-left, so the
 * content reads as a sheet resting on the rail rather than as a second panel
 * butted against it.
 */
.m-shell { background: var(--sidebar-bg); }
.m-rail { background: transparent; }
/* Same gradient for surfaces that stand alone rather than on the shell —
   the mobile topbar and drawer. It is a `background`, not a `background-color`,
   so it cannot be applied with Tailwind's bg-(--token) shorthand. */
.m-brandbg { background: var(--sidebar-bg); }
.m-canvas {
  background: var(--ui-bg-muted);
  overflow: hidden;
}
/* Only where a rail exists to rest on: never below lg (the rail is hidden
   there), and never when it is collapsed or the user is logged out. */
@media (min-width: 64rem) {
  .m-canvas:not(.is-flush) {
    border-top-left-radius: var(--radius-panel);
    border-bottom-left-radius: var(--radius-panel);
  }
}

/* Rail button — 40px, 10px corners, label on hover. */
.m-railbtn {
  position: relative;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 10px;
  color: rgb(255 255 255 / 0.62);
  text-decoration: none;
  transition: .13s;
  cursor: pointer;
}
.m-railbtn:hover { background: rgb(255 255 255 / 0.12); color: #fff; }
.m-railbtn.is-active { background: rgb(255 255 255 / 0.17); color: #fff; }

/* Status pill — 20px, soft tint, optional leading dot. */
.m-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 20px;
  padding: 0 8px;
  border-radius: var(--radius-btn);
  font-size: 11.5px;
  font-weight: 600;
  white-space: nowrap;
}
.m-pill .m-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; opacity: .85; flex: none; }
.m-pill-neutral { background: var(--st-neutral-bg); color: var(--st-neutral-fg); }
.m-pill-blue    { background: var(--st-blue-bg);    color: var(--st-blue-fg); }
.m-pill-green   { background: var(--st-green-bg);   color: var(--st-green-fg); }
.m-pill-amber   { background: var(--st-amber-bg);   color: var(--st-amber-fg); }
.m-pill-red     { background: var(--st-red-bg);     color: var(--st-red-fg); }
.m-pill-purple  { background: var(--st-purple-bg);  color: var(--st-purple-fg); }
.m-pill-magenta { background: var(--st-magenta-bg); color: var(--st-magenta-fg); }
.m-pill-teal    { background: var(--st-teal-bg);    color: var(--st-teal-fg); }

/* Inert tag — 19px, hairline ring, no meaning beyond "this is a value". */
.m-tag {
  display: inline-flex;
  align-items: center;
  height: 19px;
  padding: 0 7px;
  border-radius: var(--radius-tag);
  font-size: 11px;
  font-weight: 400;
  background: var(--color-ink-100);
  color: var(--ui-text);
  box-shadow: inset 0 0 0 1px var(--ui-border-muted);
  white-space: nowrap;
}

/* Toolbar button — 30px, quiet until hovered. */
.m-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: var(--control-h);
  padding: 0 10px;
  border-radius: var(--radius-btn);
  font-size: 12.5px;
  font-weight: 500;
  color: var(--ui-text);
  white-space: nowrap;
  transition: .12s;
  cursor: pointer;
}
.m-btn:hover { background: var(--wash-hover); color: var(--ui-text-highlighted); }
.m-btn:disabled { opacity: .45; pointer-events: none; }
.m-btn-bordered { box-shadow: inset 0 0 0 1px var(--ui-border); background: var(--ui-bg); }
.m-btn-bordered:hover { box-shadow: inset 0 0 0 1px var(--color-ink-400); background: var(--ui-bg); }
.m-btn-primary {
  background: var(--color-primary-600);
  color: #fff;
  font-weight: 550;
  box-shadow: 0 1px 2px rgb(16 24 40 / 0.12);
}
.m-btn-primary:hover { background: var(--color-primary-700); color: #fff; }
/*
 * The one destructive action that belongs in a toolbar rather than behind a
 * menu: rejecting a candidate. Red enough to be found without looking, tinted
 * rather than solid so it never outweighs the primary action beside it.
 */
.m-btn-danger {
  background: linear-gradient(150deg,
    color-mix(in srgb, var(--st-red-bg) 96%, var(--st-red-fg)),
    color-mix(in srgb, var(--st-red-bg) 40%, var(--ui-bg)) 82%);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--st-red-fg) 34%, transparent);
  color: var(--st-red-fg);
  font-weight: 550;
}
.m-btn-danger:hover {
  background: linear-gradient(150deg,
    color-mix(in srgb, var(--st-red-bg) 80%, var(--st-red-fg)),
    color-mix(in srgb, var(--st-red-bg) 62%, var(--ui-bg)) 82%);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--st-red-fg) 46%, transparent);
  color: var(--st-red-fg);
}

/* The amber twin of m-btn-danger, for an action that is consequential but not
   destructive: ignoring a candidate hides them from every list and from
   Matchtly's suggestions, and nothing is deleted. */
.m-btn-warn {
  background: linear-gradient(150deg,
    color-mix(in srgb, var(--st-amber-bg) 96%, var(--st-amber-fg)),
    color-mix(in srgb, var(--st-amber-bg) 40%, var(--ui-bg)) 82%);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--st-amber-fg) 34%, transparent);
  color: var(--st-amber-fg);
  font-weight: 550;
}
.m-btn-warn:hover {
  background: linear-gradient(150deg,
    color-mix(in srgb, var(--st-amber-bg) 80%, var(--st-amber-fg)),
    color-mix(in srgb, var(--st-amber-bg) 62%, var(--ui-bg)) 82%);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--st-amber-fg) 46%, transparent);
  color: var(--st-amber-fg);
}

/* Both of the above at once: the wash walks from amber into red, for the
   action that ignores AND rejects in one click. */
.m-btn-warn-danger {
  background: linear-gradient(115deg,
    color-mix(in srgb, var(--st-amber-bg) 96%, var(--st-amber-fg)),
    color-mix(in srgb, var(--st-red-bg) 92%, var(--st-red-fg)) 88%);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--st-red-fg) 30%, transparent);
  color: var(--st-red-fg);
  font-weight: 550;
}
.m-btn-warn-danger:hover {
  background: linear-gradient(115deg,
    color-mix(in srgb, var(--st-amber-bg) 82%, var(--st-amber-fg)),
    color-mix(in srgb, var(--st-red-bg) 76%, var(--st-red-fg)) 88%);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--st-red-fg) 42%, transparent);
  color: var(--st-red-fg);
}

.m-btn-ai { background: var(--gradient-ai); color: #fff; font-weight: 550; }
/* background restated: the generic .m-btn:hover wash otherwise overrides the
   gradient (this rule sets no background of its own) and the button flashed
   white with white text. */
.m-btn-ai:hover { background: var(--gradient-ai); filter: brightness(1.07); color: #fff; }

/* "Lit" state for a button that asks for attention (the brief was edited by
   hand, candidate ratings are stale): a slow pulsing halo in the brand color.
   Pairs with m-btn-ai for the fill; the halo alone is too subtle on a
   bordered button. */
@keyframes m-btn-glow {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--color-primary-600) 45%, transparent); }
  50% { box-shadow: 0 0 0 6px color-mix(in srgb, var(--color-primary-600) 0%, transparent); }
}
.m-btn-glow { animation: m-btn-glow 1.8s ease-in-out infinite; }

/* Icon chip for editor section headers (form editor: appearance, confirmation,
   fields). A tinted square that gives each section an identity at a glance —
   collapsed sections otherwise read as empty grey bars. */
.m-secic {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 10px;
  flex: none;
}
.m-secic-purple { background: var(--st-purple-bg); color: var(--st-purple-fg); }

/* The sticky save bar of the form editors. It floats over scrolled content,
   so it needs to read as "chrome", not as another white card: a soft brand
   wash with a purple inset ring separates it from whatever slides under. */
.m-savebar {
  background: linear-gradient(150deg,
    color-mix(in srgb, var(--st-purple-bg) 88%, var(--ui-bg)),
    color-mix(in srgb, var(--st-purple-bg) 30%, var(--ui-bg)) 78%);
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb, var(--st-purple-fg) 26%, transparent),
    var(--sh-1);
}
.m-secic-blue   { background: var(--st-blue-bg);   color: var(--st-blue-fg); }
.m-secic-teal   { background: var(--st-teal-bg);   color: var(--st-teal-fg); }
.m-secic-amber  { background: var(--st-amber-bg);  color: var(--st-amber-fg); }

/* The quiet cousin of m-btn-ai, for AI actions living among other buttons on
   one bar: a purple tint at rest, deeper purple on hover — same construction
   as m-btn-warn/danger. */
.m-btn-ai-soft {
  background: linear-gradient(150deg,
    color-mix(in srgb, var(--st-purple-bg) 96%, var(--st-purple-fg)),
    color-mix(in srgb, var(--st-purple-bg) 40%, var(--ui-bg)) 82%);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--st-purple-fg) 34%, transparent);
  color: var(--st-purple-fg);
  font-weight: 550;
}
.m-btn-ai-soft:hover {
  background: linear-gradient(150deg,
    color-mix(in srgb, var(--st-purple-bg) 74%, var(--st-purple-fg)),
    color-mix(in srgb, var(--st-purple-bg) 55%, var(--ui-bg)) 82%);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--st-purple-fg) 48%, transparent);
  color: var(--st-purple-fg);
}
.m-btn-icon { width: var(--control-h); padding: 0; justify-content: center; }
.m-btn-sm { height: 26px; font-size: 12px; padding: 0 8px; }

/* Filter chip — 26px, ringed; `.is-on` is the applied state. */
.m-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 26px;
  padding: 0 9px;
  border-radius: var(--radius-btn);
  font-size: 12px;
  font-weight: 500;
  color: var(--ui-text);
  background: var(--ui-bg);
  box-shadow: inset 0 0 0 1px var(--ui-border);
  white-space: nowrap;
  transition: .12s;
  cursor: pointer;
}
.m-chip:hover { box-shadow: inset 0 0 0 1px var(--color-ink-400); }
.m-chip.is-on {
  background: var(--color-primary-50);
  color: var(--color-primary-700);
  box-shadow: inset 0 0 0 1px var(--color-primary-200);
}

/* Segmented control. */
.m-seg { display: inline-flex; background: var(--color-ink-100); border-radius: var(--radius-btn); padding: 2px; }
.m-seg button {
  height: 26px; padding: 0 10px; border-radius: 4px;
  font-size: 12px; font-weight: 500; color: var(--ui-text);
  display: inline-flex; align-items: center; gap: 5px;
}
.m-seg button.is-on { background: var(--ui-bg); color: var(--ui-text-highlighted); box-shadow: var(--sh-1); }

/* Vertical hairline between toolbar groups. */
.m-div { width: 1px; height: 18px; background: var(--ui-border); margin: 0 4px; flex: none; }

/* AI provenance marker — the small "Matchtly AI" label. */
.m-aitag {
  display: inline-flex; align-items: center; gap: 4px;
  height: 19px; padding: 0 7px; border-radius: var(--radius-tag);
  font-size: 10.5px; font-weight: 650; letter-spacing: .02em;
  color: var(--color-primary-600);
  background: color-mix(in srgb, var(--color-primary-600) 8%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-primary-600) 22%, transparent);
}

/*
 * Data table. `.m-table` is the makieta's table geometry: a 32px sticky header
 * in small caps, 38px rows, hairlines in --line-soft, and a hover that is a
 * half-step off white rather than the muted canvas.
 */
.m-tablewrap {
  background: var(--ui-bg);
  border: 1px solid var(--ui-border);
  border-radius: var(--radius-card);
  overflow: hidden;
}
.m-table { width: 100%; border-collapse: separate; border-spacing: 0; }
.m-table thead th {
  position: sticky; top: 0; z-index: 5;
  background: var(--ui-bg);
  height: 32px; padding: 0 var(--row-px);
  text-align: left;
  font-size: 11px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--ui-text-dimmed);
  border-bottom: 1px solid var(--ui-border);
  user-select: none;
  /* A header that outgrows its column ellipsises instead of spilling into the
     next one — column widths are fixed, but label lengths are not (they change
     with the locale). */
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.m-table tbody td {
  height: var(--row-h);
  padding: 0 var(--row-px);
  border-bottom: 1px solid var(--ui-border-muted);
  font-size: 13px;
  color: var(--ui-text);
  vertical-align: middle;
  white-space: nowrap;
}
.m-table tbody tr { transition: background .1s; }
.m-table tbody tr:hover { background: var(--row-hover); }
.m-table tbody tr:hover .m-rowact { opacity: 1; }
/*
 * Outcome rows. A recruitment that closed won and one that closed lost are the
 * two rows a reader looks for first, so the whole row carries the result rather
 * than one cell doing it. The wash is a fraction of the pill colour: at full
 * strength a table of closed recruitments reads as an alert, and the figures
 * inside the rows stop being the loudest thing in them. Hover deepens it
 * instead of replacing it, so a tinted row still answers when the cursor is
 * over it.
 */
.m-table tbody tr.m-row-won { background: color-mix(in srgb, var(--st-green-bg) 52%, var(--ui-bg)); }
.m-table tbody tr.m-row-won:hover { background: color-mix(in srgb, var(--st-green-bg) 78%, var(--ui-bg)); }
.m-table tbody tr.m-row-lost { background: color-mix(in srgb, var(--st-red-bg) 52%, var(--ui-bg)); }
.m-table tbody tr.m-row-lost:hover { background: color-mix(in srgb, var(--st-red-bg) 78%, var(--ui-bg)); }
/*
 * Record name. Normal weight, one step up in size, and the darkest text colour
 * in the table — that is enough to make it the thing you read first. It used
 * to be semibold as well, which on a screen where the client tag, the priority
 * and the deadline were all also emphasised meant nothing was.
 */
.m-table td.m-name { color: var(--ui-text-highlighted); font-weight: 400; font-size: 13.5px; }
.m-table td.m-name a:hover { color: var(--color-primary-700); }
.m-table.m-fixed { table-layout: fixed; }
/* In a fixed-layout table a cell wider than its column spills over the one next
   to it — a deadline printed straight through the column beside it. Clipping,
   but no ellipsis: several cells end in a control that is invisible until the
   row is hovered, and an ellipsis for a hidden chevron reads as truncated data
   that isn't there. Cells whose text really can run long ellipsise themselves. */
.m-table.m-fixed tbody td { overflow: hidden; }
/* min-width:0 is what lets the title shrink inside its flex row — without it
   a long title pushes the seniority qualifier out of the cell instead of
   ellipsising itself. */
.m-table.m-fixed td.m-name a { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.m-rowact { opacity: 0; display: flex; gap: 2px; transition: .11s; }
.m-cellrow { display: flex; align-items: center; gap: 8px; }
.m-num { font-variant-numeric: tabular-nums; }
/*
 * Centred columns.
 *
 * Everything that is a count, a state or a person's avatar sits centred under
 * a centred header; only the name, the client and the two dates stay ranged
 * left. The mix before this — some columns left, some right — put a two-digit
 * number hard against the column border with a header at the other end of the
 * same cell, and the eye had to re-find the values on every column.
 */
.m-table th.m-mid, .m-table td.m-mid { text-align: center; }
.m-table td.m-mid > .m-cellrow { justify-content: center; }
.m-table td.m-mid > .m-inline { display: inline-flex; align-items: center; gap: 4px; }

/*
 * Progress rail, from the makieta. It sits beside the counter it measures —
 * candidates sent on — on an absolute scale, so a full bar means the same
 * thing in every row. See candidateBarWidth in RecruitmentStageBoard.
 */
.m-bar {
  width: 38px; height: 5px; border-radius: 99px;
  background: var(--color-ink-200); overflow: hidden; flex: none;
}
.m-bar i { display: block; height: 100%; border-radius: 99px; background: var(--color-primary-500); }
/* Same bar at reading scale: a pool balance is the subject of its card, not a
   detail inside a table row. */
.m-bar-wide { width: 100%; height: 6px; }

/* Divider between a date and its time. Dimmed and thin: it separates two
   readings inside one value, it is not part of either. */
.m-sep { color: var(--ui-text-dimmed); opacity: .55; margin: 0 1px; }

/*
 * A stage group, rendered as its own list.
 *
 * The heading sits outside the card — stage name, count, and the way to add
 * one more — and the card below it holds nothing but records under their own
 * column header. Two lists in a row therefore read as two lists, which is what
 * grouping inside a single table never managed to say however much padding it
 * was given.
 */
.m-grphead {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 0 2px 8px;
  cursor: pointer;
  user-select: none;
}
.m-grphead:hover .m-grp-add { opacity: 1; }
.m-grp-add { margin-left: auto; opacity: 0; transition: .11s; }

/* Drop target while a recruitment is being dragged over this stage. */
.m-grpsec.is-drop .m-tablewrap {
  border-color: var(--color-primary-300);
  box-shadow: 0 0 0 3px var(--color-primary-50);
}

/*
 * Timeline — a candidate's history as a sequence rather than a table.
 *
 * One continuous line runs down the left through everything; day headings sit
 * on it as filled dots, individual events as ringed marks. The 14px column the
 * line occupies is the only thing holding the structure — no borders between
 * rows, so a burst of five moves in one afternoon reads as a cluster instead
 * of five identical bands.
 */
.m-tl { position: relative; padding: 6px 14px 14px; }
.m-tl::before {
  content: "";
  position: absolute;
  left: 25px; top: 14px; bottom: 18px;
  width: 1px;
  background: var(--ui-border-accented);
}

.m-tl-day {
  position: relative;
  display: flex; align-items: center; gap: 9px;
  padding: 12px 0 6px 0;
  font-size: 11px; font-weight: 600; letter-spacing: .05em; text-transform: uppercase;
  color: var(--ui-text-dimmed);
}
.m-tl-day:first-child { padding-top: 4px; }
.m-tl-daydot {
  width: 9px; height: 9px; margin-left: 7px; border-radius: 50%;
  background: var(--color-ink-400);
  box-shadow: 0 0 0 3px var(--ui-bg);
  flex: none;
}

.m-tl-item { position: relative; display: flex; gap: 9px; padding: 7px 0; }
.m-tl-mark {
  position: relative;
  width: 23px; height: 23px; margin-left: 0; border-radius: 50%;
  display: grid; place-items: center;
  flex: none;
  background: var(--ui-bg);
  color: var(--ui-text-dimmed);
  box-shadow: inset 0 0 0 1px var(--ui-border), 0 0 0 2px var(--ui-bg);
}
.m-tl-mark.is-stage { color: var(--color-primary-600); box-shadow: inset 0 0 0 1px var(--color-primary-200), 0 0 0 3px var(--ui-bg); background: var(--color-primary-50); }
.m-tl-mark.is-ai    { color: var(--st-magenta-fg); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--st-magenta-fg) 25%, transparent), 0 0 0 3px var(--ui-bg); background: var(--st-magenta-bg); }
.m-tl-mark.is-new   { color: var(--st-green-fg); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--st-green-fg) 25%, transparent), 0 0 0 3px var(--ui-bg); background: var(--st-green-bg); }

.m-tl-body { min-width: 0; padding-top: 2px; }
.m-tl-text { display: block; font-size: 13px; color: var(--ui-text); text-decoration: none; }
.m-tl-text b { font-weight: 550; color: var(--ui-text-highlighted); }
.m-tl-when { display: block; margin-top: 2px; font-size: 11.5px; color: var(--ui-text-dimmed); font-variant-numeric: tabular-nums; }

/* A sent mail's own text, folded under its timeline line. The body is the HTML the
   candidate received, so it keeps its paragraphs and links; the quoted slab and the
   dimmed toggle keep it reading as a quotation of the event, not as another event. */
.m-tl-fold {
  display: inline-flex; align-items: center; gap: 4px;
  margin-top: 4px;
  font-size: 11.5px; color: var(--ui-text-dimmed);
  cursor: pointer;
}
.m-tl-fold:hover { color: var(--ui-text); }
.m-tl-mail {
  margin-top: 5px; padding: 8px 11px;
  border-left: 2px solid var(--ui-border-accented);
  border-radius: 0 6px 6px 0;
  background: var(--ui-bg-muted);
  font-size: 12.5px; line-height: 1.5; color: var(--ui-text);
  overflow-wrap: anywhere;
}
.m-tl-mail p, .m-tl-mail ul, .m-tl-mail ol { margin: 0 0 .5em; }
.m-tl-mail :last-child { margin-bottom: 0; }
.m-tl-mail ul, .m-tl-mail ol { padding-left: 1.25rem; list-style: revert; }
.m-tl-mail a { color: var(--ui-primary); text-decoration: underline; }
.m-tl-mail img { max-width: 100%; height: auto; }

/* Solid 7px dot — a stage's colour on a data row, a client's colour in a tag.
   Always paired with the label it belongs to, never used alone. */
.m-rowdot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  flex: none;
}

/*
 * Advance-to-next-stage button. Unlike the rest of the row actions it is not
 * hidden until hover — a recruiter moving a stack of recruitments forward
 * should be able to see the control without hunting for it — but it stays
 * faint until the row is hovered so a hundred chevrons don't shout down the
 * column of data next to them.
 */
.m-rowadv { opacity: .32; transition: .12s; }
.m-table tbody tr:hover .m-rowadv { opacity: 1; }
.m-rowadv:disabled { opacity: .12; pointer-events: none; }
.m-table tbody tr:hover .m-rowadv:disabled { opacity: .22; }

/*
 * Recruitment table column widths.
 *
 * Every column but the title is fixed, and the title takes what is left —
 * which is where this went wrong: the mock-up's widths were drawn on a wide
 * screen and never re-checked on a laptop, so at 1280px they left the title
 * 88px. The one column anyone actually reads was the one squeezed out, and the
 * table felt like it ran off the right edge because in effect it did.
 *
 * Each width here is the widest its header needs (measured at 11px uppercase,
 * in the longer of the two locales) plus a little air — no more. An avatar
 * does not need 98px around it, and a two-digit count does not need 92px.
 * That is worth roughly a hundred pixels back for the title at every width.
 *
 * One set at all widths, on purpose. A breakpoint that widened these columns
 * on a big screen would make the title jump *narrower* as the window grew.
 */
.m-c-grip    { width: 26px; }
.m-c-client  { width: 100px; }
.m-c-owner   { width: 68px; }
.m-c-open    { width: 88px; }
.m-c-prio    { width: 104px; }
.m-c-cand    { width: 100px; }
/* Counters are named by the org, so no width fits them all — this holds a
   two-word name and lets the rest ellipsis under a header tooltip. The first
   counter also carries the progress rail, hence the room for number + bar. */
.m-c-counter { width: 100px; }
/* Holds "28.08 | 16:03" — day, month, divider, hour. This used to be 138px
   because it printed the year too; dropping four characters nobody read is
   what let the hour survive on a narrow screen. */
.m-c-dl      { width: 104px; }
/* Dashboard active-recruitments columns: one shared set of widths is what
   keeps the per-stage tables' columns on the same vertical lines. The name
   column is fixed rather than flexible — with few columns the slack all
   landed in it and pushed everything else to the far right; a trailing
   unsized filler column absorbs the slack instead, so the data hugs the
   left edge and the client/recruiter cells keep room to breathe. */
.m-c-recname { width: 320px; }
.m-c-dclient { width: 150px; }
.m-c-downer  { width: 130px; }
.m-c-stat    { width: 112px; }
.m-c-ai      { width: 40px; }
/* Sized by its header ("Utworzono"), not its value ("10.08"). */
.m-c-created { width: 84px; }
.m-c-act     { width: 72px; }

/* Deadline urgency — computed in the component, painted here. */
.m-dl-near { color: var(--st-amber-fg); font-weight: 600; }
.m-dl-past { color: var(--st-red-fg); font-weight: 600; }

/*
 * Toolbar band. Sits between the panel header and the content and matches its
 * 46px height, so the three columns share one horizontal line across the top
 * of the app instead of each starting at its own offset.
 */
.m-toolbar {
  height: var(--bar-h);
  flex: none;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 14px;
  background: var(--ui-bg);
  border-bottom: 1px solid var(--ui-border);
}

/* Search field — a filled well rather than a bordered input, so it reads as
   part of the toolbar rather than as a form control dropped onto it. */
.m-search {
  display: flex;
  align-items: center;
  gap: 7px;
  height: var(--control-h);
  padding: 0 10px;
  border-radius: var(--radius-btn);
  background: var(--color-ink-100);
  color: var(--ui-text-dimmed);
  font-size: 12.5px;
  transition: .13s;
}
.m-search:hover { background: var(--color-ink-200); }
.m-search:focus-within { background: var(--ui-bg); box-shadow: inset 0 0 0 1px var(--color-primary-400); }
.m-search input {
  flex: 1;
  min-width: 0;
  background: transparent;
  border: 0;
  outline: 0;
  font-size: 12.5px;
  color: var(--ui-text-highlighted);
}
.m-search input::placeholder { color: var(--ui-text-dimmed); }

/* Priority — the flag's colour carries the level; only the top level spells
   itself out, because that is the only one worth a word in a dense row. */
.m-prio { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 400; }
.m-prio-urgent { color: var(--st-red-fg); }
.m-prio-high   { color: var(--st-amber-fg); }
.m-prio-low    { color: var(--color-ink-500); }

/*
 * ---------------------------------------------------------------------------
 * Record view — header, layouts, cards
 * ---------------------------------------------------------------------------
 */

/* Record header. One band: title on the first line, the record's facts on the
   second as hoverable label/value pairs, actions pinned right. It used to be
   five stacked bands and the content started below the fold. */
.m-rechead {
  flex: none;
  background: var(--ui-bg);
  border-bottom: 1px solid var(--ui-border);
  padding: 14px 16px 13px;
}
.m-rechead h1 {
  font-size: 20px;
  font-weight: 680;
  letter-spacing: -.022em;
  color: var(--ui-text-highlighted);
  line-height: 1.25;
}
.m-props { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 10px; }
.m-prop {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 26px;
  padding: 0 9px 0 8px;
  border-radius: var(--radius-btn);
  font-size: 12px;
  color: var(--ui-text);
  transition: .11s;
}
.m-prop:hover { background: var(--wash-hover); }
.m-prop .k { color: var(--ui-text-dimmed); display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.m-prop .v { color: var(--ui-text-highlighted); font-weight: 400; white-space: nowrap; }

/* Section layouts. `.m-two` is the makieta's asymmetric split — the reading
   column is wider than the facts column, which is what keeps prose from
   running to unreadable line lengths on a 1600px screen. */
.m-two { display: grid; grid-template-columns: 1.45fr 1fr; gap: 12px; align-items: start; padding: 16px; }
.m-one { padding: 16px; }
.m-narrow { max-width: 900px; }
.m-stack { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
@media (max-width: 1100px) { .m-two { grid-template-columns: 1fr; } }

/* Card. A 40px header band, a hairline, then the body — so a stack of cards
   reads as a stack of titled things rather than as boxes of text. */
.m-cardbox {
  background: var(--ui-bg);
  border: 1px solid var(--ui-border);
  border-radius: var(--radius-card);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-width: 0;
}
.m-cardbox > header {
  height: 40px;
  flex: none;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 12px 0 14px;
  border-bottom: 1px solid var(--ui-border-muted);
}
/* Section heading. 550 rather than 650: a heading needs to be distinguishable
   from the rows under it, and at 13px the darker colour already does that —
   the extra weight was only making the page look shouty. */
.m-cardbox > header h3 { font-size: 13px; font-weight: 550; color: var(--ui-text-highlighted); }
.m-cardbox .m-body { padding: 14px; }
.m-cardbox .m-foot {
  padding: 10px 14px;
  font-size: 11.5px;
  color: var(--ui-text-dimmed);
  border-top: 1px solid var(--ui-border-muted);
}
/* AI provenance on a card: a hairline gradient border, not a filled bar. On a
   tall card a thick brand outline reads as an error state, and the point is
   provenance, not alarm. */
.m-aigrad {
  border: 1px solid transparent;
  background:
    linear-gradient(var(--ui-bg), var(--ui-bg)) padding-box,
    linear-gradient(140deg,
      color-mix(in srgb, var(--color-primary-600) 55%, #fff),
      color-mix(in srgb, var(--color-accent-500) 42%, #fff)) border-box;
}

/*
 * The AI tag's counterpart for everything a person put there.
 *
 * Only one of the two groups of documents used to be labelled, which made the
 * other one look like "the documents" and the AI panel like an aside bolted on
 * top. They are two sources of the same thing, so they are now stated the same
 * way — same tag, same card, blue for uploaded against violet for generated.
 */
.m-uptag {
  display: inline-flex; align-items: center; gap: 4px;
  height: 19px; padding: 0 7px; border-radius: var(--radius-tag);
  font-size: 10.5px; font-weight: 650; letter-spacing: .02em;
  color: var(--st-blue-fg);
  background: var(--st-blue-bg);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--st-blue-fg) 20%, transparent);
}
.m-upgrad {
  border: 1px solid color-mix(in srgb, var(--st-blue-fg) 26%, #fff);
}

/* Definition list — the facts column of a record. */
.m-kv { display: grid; grid-template-columns: auto 1fr; gap: 8px 16px; padding: 14px; }
.m-kv dt { font-size: 12px; color: var(--ui-text-dimmed); white-space: nowrap; }
.m-kv dd { font-size: 12.5px; color: var(--ui-text-highlighted); font-weight: 400; min-width: 0; }

/* File row. */
.m-docrow {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 14px;
  height: 52px;
  border-bottom: 1px solid var(--ui-border-muted);
}
.m-docrow:last-child { border-bottom: 0; }
.m-docrow:hover { background: var(--row-hover); }
.m-docrow .txt { min-width: 0; flex: 1; }
.m-docrow .txt b { display: block; font-size: 13px; font-weight: 400; color: var(--ui-text-highlighted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.m-docrow .txt span { display: block; font-size: 11.5px; color: var(--ui-text-dimmed); }
.m-docicon {
  width: 28px; height: 28px;
  border-radius: var(--radius-btn);
  background: var(--color-ink-100);
  display: grid; place-items: center;
  color: var(--ui-text-dimmed);
  flex: none;
}

/* Settings row — a labelled thing with a control on the right. */
.m-setrow {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--ui-border-muted);
}
.m-setrow:last-child { border-bottom: 0; }
.m-setrow .t { flex: 1; min-width: 0; }
.m-setrow .t b { display: block; font-size: 13px; font-weight: 400; color: var(--ui-text-highlighted); }
.m-setrow .t span { display: block; font-size: 11.5px; color: var(--ui-text-dimmed); margin-top: 1px; line-height: 1.45; }

/*
 * Settings canvas.
 *
 * The organization screens are read top to bottom rather than scanned like a
 * table, so the measure is capped: a form field stretched across a 1920px
 * window is unusable. The top gap is deliberately larger than the side gaps.
 * At an even 16px the first card sat right under the toolbar hairline and the
 * whole page read as if it had been pushed against the ceiling.
 */
.m-page {
  max-width: 1120px;
  margin: 0 auto;
  padding: 28px 18px 56px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
@media (max-width: 640px) { .m-page { padding: 20px 14px 40px; } }

/* Small caps label above a value, the same rhythm as a table header. */
.m-kicker {
  font-size: 11px; font-weight: 600; letter-spacing: .05em; text-transform: uppercase;
  color: var(--ui-text-dimmed);
}
/* Kicker on a one-row tile, where the label may be two stage names joined by a
   slash and the whole tile is 64px tall. */
.m-kicker-sm { font-size: 10px; letter-spacing: .03em; line-height: 1.2; }

/* One line of explanation under a section name, before the cards. */
.m-lead { font-size: 12.5px; line-height: 1.55; color: var(--ui-text-dimmed); max-width: 76ch; }

/* Group heading inside a card: what the rows under it are. */
.m-grouplabel {
  padding: 11px 14px 5px;
  font-size: 11px; font-weight: 600; letter-spacing: .05em; text-transform: uppercase;
  color: var(--ui-text-dimmed);
}

/* Waiting for data, and having none. Both are states of the same box, so they
   are the same shape: centred, quiet, never a full-height void. */
.m-loading {
  display: flex; align-items: center; gap: 8px;
  padding: 18px 2px; font-size: 12.5px; color: var(--ui-text-dimmed);
}
.m-empty {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 40px 20px; text-align: center;
  font-size: 12.5px; color: var(--ui-text-dimmed);
}
.m-empty p { max-width: 52ch; }

/* Pipeline stage row inside a card. */
.m-stagerow {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 8px 14px;
  border-bottom: 1px solid var(--ui-border-muted);
  font-size: 12.5px;
}
.m-stagerow:last-child { border-bottom: 0; }
.m-stagerow .nm { flex: 1; }

/* Long-form text inside a card. */
.m-prose { font-size: 13px; line-height: 1.62; color: var(--ui-text); }
.m-prose p + p { margin-top: 9px; }
.m-prose strong { color: var(--ui-text-highlighted); font-weight: 600; }
.m-prose ul { margin: 6px 0 0 17px; list-style: disc; }
.m-prose li { margin-bottom: 3px; }
/* AI-written notes arrive as HTML with their own <h2>/<h3>. At document scale
   those are 24px and 20px, which in a note row makes the machine's output
   shout over everything a human wrote next to it. Scoped to note/comment rows
   (two classes, so it outranks MarkdownContent's own heading rules) — a brief
   opened as a document keeps its document-scale headings. */
.m-cmt .m-prose .markdown-content :is(h1, h2, h3, h4),
.m-cmt .m-prose :is(h1, h2, h3, h4) {
  font-size: 13.5px;
  font-weight: 650;
  color: var(--ui-text-highlighted);
  margin: 12px 0 4px;
  font-style: normal;
}
.m-cmt .m-prose :is(h1, h2, h3, h4):first-child { margin-top: 0; }

/* Comment composer + comment rows. */
.m-composer { padding: 12px 14px; border-bottom: 1px solid var(--ui-border-muted); background: var(--row-hover); }
.m-cmt { display: flex; gap: 10px; padding: 12px 14px; border-bottom: 1px solid var(--ui-border-muted); }
.m-cmt:last-child { border-bottom: 0; }
.m-cmt .c { min-width: 0; flex: 1; }
.m-cmt .h { display: flex; align-items: center; gap: 8px; margin-bottom: 5px; }
.m-cmt .h b { font-size: 12.5px; font-weight: 550; color: var(--ui-text-highlighted); }
.m-cmt .h .when { margin-left: auto; font-size: 11.5px; color: var(--ui-text-dimmed); white-space: nowrap; }

/* Kanban.
 *
 * The board is itself the flex item and the scroll container. Wrapping it in a
 * scrolling div and giving it height:100% does not work: a percentage height
 * inside a flex item is not reliably definite, and the columns fall back to
 * shrink-wrapping their cards — a row of differently-sized boxes. As a flex
 * item with `flex: 1` it gets a real height, and `align-items: stretch` then
 * has something to stretch the columns to.
 */
.m-board {
  display: flex;
  gap: 12px;
  padding: 16px;
  align-items: stretch;
  flex: 1 1 0%;
  min-height: 0;
  overflow-x: auto;
}
.m-col {
  width: 262px; flex: none;
  background: var(--color-ink-100);
  border: 1px solid transparent;
  border-radius: var(--radius-card);
  padding: 8px;
  display: flex; flex-direction: column; gap: 8px;
  min-height: 0;
}
/* The column Matchtly fills on its own — every other column is somewhere a
   recruiter dragged a card. */
.m-col-ai {
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--color-primary-600) 7%, var(--color-ink-100)), var(--color-ink-100) 55%) padding-box,
    linear-gradient(160deg,
      color-mix(in srgb, var(--color-primary-600) 42%, #fff),
      color-mix(in srgb, var(--color-accent-500) 30%, #fff)) border-box;
}
/* Fixed header height pins every column title to the same baseline — sized by
   contents, a column of cards and an empty column sat at different heights and
   the row of headings sagged across the board. */
.m-colhead { height: 28px; flex: none; display: flex; align-items: center; gap: 8px; padding: 0 4px; }
.m-colhead .cnt { font-size: 11.5px; color: var(--ui-text-dimmed); font-variant-numeric: tabular-nums; }
.m-colhead .acts { margin-left: auto; display: flex; gap: 2px; opacity: 0; transition: .11s; }
.m-col:hover .acts { opacity: 1; }
/* The 2px of padding (cancelled by the margin) is room for a hovered card to
   lift into and for its ring to sit in. Without it the scroll container clipped
   the top card's raised edge, so hovering the first card in a column shaved a
   line off it. */
.m-colbody {
  display: flex; flex-direction: column; gap: 7px;
  overflow-y: auto; flex: 1; min-height: 36px;
  padding: 2px; margin: -2px;
}
/*
 * Candidate tile. Roomier than the mock-up's: at 9px of padding a column of
 * fifteen tiles ran together into one striped block, and the gap between two
 * cards was smaller than the gap between the two lines inside one. The extra
 * padding buys the separation that a border would otherwise have to.
 */
.m-card {
  background: var(--ui-bg);
  border-radius: var(--radius-card);
  padding: 12px 12px 11px;
  box-shadow: var(--sh-1);
  cursor: pointer;
  transition: .12s;
}
.m-card:hover { box-shadow: var(--sh-2); transform: translateY(-1px); }
.m-card .t { font-size: 13px; font-weight: 400; color: var(--ui-text-highlighted); line-height: 1.35; margin-bottom: 10px; }
.m-card .meta { display: flex; align-items: center; gap: 7px; font-size: 11.5px; color: var(--ui-text-dimmed); }

/*
 * The ones worth looking at. Every rating this candidate has is in the top
 * band (see useRating), so the tile carries a green wash and a green edge —
 * a recruiter scanning a full board should find them without reading a number.
 *
 * Deliberately faint: it marks a tile, it does not replace the ratings printed
 * on it, and a column of five highlighted cards should still look like a
 * column of cards.
 */
.m-card.is-strong {
  background: linear-gradient(150deg, color-mix(in srgb, var(--st-green-bg) 90%, #fff), var(--ui-bg) 72%);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--st-green-fg) 26%, transparent), var(--sh-1);
}
.m-card.is-strong:hover {
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--st-green-fg) 38%, transparent), var(--sh-2);
}

/* And the mirror image: every rating in the bottom band. Same weight of
   marking as the green one — this is a tile to skip, not an error. */
.m-card.is-weak {
  background: linear-gradient(150deg, color-mix(in srgb, var(--st-red-bg) 90%, #fff), var(--ui-bg) 72%);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--st-red-fg) 22%, transparent), var(--sh-1);
}
.m-card.is-weak:hover {
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--st-red-fg) 34%, transparent), var(--sh-2);
}

/*
 * Bulk selection on the board. The checkbox materialises on hover so forty
 * idle cards don't wear forty empty boxes; once anything is picked it stays
 * visible on the picked cards, which are also ringed — a recruiter scrolling
 * a long column has to see what is in the batch without hovering each tile.
 */
.m-card { position: relative; }
.m-card .m-pick {
  position: absolute; top: 9px; right: 9px;
  width: 15px; height: 15px; margin: 0;
  accent-color: var(--color-primary-600);
  opacity: 0; transition: opacity .12s;
  cursor: pointer;
}
.m-card:hover .m-pick, .m-card.is-picked .m-pick { opacity: 1; }
.m-card.is-picked {
  box-shadow: inset 0 0 0 1.5px var(--color-primary-400), var(--sh-1);
}
.m-card.is-picked:hover {
  box-shadow: inset 0 0 0 1.5px var(--color-primary-400), var(--sh-2);
}
/* Keep a long name from running under the hover checkbox. */
.m-card .t { padding-right: 20px; }

/* Whole-column checkbox in the column header — same reveal rule as the card
   ones: shows when the column is hovered, stays while anything in it is
   picked. */
.m-colhead .m-pickall {
  margin-left: auto; flex: none;
  width: 15px; height: 15px;
  accent-color: var(--color-primary-600);
  opacity: 0; transition: opacity .12s;
  cursor: pointer;
}
.m-col:hover .m-pickall, .m-colhead .m-pickall.is-on { opacity: 1; }

/* The action bar that slides in over the column titles once something is
   picked. Same visual language as a toolbar band: one row, buttons at the
   right end, the count at the left. Sticky against the tab's scroll box —
   the cards worth rejecting are usually at the bottom of a long column, and
   the bar has to still be there when the recruiter arrives at them. Opaque
   background (no color-mix with a translucent tone) so cards sliding
   underneath never show through. */
.m-bulkbar {
  position: sticky; top: 8px; z-index: 30;
  display: flex; align-items: center; gap: 8px;
  padding: 7px 10px;
  border-radius: var(--radius-card);
  border: 1px solid color-mix(in srgb, var(--color-primary-400) 45%, transparent);
  background: color-mix(in srgb, var(--color-primary-50) 60%, var(--ui-bg));
  box-shadow: var(--sh-2);
}
.m-bulkbar .cnt { font-size: 12.5px; font-weight: 550; color: var(--ui-text-highlighted); }
.m-bulkslide-enter-active, .m-bulkslide-leave-active { transition: opacity .14s, transform .14s; }
.m-bulkslide-enter-from, .m-bulkslide-leave-to { opacity: 0; transform: translateY(-6px); }

.m-ghost {
  display: flex; align-items: center; gap: 6px;
  height: 28px; padding: 0 8px;
  border-radius: var(--radius-btn);
  font-size: 12.5px; color: var(--ui-text-dimmed);
  transition: .11s; flex: none; cursor: pointer;
}
.m-ghost:hover { background: var(--wash-hover); color: var(--ui-text); }

/* Rating pair — the two AI scores, side by side above everything else on a
   candidate. A number this important gets to be 28px; the track underneath
   turns "78" into "78 out of 100" without a second line of text. */
.m-ratings { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
/*
 * Score tile. The wash is the colour of the score it carries, not the brand
 * gradient it used to wear — a 73 and a 34 looked identical until you read the
 * number, which is the one thing a tile like this is supposed to save you from.
 * The AI tag still marks provenance; the colour now says how it went.
 */
.m-rate { padding: 12px 14px; }
.m-rate-green  { background: linear-gradient(150deg, color-mix(in srgb, var(--st-green-bg) 92%, #fff), var(--ui-bg) 70%); border-color: color-mix(in srgb, var(--st-green-fg) 24%, transparent); }
.m-rate-blue   { background: linear-gradient(150deg, color-mix(in srgb, var(--st-blue-bg) 92%, #fff), var(--ui-bg) 70%); border-color: color-mix(in srgb, var(--st-blue-fg) 24%, transparent); }
.m-rate-amber  { background: linear-gradient(150deg, color-mix(in srgb, var(--st-amber-bg) 92%, #fff), var(--ui-bg) 70%); border-color: color-mix(in srgb, var(--st-amber-fg) 24%, transparent); }
.m-rate-red    { background: linear-gradient(150deg, color-mix(in srgb, var(--st-red-bg) 92%, #fff), var(--ui-bg) 70%); border-color: color-mix(in srgb, var(--st-red-fg) 24%, transparent); }
.m-rate .k {
  font-size: 11.5px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .04em; color: var(--ui-text-dimmed);
}
.m-rate .v { display: flex; align-items: baseline; gap: 6px; margin-top: 5px; }
.m-rate .v b {
  font-size: 28px; font-weight: 700; letter-spacing: -.03em;
  font-variant-numeric: tabular-nums; line-height: 1;
}
.m-rate .v span { font-size: 12px; color: var(--ui-text-dimmed); }
.m-rate .track {
  height: 6px; border-radius: 99px; background: var(--color-ink-200);
  margin-top: 9px; overflow: hidden;
}
.m-rate .track i { display: block; height: 100%; border-radius: 99px; }
/*
 * A tile that leads somewhere. Every score on this page was worked out from a
 * document or written up in a summary, and the tile is where the reader is
 * already looking — so it is the shortest route to the reasoning. It only
 * looks pressable when it actually leads somewhere: a tile whose score has no
 * write-up behind it stays a plain tile.
 */
.m-rate.is-link {
  display: block; width: 100%; text-align: left; cursor: pointer;
  transition: box-shadow .12s ease, transform .12s ease;
}
.m-rate.is-link:hover { box-shadow: var(--sh-2); transform: translateY(-1px); }
.m-rate.is-link:focus-visible { outline: 2px solid var(--color-primary-500); outline-offset: 2px; }
.m-rate .go {
  font-size: 11px; color: var(--ui-text-dimmed);
  display: inline-flex; align-items: center; gap: 3px;
  opacity: 0; transition: opacity .12s ease;
}
.m-rate.is-link:hover .go, .m-rate.is-link:focus-visible .go { opacity: 1; }
@media (max-width: 640px) { .m-ratings { grid-template-columns: 1fr; } }

/*
 * Landing mark. When a click sends the reader further down the same page
 * rather than to a new one, nothing moves except the scroll position — and a
 * scroll that lands mid-column is easy to mistake for having gone nowhere.
 * The card it landed on says so for a moment, then stops.
 */
@keyframes m-land {
  0%   { box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary-500) 38%, transparent); }
  100% { box-shadow: 0 0 0 3px transparent; }
}
.m-land { animation: m-land 1.4s ease-out; }

/*
 * The CV, embedded in the overview. Tall enough to read a page of it without
 * leaving, and no taller — the column below it still has to be reachable. The
 * reader (with its toolbar and full height) is one click away in the header.
 */
.m-cvbox {
  height: 560px;
  background: var(--color-ink-100);
  border-bottom-left-radius: var(--radius-card);
  border-bottom-right-radius: var(--radius-card);
  overflow: hidden;
}
.m-cvbox > * { height: 100%; }
/* The same CV card inside the candidates preview panel: no frame of its own
   (the panel already draws one) and the document takes the height the profile
   above it leaves, rather than a fixed 560px inside a scrolling column. */
.m-cardbox.is-flush { border: 0; border-radius: 0; }
.m-cardbox.is-fill { min-height: 0; flex: 1 1 0%; }
.m-cardbox.is-fill .m-cvbox { height: auto; min-height: 0; flex: 1 1 0%; border-radius: 0; }

/* Numbered list — AI-generated interview questions. */
.m-qlist { display: flex; flex-direction: column; }
.m-q {
  display: flex; gap: 10px;
  padding: 11px 14px;
  border-bottom: 1px solid var(--ui-border-muted);
  font-size: 13px; line-height: 1.5; color: var(--ui-text);
}
.m-q:last-child { border-bottom: 0; }
.m-q .n {
  width: 18px; flex: none; padding-top: 2px;
  font-size: 11px; font-weight: 700;
  color: var(--color-primary-600);
  font-variant-numeric: tabular-nums;
}

/* Note row. */
.m-note { padding: 12px 14px; border-bottom: 1px solid var(--ui-border-muted); }
.m-note:last-child { border-bottom: 0; }
.m-note .h { display: flex; align-items: center; gap: 8px; margin-bottom: 5px; }
.m-note .h b { font-size: 12.5px; font-weight: 550; color: var(--ui-text-highlighted); }
.m-note .h .when { margin-left: auto; font-size: 11.5px; color: var(--ui-text-dimmed); white-space: nowrap; }
.m-note p { font-size: 12.5px; line-height: 1.55; color: var(--ui-text); }

/* Score chip — a rating with its own colour band. */
.m-score {
  display: inline-flex; align-items: center; gap: 4px;
  height: 19px; padding: 0 6px;
  border-radius: var(--radius-tag);
  font-size: 11px; font-weight: 650;
  font-variant-numeric: tabular-nums;
}

/*
 * Document stage — the grey field a page sits on.
 *
 * A PDF handed straight to an <iframe> fills the box edge to edge and the
 * browser paints its own background behind it, so the document has no
 * boundary: it stops being a sheet of paper and becomes the window. The stage
 * gives it one, and `toolbar=0` on the viewer URL keeps the browser's own
 * controls out so the toolbar above is the only one.
 */
.m-docstage {
  background: var(--color-ink-100);
  padding: 16px;
  display: flex;
  justify-content: center;
  min-height: 0;
  flex: 1 1 0%;
}
/* No card of our own around the frame: the PDF viewer already paints the sheet
   and its own edge, and wrapping that in a second rounded, shadowed box reads
   as two frames around one document. */
.m-docstage > * {
  width: 100%;
  max-width: 900px;
}

/*
 * Side panel beside a list — the candidates preview.
 *
 * It has to read as a second surface, not as one more card in the same column:
 * on a page of white boxes a 1px border and a hairline shadow disappeared. So it
 * gets the lifted shadow, a slightly cooler edge, and a brand-tinted header band
 * naming whose panel it is. The tint is a wash of the primary at 6%, the same
 * device the AI column on the kanban uses.
 */
.m-sidepanel {
  background: var(--ui-bg);
  border-radius: var(--radius-card);
  box-shadow: var(--sh-3);
  border: 1px solid var(--ui-border);
  overflow: hidden;
}
/*
 * The panel's head is a name over a job title, not a row of controls, so it
 * takes the room a heading needs instead of the 46px a toolbar gets. Height goes
 * auto and the padding is stated: at the toolbar's own height the name sat
 * against the top edge of the card.
 */
.m-sidepanel > .m-toolbar {
  height: auto;
  min-height: var(--bar-h);
  padding: 14px 14px 12px;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--color-primary-600) 6%, var(--ui-bg)),
    var(--ui-bg) 92%);
  border-bottom-color: var(--ui-border);
}

/* Drop zone. */
.m-drop {
  border: 1px dashed var(--color-ink-400);
  border-radius: var(--radius-card);
  padding: 22px;
  text-align: center;
  font-size: 12.5px;
  color: var(--ui-text-dimmed);
  background: var(--ui-bg);
  transition: .12s;
}
.m-drop:hover { border-color: var(--color-primary-400); color: var(--ui-text); }

/*
 * The brand gradient means "this came from AI" and nothing else. It is the one
 * visual device the product owns, so spending it on ordinary primary buttons
 * spends the signal. Alias it under a name that says so; --gradient-brand stays
 * for the marketing surfaces (hero, landing) where it is decoration.
 */
:root {
  --gradient-ai: var(--gradient-brand);
}

/* Utility — apply the brand gradient as a background.
   `!important` so the gradient wins over Nuxt UI's solid-variant
   `background-color` utility (same specificity, source-order tied). */
.bg-gradient-brand { background: var(--gradient-brand) !important; }
.bg-gradient-hero  { background: var(--gradient-hero); }
.bg-gradient-soft  { background: var(--gradient-soft); }

/*
 * Utility — surface that Matchtly filled by itself.
 *
 * A hairline gradient border rather than the 2px ring of
 * .border-gradient-brand: on a tall kanban column a thick brand outline reads
 * as an error state, and the point here is provenance, not alarm. Two
 * backgrounds — one clipped to the padding box, one to the border box — put a
 * gradient in the border while leaving the interior a flat tint, which
 * border-image cannot do without discarding the radius.
 */
.surface-ai {
  border: 1px solid transparent;
  background:
    linear-gradient(color-mix(in srgb, var(--color-primary-500) 5%, var(--ui-bg)),
                    color-mix(in srgb, var(--color-accent-500) 4%, var(--ui-bg))) padding-box,
    linear-gradient(155deg,
                    color-mix(in srgb, var(--color-primary-500) 55%, transparent),
                    color-mix(in srgb, var(--color-accent-500) 45%, transparent)) border-box;
}

/* Utility — gradient text */
.text-gradient-brand {
  background: var(--gradient-brand);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* Utility — gradient border with a truly transparent interior that still
   respects ``border-radius``. ``border-image`` would ignore the radius,
   so we paint a brand-gradient overlay on a ``::before`` pseudo and mask
   out the inside via the standard "outer minus content-box" composite
   trick. The element's own background stays untouched. */
.border-gradient-brand {
  position: relative;
  isolation: isolate;
}
.border-gradient-brand::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 2px;
  background: var(--gradient-brand);
  -webkit-mask:
    linear-gradient(#000, #000) content-box,
    linear-gradient(#000, #000);
  -webkit-mask-composite: xor;
  mask:
    linear-gradient(#000, #000) content-box,
    linear-gradient(#000, #000);
  mask-composite: exclude;
  pointer-events: none;
}

/* Utility — violet gradient underline that hugs the text width.
   Use on an inline / inline-block element so the underline matches the
   text. */
.gradient-underline-brand {
  background-image: var(--gradient-brand);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 100% 2px;
  padding-bottom: 3px;
}

/*
 * ---------------------------------------------------------------------------
 * Management report
 * ---------------------------------------------------------------------------
 * The report is read, not operated: one screen someone scans before a meeting.
 * So the tiles are quieter than the rest of the application and the hierarchy
 * is carried by size alone — a figure at 30px, a section title at 13px, a
 * label at 11px — rather than by colour.
 */

/*
 * Which way a figure moved against the period before it: green when the trend
 * is the good one, red when it is not.
 *
 * A wash and a tinted border, nothing else. It used to be a wash plus a
 * coloured figure plus a coloured bar along the top edge, which put three
 * statements of the same colour on one tile. The bar is gone from every tile
 * for the same reason: a row of them, each with a violet stripe, read as
 * decoration before it read as data.
 */
.m-kpi-good {
  background: linear-gradient(150deg,
    color-mix(in srgb, var(--st-green-bg) 92%, var(--st-green-fg)),
    color-mix(in srgb, var(--st-green-bg) 32%, var(--ui-bg)) 76%);
  border-color: color-mix(in srgb, var(--st-green-fg) 34%, var(--ui-border));
}
.m-kpi-bad {
  background: linear-gradient(150deg,
    color-mix(in srgb, var(--st-red-bg) 92%, var(--st-red-fg)),
    color-mix(in srgb, var(--st-red-bg) 32%, var(--ui-bg)) 76%);
  border-color: color-mix(in srgb, var(--st-red-fg) 30%, var(--ui-border));
}

/* Change against the previous period. A pill, not coloured digits: a red
   number sitting beside a black one reads as a second value. */
.m-delta {
  display: inline-flex; align-items: center; gap: 3px;
  height: 19px; padding: 0 7px; border-radius: var(--radius-tag);
  font-size: 11px; font-weight: 650; font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.m-delta-up { background: var(--st-green-bg); color: var(--st-green-fg); }
.m-delta-down { background: var(--st-red-bg); color: var(--st-red-fg); }
/* One-row tiles: the pill has to sit beside a 21px figure without becoming
   the tallest thing on the tile. */
.m-delta-sm { height: 17px; padding: 0 5px; font-size: 10px; gap: 2px; }

/* Loading placeholder — a shape where the figure will be, so the tile does not
   change height when the data lands. */
.m-skel {
  border-radius: var(--radius-btn);
  background: linear-gradient(90deg, var(--color-ink-100), var(--color-ink-200), var(--color-ink-100));
  background-size: 200% 100%;
  animation: m-skel 1.3s ease-in-out infinite;
}
@keyframes m-skel { 0% { background-position: 100% 0; } 100% { background-position: -100% 0; } }

/* Second line of a tile header (which pipeline a funnel is showing). */
.m-tilesub {
  display: flex; align-items: center; gap: 6px;
  flex: none; padding: 8px 14px 0;
  font-size: 11.5px; color: var(--ui-text-dimmed);
}

/* Series key in a chart tile's header. */
.m-legend {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11px; color: var(--ui-text-dimmed); white-space: nowrap;
}
.m-legend i { width: 8px; height: 8px; border-radius: 2px; flex: none; }

/*
 * Funnel, in HTML.
 *
 * Two columns per stage: the silhouette on the left, the words on the right.
 * echarts drew the shape but wrote the labels inside it, where at nine stages
 * they overlapped; plain bars read cleanly but stopped looking like a funnel.
 * Splitting the two keeps the shape scannable and the text legible.
 *
 * Rows are flex children of a fixed-height tile, so the funnel always fills
 * the tile rather than leaving a gap under itself.
 */
/*
 * The funnel's conversions, above the shape.
 *
 * Three cards rather than three cells of a table: this is the headline of the
 * tile, and a ruled grid read as a footnote to the shape below it. Each sits
 * on a wash of the brand with the figure in the brand's own colour, so the
 * strip states itself without competing with the funnel's ramp underneath.
 */
.m-fconv {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px; flex: none; padding: 12px 14px 4px;
}
.m-fconv > div {
  min-width: 0; padding: 9px 11px 10px;
  border-radius: var(--radius-card);
  background: linear-gradient(155deg,
    color-mix(in srgb, var(--ui-primary) 9%, var(--ui-bg)),
    color-mix(in srgb, var(--ui-primary) 3%, var(--ui-bg)));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ui-primary) 16%, transparent);
}
.m-fconv b {
  display: flex; align-items: center; gap: 7px;
  font-size: 22px; font-weight: 700; line-height: 1.05;
  letter-spacing: -.03em; font-variant-numeric: tabular-nums;
  color: var(--ui-primary);
}
/* The trend pill sits on the figure's baseline, in its own weight. */
.m-fconv b .m-delta { font-style: normal; letter-spacing: 0; }
.m-fconv span {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; margin-top: 4px;
  font-size: 10.5px; line-height: 1.3; color: var(--ui-text-dimmed);
}
.m-fconv span .iconify { display: inline-block; vertical-align: -1px; }

.m-funnel {
  display: flex; flex-direction: column; gap: 3px;
  flex: 1; min-height: 0; padding: 12px 14px;
}
.m-frow {
  display: grid; grid-template-columns: minmax(56px, 38%) minmax(0, 1fr);
  gap: 12px; align-items: stretch;
  flex: 1 1 0; min-height: 22px;
}
/* The trapezoid. Clipped rather than drawn, so one element carries both the
   colour and the taper. */
.m-fshape { position: relative; }
.m-fshape i { position: absolute; inset: 0; display: block; }
.m-flabel { display: flex; align-items: center; gap: 8px; min-width: 0; }
.m-flabel b { font-size: 12.5px; font-weight: 500; color: var(--ui-text-highlighted); min-width: 0; }
.m-flabel .n {
  margin-left: auto; font-size: 13px; font-weight: 650;
  font-variant-numeric: tabular-nums; color: var(--ui-text-highlighted);
}
.m-flabel .p {
  width: 42px; text-align: right; flex: none;
  font-size: 11.5px; color: var(--ui-text-dimmed); font-variant-numeric: tabular-nums;
}

/* Outcomes that sit beside the funnel rather than inside it. Separated by a
   rule, because the point is that they are not steps. */
.m-foutside {
  flex: none; margin-top: 10px; padding-top: 9px;
  border-top: 1px solid var(--ui-border-muted);
}
.m-fout { display: flex; align-items: center; gap: 8px; height: 24px; }
.m-fout i { width: 9px; height: 9px; border-radius: 3px; flex: none; }
.m-fout b { font-size: 12.5px; font-weight: 500; color: var(--ui-text-highlighted); min-width: 0; }
.m-fout .n {
  margin-left: auto; font-size: 13px; font-weight: 650;
  font-variant-numeric: tabular-nums; color: var(--ui-text-highlighted);
}
.m-fout .p {
  width: 42px; text-align: right; flex: none;
  font-size: 11.5px; color: var(--ui-text-dimmed); font-variant-numeric: tabular-nums;
}

/* Header row that lets long column names wrap over two lines instead of
   widening the column. For tables whose headers are user-authored (stage
   names), where a single line cannot be budgeted for. */
.m-table.m-thwrap thead th {
  height: 42px;
  white-space: normal;
  line-height: 1.15;
  vertical-align: middle;
}

/* The period every figure on the page is scoped to, stated once in the toolbar. */
.m-range {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12.5px; font-weight: 500; color: var(--ui-text-highlighted);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
/* Native date input, sized like a toolbar control. */
.m-dateinput {
  height: var(--control-h); padding: 0 8px;
  border-radius: var(--radius-btn);
  background: var(--color-ink-100);
  font-size: 12.5px; color: var(--ui-text-highlighted);
  font-variant-numeric: tabular-nums;
  border: 0; outline: 0;
}
.m-dateinput:focus { background: var(--ui-bg); box-shadow: inset 0 0 0 1px var(--color-primary-400); }

/*
 * Pointer cursor on interactive elements. Tailwind v4 preflight no longer
 * sets `cursor: pointer` on <button> by default, and Nuxt UI buttons rely on
 * a class set in app.config.ts — this rule covers raw <button>/role="button"
 * elements that bypass the design system.
 */
button:not(:disabled),
[role="button"]:not([aria-disabled="true"]) {
  cursor: pointer;
}

/*
 * Guided tour (driver.js) — brand the popover so it looks at home in the app.
 * driver.js applies our class on `popoverClass`; we restyle the card, title,
 * primary buttons (gradient), and close button.
 */
.matchtly-tour-popover {
  border-radius: var(--radius-card, 16px) !important;
  box-shadow: 0 20px 40px -10px rgb(0 0 0 / 0.25), 0 8px 16px -4px rgb(0 0 0 / 0.1) !important;
  border: 1px solid var(--ui-border, #e4e4e7) !important;
}
.matchtly-tour-popover .driver-popover-title {
  font-weight: 700;
  font-size: 1rem;
  color: var(--ui-text, #111827);
}
/* Eyebrow line above each step's title — "🎓 Samouczek" / "🎓 Tutorial".
   Smaller and lighter than the title so it reads as a section label. */
.matchtly-tour-popover .matchtly-tour-eyebrow {
  display: block;
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--ui-text-muted, #6b7280);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 2px;
}
.matchtly-tour-popover .matchtly-tour-title-text {
  display: block;
}
.matchtly-tour-popover .driver-popover-description {
  color: var(--ui-text-muted, #4b5563);
  line-height: 1.45;
}
.matchtly-tour-popover .driver-popover-next-btn,
.matchtly-tour-popover .driver-popover-done-btn {
  background: var(--gradient-brand) !important;
  border: 0 !important;
  color: #fff !important;
  text-shadow: none !important;
  font-weight: 600;
  padding: 6px 14px;
  border-radius: 8px;
}
.matchtly-tour-popover .driver-popover-prev-btn {
  background: transparent !important;
  color: var(--ui-text-muted, #4b5563) !important;
  border: 1px solid var(--ui-border, #e4e4e7) !important;
  border-radius: 8px;
}
.matchtly-tour-popover .driver-popover-close-btn {
  color: var(--ui-text-muted, #4b5563) !important;
}
.driver-active-element {
  border-radius: 8px !important;
  /*
   * Block clicks on the highlighted element. The user should be able to
   * advance only through the popover's "Dalej" / "Wstecz" / close buttons —
   * clicking the highlighted button itself would otherwise navigate them
   * away from the step the tour is trying to teach.
   */
  pointer-events: none !important;
}

/*
 * Hard click-lock while the tour is on screen: disable pointer events on
 * every element under <body>, then explicitly re-enable the driver.js popover
 * and overlay. The overlay catches clicks too — paired with
 * overlayClickBehavior: 'noop' it just absorbs them. Net effect: only Wstecz,
 * Dalej and the close (X) button respond to clicks during a tour.
 */
body.matchtly-tour-active * {
  pointer-events: none !important;
}
body.matchtly-tour-active .driver-popover,
body.matchtly-tour-active .driver-popover *,
body.matchtly-tour-active .driver-overlay,
body.matchtly-tour-active .driver-overlay * {
  pointer-events: auto !important;
}

/*
 * ---------------------------------------------------------------------------
 * Dashboard tiles
 * ---------------------------------------------------------------------------
 * Two shapes the dashboard needs and nothing else does yet: a stat card whose
 * subject is one large number, and a queue card whose subject is one count and
 * where it leads. Both are fixed geometry for the same reason as the rest of
 * the makieta primitives — a row of five of them has to line up exactly.
 */

/* Stat card — kicker, number, optional breakdown, one line of context. */
.m-stat {
  background: var(--ui-bg);
  border: 1px solid var(--ui-border);
  border-radius: var(--radius-card);
  padding: 13px 15px 12px;
  box-shadow: var(--sh-1);
  min-width: 0;
}
/* The one figure with money behind it. Deliberately singular: a row of
   gradients is wallpaper, one gradient is a heading. */
.m-stat.is-brand {
  background: var(--gradient-hero);
  border-color: transparent;
  color: #fff;
  box-shadow: var(--sh-2);
}
.m-stat-head { display: flex; align-items: center; gap: 8px; }
.m-stat-head .m-kicker { flex: 1 1 auto; min-width: 0; }
.m-stat.is-brand .m-stat-head .m-kicker { color: rgb(255 255 255 / .72); }

.m-stat-ico {
  display: grid; place-items: center;
  width: 28px; height: 28px; border-radius: 8px; flex: none;
  background: var(--st-neutral-bg); color: var(--st-neutral-fg);
}
.m-stat-ico.is-blue { background: var(--st-blue-bg); color: var(--st-blue-fg); }
.m-stat-ico.is-teal { background: var(--st-teal-bg); color: var(--st-teal-fg); }
.m-stat.is-brand .m-stat-ico { background: rgb(255 255 255 / .16); color: #fff; }

.m-stat-num {
  margin-top: 6px;
  font-size: 34px; line-height: 1.05; font-weight: 600; letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
  color: var(--ui-text-highlighted);
}
.m-stat.is-brand .m-stat-num { color: #fff; }

/* The number broken into its parts, one row of small labelled counts. */
.m-stat-split { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 6px 18px; }
.m-stat-cell { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
.m-stat-cell b {
  font-size: 15px; font-weight: 600; font-variant-numeric: tabular-nums;
  color: var(--ui-text-highlighted);
}
.m-stat-cell span {
  font-size: 11px; color: var(--ui-text-dimmed);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.m-stat-split.is-quiet .m-stat-cell b { font-size: 14px; color: rgb(255 255 255 / .92); }
.m-stat-split.is-quiet .m-stat-cell span { color: rgb(255 255 255 / .6); }

.m-stat-foot { margin-top: 8px; font-size: 11.5px; color: var(--ui-text-dimmed); }
.m-stat.is-brand .m-stat-foot { color: rgb(255 255 255 / .74); }

/* Change against the previous period, on the gradient tile. The status pills
   would fight the violet, so this is the tile's own translucent white. */
.m-delta {
  display: inline-flex; align-items: center; gap: 4px;
  height: 20px; padding: 0 8px; border-radius: var(--radius-btn);
  font-size: 11.5px; font-weight: 600;
  background: rgb(255 255 255 / .16); color: #fff;
}
.m-delta.is-down { background: color-mix(in srgb, var(--st-red-fg) 55%, transparent); }

/*
 * Queue card. The count is the subject, the label sits beside it rather than
 * under it (a number alone reads as decoration), and the whole card is the link
 * to wherever that queue is worked off.
 */
.m-todo {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-rows: auto auto;
  align-items: center;
  gap: 0 10px;
  padding: 10px 12px;
  text-align: left;
  background: var(--ui-bg);
  border: 1px solid var(--ui-border);
  border-radius: var(--radius-card);
  transition: .12s;
  cursor: pointer;
}
.m-todo:hover { border-color: var(--color-ink-400); box-shadow: var(--sh-2); }
.m-todo-ico {
  grid-row: 1 / span 2;
  display: grid; place-items: center;
  width: 32px; height: 32px; border-radius: 9px;
}
.m-todo-top { display: flex; align-items: baseline; gap: 6px; min-width: 0; }
.m-todo-num {
  font-size: 19px; font-weight: 600; line-height: 1.15;
  font-variant-numeric: tabular-nums;
  color: var(--ui-text-highlighted);
}
.m-todo-lab {
  min-width: 0;
  font-size: 12.5px; font-weight: 550;
  color: var(--ui-text-highlighted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.m-todo-sub { font-size: 11.5px; color: var(--ui-text-dimmed); }
.m-todo-go {
  position: absolute; right: 10px; top: 12px;
  color: var(--ui-text-dimmed); opacity: 0; transition: .12s;
}
.m-todo:hover .m-todo-go { opacity: 1; }

.m-todo.is-amber   .m-todo-ico { background: var(--st-amber-bg);   color: var(--st-amber-fg); }
.m-todo.is-magenta .m-todo-ico { background: var(--st-magenta-bg); color: var(--st-magenta-fg); }
.m-todo.is-purple  .m-todo-ico { background: var(--st-purple-bg);  color: var(--st-purple-fg); }
.m-todo.is-blue    .m-todo-ico { background: var(--st-blue-bg);    color: var(--st-blue-fg); }
.m-todo.is-red     .m-todo-ico { background: var(--st-red-bg);     color: var(--st-red-fg); }

/* Sortable column header. A table header that is also a control still has to
   read as a header, so it borrows the header's own type and only gains the
   arrow and a hover. */
.m-sortbtn {
  display: inline-flex; align-items: center; gap: 4px;
  font: inherit; color: inherit; letter-spacing: inherit; text-transform: inherit;
  cursor: pointer;
}
.m-sortbtn:hover { color: var(--ui-text); }

/* The in-process breakdown: one proportional bar, then a wrapping legend.
   Fixed-height however many stages the org has and however narrow the tile —
   which the row of labelled counts it replaces was not. */
.m-segbar {
  margin-top: 12px;
  display: flex;
  height: 7px;
  border-radius: 99px;
  overflow: hidden;
  background: var(--color-ink-100);
}
.m-segbar i { display: block; height: 100%; flex: none; }
.m-legend { margin-top: 8px; display: flex; flex-wrap: wrap; gap: 4px 14px; }
.m-leg {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11px; color: var(--ui-text-dimmed);
  min-width: 0; white-space: nowrap;
}
.m-leg b {
  font-size: 12px; font-weight: 600;
  color: var(--ui-text-highlighted);
  font-variant-numeric: tabular-nums;
}
.m-leg .m-rowdot { width: 6px; height: 6px; }

/* --- klasy z komponentów Vue (AppContextPanel), potrzebne w demie --- */
.m-plabel {
  display: flex; align-items: center; gap: 6px;
  padding: 12px 8px 5px;
  font-size: 11px; font-weight: 600; letter-spacing: .05em; text-transform: uppercase;
  color: var(--ui-text-dimmed);
}
.m-pitem {
  display: flex; align-items: center; gap: 9px; width: 100%;
  min-height: 30px; padding: 4px 8px; border-radius: var(--radius-btn);
  color: var(--ui-text); font-size: 13px; text-align: left; text-decoration: none;
  transition: .11s; cursor: pointer; border: none; background: transparent; font-family: inherit;
}
.m-pitem:hover { background: var(--wash-hover); color: var(--ui-text-highlighted); }
.m-pitem.is-active { background: var(--color-primary-50); color: var(--color-primary-700); font-weight: 550; }
.m-pitem.is-ai { color: var(--color-primary-700); }
.m-pitem.is-ai:hover { background: color-mix(in srgb, var(--color-primary-600) 7%, transparent); }
.m-pcount { margin-left: auto; font-size: 11px; color: var(--ui-text-dimmed); font-variant-numeric: tabular-nums; }
.m-pitem.is-active .m-pcount { color: var(--color-primary-600); }

/* --- reset odpowiadający preflightowi Tailwinda, którego demo nie ładuje --- */
* { box-sizing: border-box; }
button, input, select, textarea {
  font: inherit; color: inherit; background-color: transparent; border: 0; margin: 0; padding: 0;
}
button { cursor: pointer; }
table { border-collapse: collapse; }
h1, h2, h3, h4, p, ul, ol, dl, dd, figure { margin: 0; }
ul, ol { list-style: none; padding: 0; }
img, svg, video { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }

html, body { margin: 0; padding: 0; height: 100%; }
body { font-family: var(--font-sans); color: var(--ui-text); overflow: hidden; }
.demo-shell { display: flex; height: 100%; }
.m-rail { width: 56px; flex: none; display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 8px 0; color: #fff; }
.m-rail img { width: 32px; height: 32px; border-radius: 10px; margin-bottom: 10px; }
.m-canvas { flex: 1; min-width: 0; display: flex; border-top-left-radius: var(--radius-panel); border-bottom-left-radius: var(--radius-panel); }
.demo-panel { width: 236px; flex: none; display: flex; flex-direction: column; border-right: 1px solid var(--ui-border); background: var(--ui-bg); border-top-left-radius: var(--radius-panel); }
.demo-panel-head {
  height: var(--bar-h); flex: none; display: flex; align-items: center; gap: 8px;
  padding: 0 8px 0 12px; border-bottom: 1px solid var(--ui-border-muted);
  font-size: 14px; font-weight: 600; letter-spacing: -0.01em; color: var(--ui-text-highlighted);
}
.demo-panel-body { flex: 1; overflow-y: auto; padding: 8px; }
.demo-content { flex: 1; min-width: 0; display: flex; flex-direction: column; overflow: hidden; }
.demo-scroll { flex: 1; min-height: 0; overflow-y: auto; }
.m-railbtn svg, .m-pitem svg, .m-btn svg, .m-pill svg, .m-aitag svg { flex: none; }
.demo-hintline { padding: 10px 16px 16px; font-size: 12px; color: var(--ui-text-dimmed); }
/* W hero podpowiedzi są nad ramką, w środku tylko by się ucinały */
.demo-shell.is-hero .demo-hintline { display: none; }
.demo-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.demo-grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.demo-grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }

/* Nota pod nagłówkiem kolumny. Tag AI stał wcześniej w jednej linii z pillem
   etapu i wypychał nagłówek poza kolumnę. Tutaj mieści się cały i przy okazji
   mówi, skąd system wziął tych kandydatów. */
.m-colnote {
  display: flex; align-items: center; gap: 5px;
  padding: 0 4px; font-size: 11px; line-height: 1.35;
  color: var(--color-primary-700);
}
.m-colnote svg { flex: none; color: var(--color-primary-600); }

/* Flaga na karcie kandydata w pipeline: CV, w którym system znalazł
   niespójności. Sygnał do weryfikacji, dlatego bursztyn, nie czerwień. */
.m-flagline {
  display: inline-flex; align-items: center; gap: 4px;
  margin-top: 5px; padding: 2px 6px; border-radius: 5px;
  background: var(--st-amber-bg); color: var(--st-amber-fg);
  font-size: 10.5px; line-height: 1.3; font-weight: 500;
}
.m-flagline svg { flex: none; }

/* Pasek narzędzi w demie ma stałą wysokość z aplikacji. Przy wąskim kadrze,
   który wymuszamy na telefonie, przyciski przechodzą do drugiej linii i wchodzą
   na tablicę. W demie pozwalamy paskowi urosnąć, zamiast kroić przyciski. */
.demo-shell .m-toolbar { height: auto; min-height: var(--bar-h); padding-top: 8px; padding-bottom: 8px; row-gap: 8px; }
