
/* ===========================================================================
 Cofa cool-graphite design system. One temperature everywhere: every neutral
 sits on the same cool axis so the UI reads OS-native and calm, and the lime
 accent supplies the only heat — reserved for explicit action controls.
 Type is Pretendard Variable first (self-hosted, same stack as the Cofa
 brochure site) with the system stack as fallback.
 Dark + light themes via the [data-theme] attribute on <html>.
 =========================================================================== */
[data-theme="dark"] {
  /* Deep-space graphite (bg ~8% lightness, a hair of blue): the night sky a
     lime ship drifts through — cool everywhere so the accent supplies the
     only heat. Reads as deep gray, never navy. */
  --bg: #121318;
  --panel: #181a1f;
  --panel-2: #1e2026;
  --elev: #24262d;
  --border: #2f323c;
  --border-2: #3b3f4a;
  --text: #eef0f4;
  /* Display headings that sit bare on --bg (hero, page titles): a cool
     starlight white, one step off the body text. */
  --heading: #e4e8f0;
  --text2: #a4a9b4;
  --muted: #6f747f;
  --ok: #eaecf0;
  --warn: #b4b8c1;
  --bad: #686d78;
  --link: #dee2ea;
  --github-link: #f0f2f5;
  --press-link: #f59e0b;
  --hover: rgba(255, 255, 255, 0.06);
  --active: #272931;
  --accent: #dff41b; /* action color (lime) — primary actions and strong action states */
  --accent-mark: #dff41b; /* icons, checks, focus marks and borders */
  --accent-ink: #dff41b; /* readable accent text and links */
  --on-accent: #101010; /* dark neutral ink on lime for contrast */
  --accent-soft: rgba(255, 255, 255, 0.07);
  --accent-tint: rgba(223, 244, 27, 0.08); /* lime row tint for selected rows */
  --step-flow-start: #4fc182;
  --step-flow-end: var(--accent);
  --step-flow-rest: var(--border-2);
  --step-flow-glow: 0 0 8px rgba(139, 211, 65, 0.14);
  --credit-low: #fbbf24;
  --credit-low-bg: rgba(251, 191, 36, 0.12);
  --credit-low-border: rgba(251, 191, 36, 0.36);
  --credit-empty: #f87171;
  --credit-empty-bg: rgba(248, 113, 113, 0.12);
  --credit-empty-border: rgba(248, 113, 113, 0.36);
  --sale: #ff7d6e; /* discount red — strikes and -NN% tags */
  --sale-bg: rgba(255, 125, 110, 0.13);
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-lg: 0 14px 50px rgba(0, 0, 0, 0.55);
  --scrim: rgba(0, 0, 0, 0.6);
}
[data-theme="light"] {
  --bg: #ffffff;
  --panel: #fafafb;
  --panel-2: #ffffff;
  --elev: #ffffff;
  --border: #e7e9ec;
  --border-2: #dadde1;
  --text: #2a2d33;
  /* Display headings on white: a cool near-black, one step deeper than
     body text so big type carries its own weight. */
  --heading: #1d2027;
  --text2: #6b7178;
  --muted: #9ba1a8;
  /* Monochrome status tones (같은 시맨틱: ok=진하게, bad=흐리게). These were
     missing on light, which silently voided every var(--ok|warn|bad) rule —
     e.g. the score gauge fill rendered transparent. */
  --ok: #1d2027;
  --warn: #6b7178;
  --bad: #9ba1a8;
  --link: #2563eb;
  --github-link: #24292f;
  --press-link: #b45309;
  --hover: #f2f3f5;
  --active: #eceef1;
  --accent: #dff41b; /* key color (lime) */
  /* White needs a cleaner green-lime mark and a separate, readable ink. The
     old shared olive (#93a800) made the whole light UI look muddy. */
  --accent-mark: #83b72a;
  --accent-ink: #47751e;
  --on-accent: #15171b; /* dark ink on lime (white would be invisible on lime) */
  --accent-soft: #f2f6e9;
  --accent-tint: rgba(131, 183, 42, 0.1); /* clean green-lime selection tint */
  --step-flow-start: #3f8f63;
  --step-flow-end: var(--accent);
  --step-flow-rest: var(--border-2);
  --step-flow-glow: none;
  --credit-low: #9a5b00;
  --credit-low-bg: #fff7df;
  --credit-low-border: #f1c75d;
  --credit-empty: #b42318;
  --credit-empty-bg: #fff1f1;
  --credit-empty-border: #f2a8a8;
  --sale: #d92d20; /* discount red — strikes and -NN% tags */
  --sale-bg: #feeceb;
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
  --shadow-lg: 0 16px 50px rgba(0, 0, 0, 0.18);
  --scrim: rgba(20, 22, 26, 0.42);
}
* {
  box-sizing: border-box;
}
html,
body {
  height: 100%;
}
/* The detail slideover parks off the right viewport edge (translateX(108%));
   clip that phantom width at the document level or its horizontal scrollbar
   pops in/out as the panel opens/closes and nudges the whole layout. Vertical
   body scroll (login/share pages) is untouched. */
html {
  overflow-x: clip;
}
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  /* Pretendard Variable leads (self-hosted dynamic-subset, linked in
     layout.tsx) — same face as the Cofa brochure site so the product and
     marketing surfaces read as one family; system faces back the stack. */
  font-family: "Pretendard Variable", "Pretendard", -apple-system, "SF Pro Text",
    "Apple SD Gothic Neo", "Segoe UI", system-ui, sans-serif;
  font-feature-settings: "ss06", "ss07"; /* Pretendard tabular/optical tweaks */
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  transition: background 0.2s, color 0.2s;
}
/* Native select arrows sit at inconsistent edges across browsers. Use one
   quiet chevron, inset from the right edge, for every single-choice control. */
select:not([multiple]) {
  appearance: none;
  -webkit-appearance: none;
  background-image: none;
  background-position: right 14px center;
  background-repeat: no-repeat;
  background-size: 14px;
  padding-right: 38px;
}
::-webkit-scrollbar {
  width: 9px;
  height: 9px;
}
::-webkit-scrollbar-thumb {
  background: var(--border-2);
  border-radius: 6px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
.ico {
  width: 16px;
  height: 16px;
  flex: none;
  display: inline-flex;
}
.ico svg {
  width: 100%;
  height: 100%;
  stroke: currentColor;
  fill: none;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
  display: block;
}
.ico.sm {
  width: 14px;
  height: 14px;
}
.ico.xs {
  width: 12px;
  height: 12px;
}
.ico.lg {
  width: 19px;
  height: 19px;
}
.app {
  display: grid;
  grid-template-columns: var(--sidebar-w, 252px) minmax(0, 1fr);
  height: 100vh;
  overflow: hidden;
  transition: grid-template-columns 0.2s ease;
}
.app.resizing-sidebar {
  transition: none;
}
.app.collapsed {
  grid-template-columns: 0px 1fr;
}
.app-size-guard {
  display: none;
}
.app-size-logo {
  font-size: 34px;
  margin-bottom: 26px;
}
.app-size-title {
  max-width: 360px;
  color: var(--text);
  font-size: 20px;
  font-weight: 700;
  line-height: 1.35;
}
.app-size-guard p {
  max-width: 360px;
  margin: 10px 0 0;
  color: var(--text2);
  font-size: 13px;
}
/* The product UI is dense: below 1000px (an FHD screen split in half no
   longer fits), hide the workspace instead of squeezing tables, panes, and
   sidebars into unreadable columns. Widening the window restores the exact
   same mounted app. */
@media (max-width: 999px) {
  .app {
    display: block;
    height: 100dvh;
    min-height: 100dvh;
    overflow: hidden;
  }
  .app > .sidebar,
  .app > .guest-header,
  .app > .main {
    display: none;
  }
  .app-size-guard {
    display: flex;
    min-height: 100dvh;
    padding: 32px;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: var(--bg);
    text-align: center;
  }
}
/* ===== guest shell (logged-out home) ===== */
/* No sidebar: a top bar with the brand at the left and Log in / Sign up at the
   right over the centered composer. Reuses `.app` so the small-screen guard
   still applies; `.app-guest` swaps the sidebar grid for a header + main
   column. */
.app-guest {
  display: flex;
  flex-direction: column;
}
.guest-header {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 14px 22px;
}
/* Three-part bar: brand left, nav centered, actions right. The 1-flex sides
   keep the nav visually centered regardless of brand/action widths. */
.guest-brand {
  flex: 1 0 auto;
}
.guest-nav {
  display: flex;
  align-items: center;
  gap: 40px;
}
.guest-navlink {
  border: 0;
  background: transparent;
  padding: 4px 2px;
  cursor: pointer;
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  color: var(--text2);
  text-decoration: none;
  transition: color 0.12s ease;
}
.guest-navlink:hover,
.guest-navlink[aria-current="page"] {
  color: var(--text);
}
.guest-actions {
  flex: 1 0 auto;
  display: flex;
  justify-content: flex-end;
}
.app-guest .main {
  flex: 1;
  min-height: 0;
}
.guest-login-btn {
  padding: 8px 16px;
  font-size: 13px;
  font-weight: 600;
}

/* ===== sidebar ===== */
.sidebar {
  background: var(--panel);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  position: relative;
}
.sidebar-resizer {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 9px;
  cursor: col-resize;
  touch-action: none;
  z-index: 20;
}
.sidebar-resizer::before {
  content: "";
  position: absolute;
  inset: 0 0 0 7px;
  background: transparent;
  transition: background 0.15s ease;
}
.sidebar-resizer:hover::before,
.sidebar-resizer.dragging::before {
  background: var(--text2);
}
.app.collapsed .sidebar-resizer {
  display: none;
}
.side-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 15px 14px 10px;
}
/* Right-side icon cluster in the top row: quick find (magnifier) + collapse. */
.side-top-actions {
  display: flex;
  align-items: center;
  gap: 2px;
}
.brand {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 800;
  font-size: 16px;
  letter-spacing: -0.01em;
}
/* Cofa wordmark. Both masters render; [data-theme] picks the visible one
   (white on dark, black on light) so the swap is CSS-only. */
.cofa-logo {
  position: relative;
  display: inline-flex;
  align-items: center;
  aspect-ratio: 1063 / 210;
  height: 0.95em;
  flex: none;
}
.cofa-logo-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: left center;
}
[data-theme="light"] .cofa-logo-on-dark {
  display: none;
}
[data-theme="dark"] .cofa-logo-on-light {
  display: none;
}
.brand-btn {
  border: 0;
  background: transparent;
  padding: 0;
  cursor: pointer;
  color: inherit;
  font-family: inherit;
  border-radius: 7px;
}
.brand-btn:hover {
  opacity: 0.65;
}
.iconbtn {
  border: 0;
  background: transparent;
  color: var(--text2);
  border-radius: 7px;
  padding: 6px;
  cursor: pointer;
  display: inline-flex;
}
.iconbtn:hover {
  background: var(--hover);
  color: var(--text);
}
.newtask {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 2px 10px 2px;
  padding: 8px 10px;
  border-radius: 9px;
  background: transparent;
  /* Dim tone to match idle session rows; sharpens on hover only. */
  color: var(--text2);
  font-weight: 600;
  font-size: 13.5px;
  cursor: pointer;
  border: 0;
  width: calc(100% - 20px);
  text-align: left;
}
.newtask .ico {
  color: var(--text2);
}
.newtask:hover {
  background: var(--hover);
  color: var(--text);
}
/* Work-mode tabs (sourcing / evaluation) at the very top of the sidebar — a
   full-width segmented pill. Each mode is its own workspace (projects +
   sessions), so the active tab reads as "where am I", not a filter. */
.side-seg {
  position: relative;
  display: flex;
  gap: 2px;
  margin: 2px 14px 8px;
  padding: 3px;
  /* A real track in both themes: --elev is white in light and near-panel in
     dark, so the pill needs the stronger --active fill plus a border. */
  background: var(--active);
  border: 1px solid var(--border);
  border-radius: 10px;
}
/* The single inverted thumb (text-on-background swap) that glides between the
   two tabs — sized for exactly the 2-tab layout (padding 3px, gap 2px). The
   active state must read at a glance on both themes; token-tone fills
   (--active/--elev) were near-invisible in dark mode. */
.side-seg::before {
  content: "";
  position: absolute;
  top: 3px;
  bottom: 3px;
  left: 3px;
  width: calc(50% - 4px);
  border-radius: 7px;
  background: var(--text);
}
.side-seg[data-active="screening"]::before {
  transform: translateX(calc(100% + 2px));
}
.side-seg button {
  position: relative; /* sits above the sliding thumb */
  flex: 1;
  border: 0;
  background: transparent;
  border-radius: 7px;
  padding: 5px 0;
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text2);
  cursor: pointer;
}
.side-seg button:hover {
  color: var(--text);
}
.side-seg button.active {
  color: var(--bg);
}
@media (prefers-reduced-motion: no-preference) {
  .side-seg::before {
    transition: transform 0.18s ease;
  }
  .side-seg button {
    transition: color 0.15s ease;
  }
}
.side-scroll {
  flex: 1;
  overflow: auto;
  padding: 2px 10px;
}
/* Bottom-pinned global nav (dashboard, talent pool, integrations, admin) —
   mode-independent destinations above the profile menu. Inherits .side-bottom's
   top border and padding; rows reuse .navrow verbatim.
   The doubled class is load-bearing: .side-bottom declares its own gap later in
   this file at equal specificity, so a bare .side-bottom-nav would lose. The
   gap must equal the top nav's row margin — one spacing for every nav row. */
.side-bottom.side-bottom-nav {
  gap: 4px;
}
/* The flex gap already spaces these rows; the .navrow margin would stack on it. */
.side-bottom-nav .navrow + .navrow {
  margin-top: 0;
}
/* Empty evaluation tab — one muted line under "+ new evaluation". */
.proj-empty-hint {
  padding: 4px 10px 6px 11px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--muted);
}
.navrow {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 10px;
  border-radius: 9px;
  /* Full text tone (not the dim --text2 of session rows): these are the app's
     primary destinations, so they must read at a glance. */
  color: var(--text);
  font-weight: 500;
  line-height: 1.35;
  cursor: pointer;
  font-size: 13.5px;
  /* Interactive rows render as <button> (the disabled integration row stays a
     <div>); neutralize UA button chrome so both read identically to the old
     styled row. */
  border: 0;
  background: transparent;
  width: 100%;
  text-align: left;
  font-family: inherit;
}
/* Under-development destination: greyed out and non-clickable. */
/* Primary destinations read as one compact menu group. Keep the row's touch
   target intact and control visual density through only the inter-row gap.
   Matched by .side-bottom-nav's flex gap so the top and bottom nav clusters
   breathe identically. */
.navrow + .navrow {
  margin-top: 4px;
}
.navrow.disabled {
  color: var(--muted);
  cursor: default;
  pointer-events: none;
}
.navrow:hover {
  background: var(--hover);
  color: var(--text);
}
.navrow.active {
  background: var(--active);
  color: var(--text);
  font-weight: 600;
}
.navrow .tail {
  margin-left: auto;
  color: var(--muted);
  font-size: 11px;
}
.divider {
  height: 1px;
  background: var(--border);
  margin: 14px 8px;
}
.sec-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 4px 12px 6px;
}
.sec-title {
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text2);
  font-weight: 700;
}
.sec-more {
  font-size: 11px;
  color: var(--muted);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 3px;
}
.sess {
  position: relative;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 5px 10px 5px 11px;
  border-radius: 8px;
  color: var(--text2);
  cursor: pointer;
  font-size: 13px;
  white-space: nowrap;
  overflow: hidden;
}
/* Keep each run as its own target: the small gap prevents adjacent hover and
   active fills from reading as a single merged block. */
.sess-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.sess .ico {
  width: 14px;
  height: 14px;
  opacity: 0.8;
}
.sess .label {
  overflow: hidden;
  text-overflow: ellipsis;
}
.sess:hover {
  background: var(--hover);
  color: var(--text);
}
.sess.active {
  background: var(--active);
  color: var(--text);
  font-weight: 600;
}
/* Shortlist row styling lives with .proj-children (sidebar project section). */
.sess-status {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
}
.sess:hover .sess-status {
  opacity: 0;
}
.sess.opening .sess-status {
  opacity: 1;
}
/* An archive being read has no name yet — the row shows the state instead,
   dimmed so it does not read as a title. The spinner in the icon slot is the
   only motion it needs; a progress bar would have to pretend it knows how far
   along the roster agent is, and it never does. */
.sess.reading .label,
.sess.read-failed .label {
  color: var(--text3);
}
.live-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--text);
  flex: none;
  animation: pulse 1.8s infinite;
}
@keyframes pulse {
  0% {
    box-shadow: 0 0 0 0 rgba(150, 150, 150, 0.5);
  }
  70% {
    box-shadow: 0 0 0 5px rgba(150, 150, 150, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(150, 150, 150, 0);
  }
}
.sess-more {
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  border: 0;
  background: transparent;
  color: var(--text2);
  padding: 4px;
  border-radius: 6px;
  cursor: pointer;
  display: inline-flex;
  opacity: 0;
}
.sess:hover .sess-more,
.sess-more.open {
  opacity: 1;
}
.sess-more:hover {
  background: var(--active);
  color: var(--text);
}
.sess-more .ico {
  width: 15px;
  height: 15px;
  opacity: 1;
}
.sess.renaming {
  background: var(--active);
}
/* Inline rename input: zero-height box (no border/vertical padding, matching
   line-height) so it occupies exactly the .sess label's space — no row jump
   between display and edit. Focus ring is drawn INSET so it never grows the box. */
.sess-rename {
  flex: 1;
  min-width: 0;
  border: 1px solid var(--border-2);
  background: var(--elev);
  color: var(--text);
  /* A real input box with comfortable padding — the row may grow slightly while
     editing; that's fine and reads more naturally than text glued to the edge. */
  padding: 5px 9px;
  margin: 0;
  border-radius: 7px;
  font-size: 13px;
  line-height: 1.2;
  font-family: inherit;
  outline: none;
}
.sess-rename:focus {
  border-color: var(--text2);
}
/* Session context menu (⋯) — floats over the main content, monochrome. */
.ctx-backdrop {
  position: fixed;
  inset: 0;
  z-index: 199;
}
.ctxmenu {
  position: fixed;
  min-width: 184px;
  background: var(--elev);
  border: 1px solid var(--border-2);
  border-radius: 13px;
  box-shadow: var(--shadow-lg);
  padding: 6px;
  z-index: 200;
  animation: popUp 0.14s ease;
}
.ctxmenu .mi {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  padding: 9px 11px;
  border: 0;
  background: transparent;
  border-radius: 9px;
  color: var(--text);
  cursor: pointer;
  font-size: 13px;
  font-family: inherit;
  text-align: left;
}
.ctxmenu .mi .ico {
  color: var(--text2);
}
.ctxmenu .mi:hover {
  background: var(--hover);
}
.ctxmenu .mi-danger:hover .ico {
  color: var(--text);
}
.side-bottom {
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px 10px;
  position: relative;
}
.guest-footer {
  gap: 8px;
}
.guest-indicator {
  color: var(--text2);
  font-size: 11.5px;
  line-height: 1.45;
  text-align: center;
}
.signup-prompt-copy {
  color: var(--text2);
  font-size: 13px;
  line-height: 1.6;
  margin: 0 0 18px;
}
.signup-prompt-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}
.signup-prompt-actions .btn {
  min-height: 34px;
}
.credit-pill {
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text2);
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 100%;
  min-height: 30px;
  padding: 6px 8px;
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 700;
  cursor: default;
}
.credit-pill-copy {
  display: inline-flex;
  align-items: baseline;
  gap: 0.32em;
}
/* Live counters roll only after their first value. The outgoing value is a
   pseudo-element, keeping one current number in the accessible/text DOM. */
.rolling-number {
  position: relative;
  display: inline-grid;
  place-items: center;
  overflow: clip;
  min-width: 1ch;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  isolation: isolate;
}
.rolling-number-value,
.rolling-number.is-changing::before {
  grid-area: 1 / 1;
}
.rolling-number.is-changing::before {
  content: attr(data-previous);
  pointer-events: none;
}
.rolling-number.direction-down::before {
  animation: rolling-number-out-down 360ms cubic-bezier(0.22, 0.61, 0.36, 1)
    both;
}
.rolling-number.direction-down .rolling-number-value {
  animation: rolling-number-in-down 360ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
}
.rolling-number.direction-up::before {
  animation: rolling-number-out-up 360ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
}
.rolling-number.direction-up .rolling-number-value {
  animation: rolling-number-in-up 360ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
}
/* A balance change gets one faint acknowledgement from the existing pill;
   no extra -1 label or persistent color state is introduced. */
.credit-pill:has(.credit-roll.is-changing) {
  animation: credit-balance-flash 420ms ease-out both;
}
@keyframes rolling-number-out-down {
  to {
    opacity: 0;
    transform: translateY(72%);
  }
}
@keyframes rolling-number-in-down {
  from {
    opacity: 0;
    transform: translateY(-72%);
  }
}
@keyframes rolling-number-out-up {
  to {
    opacity: 0;
    transform: translateY(-72%);
  }
}
@keyframes rolling-number-in-up {
  from {
    opacity: 0;
    transform: translateY(72%);
  }
}
@keyframes credit-balance-flash {
  45% {
    border-color: color-mix(in srgb, var(--accent-mark) 42%, var(--border));
    box-shadow: 0 0 0 3px var(--accent-tint);
  }
}
/* The zap bolt carries the brand lime — the one colored note in the pill.
   Low/empty states keep their own amber/red and color the bolt with them. */
.credit-pill:not(.low):not(.empty) .ico,
.planhead-credit .ico {
  color: var(--accent-mark);
}
.credit-pill.low {
  border-color: var(--credit-low-border);
  background: var(--credit-low-bg);
  color: var(--credit-low);
}
.credit-pill.empty {
  border-color: var(--credit-empty-border);
  background: var(--credit-empty-bg);
  color: var(--credit-empty);
}
/* Account row + bell side by side — separate hover targets by design. */
.profile-row {
  display: flex;
  align-items: center;
  gap: 4px;
}
.profile {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 7px 8px;
  border-radius: 8px;
  color: var(--text2);
  font-size: 13px;
  cursor: pointer;
}
.profile:hover {
  background: var(--hover);
}
.profile-name {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
.profile-name > span:first-child {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.plan-badge {
  border: 1px solid var(--border-2);
  border-radius: 999px;
  color: var(--text2);
  background: var(--active);
  padding: 1px 6px;
  font-size: 10px;
  font-weight: 700;
  line-height: 1.5;
  flex: none;
}
.avatar {
  width: 27px;
  height: 27px;
  border-radius: 50%;
  background: var(--active);
  color: var(--text);
  display: grid;
  place-items: center;
  font-size: 12px;
  font-weight: 700;
  flex: none;
}
.pmenu {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 10px;
  right: 10px;
  background: var(--elev);
  border: 1px solid var(--border-2);
  border-radius: 14px;
  box-shadow: var(--shadow-lg);
  padding: 8px;
  z-index: 50;
  animation: popUp 0.16s ease;
}
@keyframes popUp {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
.pmenu .mailhead {
  font-size: 12px;
  color: var(--text2);
  padding: 8px 10px 4px;
}
.pmenu .planhead {
  display: flex;
  align-items: center;
  gap: 5px;
  color: var(--text);
  padding: 0 10px 8px;
  font-size: 12px;
  font-weight: 700;
}
.pmenu .planhead-credit {
  color: var(--text2);
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.pmenu .mi {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 9px 10px;
  border-radius: 9px;
  color: var(--text);
  cursor: pointer;
  font-size: 13px;
}
.pmenu .mi:hover {
  background: var(--hover);
}
.pmenu .mi .tail {
  margin-left: auto;
  color: var(--muted);
}
.pmenu .mdiv {
  height: 1px;
  background: var(--border);
  margin: 6px 6px;
}
/* Language flyout — fixed so the sidebar's overflow:hidden can't clip it;
   anchored to the row's viewport rect from ProfileMenu. */
.pmenu-sub {
  position: fixed;
  min-width: 190px;
  background: var(--elev);
  border: 1px solid var(--border-2);
  border-radius: 14px;
  box-shadow: var(--shadow-lg);
  padding: 8px;
  z-index: 51;
  animation: popUp 0.16s ease;
}
.pmenu-sub .mi .pmenu-sub-check {
  color: var(--accent-mark);
}
/* ===== notification bell (right of the account row) + its popover ===== */
.notif {
  display: flex;
  flex: none;
}
.notif-bell {
  position: relative;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--muted);
  font-family: inherit;
  cursor: pointer;
}
.notif-bell:hover {
  background: var(--active);
  color: var(--text);
}
/* Unread count — the one lime note in the row (key color = badges only). */
.notif-badge {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 15px;
  height: 15px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--on-accent);
  font-size: 9.5px;
  font-weight: 700;
  line-height: 15px;
  text-align: center;
}
/* Floating panel to the RIGHT of the sidebar (Liner-style). Fixed like
   .pmenu-sub so the sidebar's overflow can't clip it — anchored to the
   bell's viewport rect from NotificationBell. */
.notif-pop {
  position: fixed;
  width: 320px;
  max-width: calc(100vw - 24px);
  background: var(--elev);
  border: 1px solid var(--border-2);
  border-radius: 14px;
  box-shadow: var(--shadow-lg);
  padding: 8px;
  z-index: 51;
  animation: popUp 0.16s ease;
  cursor: default;
  display: flex;
  flex-direction: column;
}
.notif-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 4px 10px 8px;
}
.notif-title {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text);
}
.notif-markall {
  border: 0;
  background: transparent;
  padding: 2px 4px;
  border-radius: 6px;
  color: var(--text2);
  font-family: inherit;
  font-size: 11.5px;
  font-weight: 600;
  cursor: pointer;
}
.notif-markall:hover {
  background: var(--hover);
  color: var(--text);
}
.notif-list {
  max-height: min(380px, 50vh);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.notif-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  color: var(--text2);
  font-size: 12.5px;
  padding: 46px 16px;
  text-align: center;
}
.notif-empty .ico {
  color: var(--muted);
}
.notif-item {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 9px 10px;
  border-radius: 9px;
  cursor: default;
  text-align: left;
}
.notif-item.unread {
  cursor: pointer;
}
.notif-item.unread:hover {
  background: var(--hover);
}
.notif-item-head {
  display: flex;
  align-items: center;
  gap: 6px;
}
/* Neutral kind chip (plan-badge sizing); the lime stays on badge + dot. */
.notif-type {
  border: 1px solid var(--border-2);
  border-radius: 999px;
  background: var(--active);
  color: var(--text2);
  padding: 1px 6px;
  font-size: 10px;
  font-weight: 700;
  line-height: 1.5;
  flex: none;
}
.notif-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent-mark);
  flex: none;
}
.notif-time {
  margin-left: auto;
  color: var(--muted);
  font-size: 11px;
  flex: none;
}
.notif-item-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  line-height: 1.4;
}
.notif-item-body {
  font-size: 12px;
  color: var(--text2);
  line-height: 1.55;
  white-space: pre-wrap;
  word-break: break-word;
}
/* ===== main ===== */
.main {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}
.topbar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 18px;
  border-bottom: 1px solid var(--border);
  min-height: 54px;
}
.crumb {
  display: flex;
  align-items: center;
  gap: 9px;
  color: var(--text);
  font-weight: 600;
  font-size: 14px;
}
.crumb .meta {
  color: var(--text2);
  font-weight: 400;
  font-size: 12.5px;
}
/* Session status chip — the mark carries the state (pulsing live-dot while
   running, key-color check when done, hollow dot while waiting); the label
   stays quiet so it never competes with the title. */
.crumb-status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  font-weight: 400;
  color: var(--text2);
}
.crumb-status .wait-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  border: 1.5px solid var(--border-2);
  flex: none;
}
.crumb-status.s-running {
  color: var(--text);
  font-weight: 500;
}
.crumb-status.s-done .ico {
  color: var(--accent-mark);
}
.crumb-status.s-aborted {
  color: var(--muted);
}
/* Session title doubles as the rename affordance — quiet until hovered,
   then a pencil appears; clicking swaps it for the inline input. */
.crumb-edit {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-weight: 600;
  padding: 2px 6px;
  margin: -2px -6px;
  border-radius: 6px;
  cursor: text;
}
.crumb-edit:hover {
  background: var(--panel-2);
}
.crumb-edit .ico {
  color: var(--text2);
  opacity: 0;
  transition: opacity 0.12s;
}
.crumb-edit:hover .ico,
.crumb-edit:focus-visible .ico {
  opacity: 1;
}
.crumb-rename {
  width: min(340px, 40vw);
  border: 1px solid var(--border-2);
  background: var(--bg);
  color: var(--text);
  border-radius: 6px;
  padding: 3px 7px;
  font: inherit;
  font-weight: 600;
  outline: none;
}
.crumb-rename:focus {
  border-color: var(--text2);
}
.stage {
  flex: 1;
  min-height: 0;
  display: flex;
  /* Containing block for the candidate detail slideover on every page. The
     session view's .split (position: relative, fills the stage) already scoped
     the panel to the content area below the topbar; without this, pages
     lacking a positioned wrapper (dashboard, talent pool, project home) let
     the panel resolve to the viewport instead — covering the topbar and
     computing its 92% width cap against a wider box, so the same detailW
     rendered different widths per page. One shared containing block keeps the
     panel geometry identical everywhere. */
  position: relative;
}
.collapsed-toggle {
  background: var(--panel);
  border: 1px solid var(--border);
}
/* Home has no topbar — the expand control floats where the bar would start. */
.collapsed-toggle-float {
  position: fixed;
  top: 11px;
  left: 14px;
  z-index: 30;
}
/* ===== composer ===== */
.composer {
  border: 1px solid var(--border-2);
  border-radius: 16px;
  background: var(--panel-2);
  padding: 13px 15px 11px;
  box-shadow: var(--shadow);
  transition: border-color 0.15s;
}
.composer-top {
  display: flex;
  justify-content: flex-start;
  margin: -2px 0 14px;
}
.composer .field {
  width: 100%;
  border: 0;
  outline: 0;
  background: transparent;
  color: var(--text);
  font-family: inherit;
  font-size: 14px;
  resize: none;
  line-height: 1.55;
  max-height: 150px;
}
.composer .field::placeholder {
  color: var(--muted);
}
.composer-actions {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-top: 9px;
}
/* Send sits beside the text when there is nothing else to put on its row.
   Centred, and padded evenly on both ends: the button is the right-hand
   counterpart of the first character, not a second row's worth of chrome. */
/* Bottom-aligned, not centred: as the text grows to two, three, five lines the
   send button stays in the corner it was in — a target that drifts up the box
   with every newline is a target you have to look for. */
.composer-inline {
  display: flex;
  align-items: flex-end;
  gap: 10px;
  padding: 10px 10px 10px 16px;
}
.composer-inline .field {
  flex: 1;
  min-width: 0;
  /* As tall as the send button, with one line centred inside it. The padding
     has to be symmetric: the row is bottom-aligned, so top padding alone
     drops the text onto the floor of the box while the space piles up above
     it. Growing to two lines keeps the same breathing room top and bottom. */
  min-height: 33px;
  padding: 5px 0;
}
.composer-inline .composer-actions {
  margin-top: 0;
  flex: none;
}
/* Attached-file chips shown above the textarea while composing. */
.composer-files {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 8px;
}
.filechip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: 240px;
  font-size: 12px;
  color: var(--text2);
  border: 1px solid var(--border-2);
  background: var(--panel);
  border-radius: 8px;
  padding: 4px 6px 4px 9px;
}
.filechip .fname {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.filechip.error {
  border-style: dashed;
  color: var(--muted);
}
.filechip .ferr {
  color: var(--muted);
}
.filechip .fdel {
  border: 0;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  padding: 2px;
  border-radius: 5px;
  display: inline-flex;
}
.filechip .fdel:hover {
  background: var(--hover);
  color: var(--text);
}
.filechip .fthumb {
  width: 22px;
  height: 22px;
  border-radius: 5px;
  object-fit: cover;
  display: block;
  flex: none;
}
/* ===== intake checklist (hero composer) ===== */
/* Slot in the composer's bottom action bar: grows between the attach and
   send controls; the checklist wraps inside it at narrow widths. The slot
   absorbs ALL the squeeze (its content wraps), so the sibling action
   buttons must not shrink or their labels break mid-word. */
.composer-slot {
  flex: 1 1 auto;
  min-width: 0;
}
.composer-actions:has(.composer-slot) > .iconbtn,
.composer-actions:has(.composer-slot) > .chipbtn,
.composer-actions:has(.composer-slot) > .send {
  flex: none;
  white-space: nowrap;
}
.intake-checklist {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  padding: 0 2px;
  font-size: 12px;
  color: var(--muted);
  transition: opacity 0.35s ease, transform 0.35s ease;
}
/* Pre-reveal state: mounted (so the reveal transitions instead of popping and
   the layout never jumps) but invisible until typing/chat starts. */
.intake-checklist.intake-checklist-hidden {
  opacity: 0;
  transform: translateY(4px);
  pointer-events: none;
}
/* One guidance sentence; a mentioned term lights up as colored check +
   colored text — no box or circle, so nothing reads as a clickable control. */
/* Unfilled terms read as part of the sentence — no weight of their own;
   the highlighter band alone marks the covered ones. */
.intake-term {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  color: inherit;
  transition: color 0.25s;
}
.intake-term.met {
  /* A real highlighter stroke: the lime band sits behind the LOWER half of
     the glyphs (not a pill around them) — same type size as the sentence,
     the marker alone carries the emphasis. */
  color: var(--heading);
  font-weight: 700;
  background: linear-gradient(
    transparent 45%,
    var(--accent) 45%,
    var(--accent) 92%,
    transparent 92%
  );
  padding: 0 3px;
  margin: 0 -1px;
}
/* Light glyphs over full-strength lime wash out — on dark, dim the band and
   let the hue mark the hit. */
[data-theme="dark"] .intake-term.met {
  background: linear-gradient(
    transparent 45%,
    rgba(223, 244, 27, 0.52) 45%,
    rgba(223, 244, 27, 0.52) 92%,
    transparent 92%
  );
}
.intake-sep {
  margin: 0 3px;
  white-space: pre;
}
/* All five covered: the trailing clause flips to the completion note — same
   voice (weight/color) as the rest of the sentence; the five highlighted
   terms already carry the celebration. */
.intake-done {
  color: inherit;
  font-weight: inherit;
}
/* ===== chat attachments (message bubbles) ===== */
.msg-files {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 8px;
}
.att-thumb {
  display: block;
  width: 180px;
  max-width: 100%;
  border: 1px solid var(--border-2);
  border-radius: 10px;
  overflow: hidden;
  padding: 0;
  background: var(--panel-2);
  cursor: zoom-in;
}
.att-thumb:hover {
  border-color: var(--text2);
}
.att-thumb img {
  display: block;
  width: 100%;
  height: auto;
  max-height: 220px;
  object-fit: cover;
}
.att-thumb.loading {
  height: 110px;
  background: var(--active);
}
.att-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--border-2);
  background: var(--panel-2);
  color: var(--text);
  border-radius: 8px;
  padding: 5px 9px;
  font-size: 12px;
  font-family: inherit;
  cursor: pointer;
}
.att-chip:hover {
  background: var(--hover);
}
.att-chip .ico {
  color: var(--text2);
}
.att-chip.inert {
  cursor: default;
  color: var(--text2);
}
.att-chip.inert:hover {
  background: var(--panel-2);
}
/* full-size image viewer */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 300;
  background: var(--scrim);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  animation: popUp 0.14s ease;
  cursor: zoom-out;
}
.lightbox img {
  max-width: min(1200px, 92vw);
  max-height: 84vh;
  border-radius: 12px;
  box-shadow: var(--shadow-lg);
  background: var(--panel);
  cursor: default;
}
.lb-name {
  color: #fff;
  font-size: 12.5px;
  opacity: 0.85;
}
.lb-close {
  position: absolute;
  top: 16px;
  right: 16px;
  border: 0;
  background: rgba(0, 0, 0, 0.35);
  color: #fff;
  border-radius: 9px;
  padding: 8px;
  cursor: pointer;
  display: inline-flex;
}
.lb-close:hover {
  background: rgba(0, 0, 0, 0.55);
}
.chipbtn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text2);
  border-radius: 8px;
  padding: 5px 10px;
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
}
.chipbtn:hover {
  background: var(--hover);
  color: var(--text);
}
.roundbtn {
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--text2);
  display: grid;
  place-items: center;
  cursor: pointer;
}
.roundbtn:hover {
  background: var(--hover);
  color: var(--text);
}
.send {
  width: 33px;
  height: 33px;
  border: 0;
  border-radius: 50%;
  background: var(--text);
  color: var(--bg);
  display: grid;
  place-items: center;
  cursor: pointer;
  margin-left: auto;
}
.send:hover {
  opacity: 0.9;
}
.send[disabled] {
  opacity: 0.45;
  cursor: default;
}
.send.stop {
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border-2);
}
.send.stop:hover {
  opacity: 1;
  background: var(--hover);
}
/* While busy, stop renders NEXT TO send: only the first of the pair may carry
   the auto margin, or flexbox splits the free space and strands stop mid-row. */
.send.stop + .send {
  margin-left: 0;
}

/* Pending-instruction stack shown directly above the composer (queue + steer). */
.queue-stack {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 8px;
}
.queue-card {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  background: var(--panel);
  border: 1px solid var(--border-2);
  border-radius: 10px;
  padding: 7px 10px;
  animation: slideIn 0.2s ease;
}
.queue-card .qc-lead {
  color: var(--muted);
  flex: none;
}
.queue-card .qc-text {
  color: var(--text);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.queue-card .qc-tag {
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  border: 1px solid var(--border-2);
  border-radius: 5px;
  padding: 1px 5px;
  flex: none;
}
.queue-card .qc-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  border: 1px solid var(--border-2);
  background: transparent;
  color: var(--text);
  border-radius: 7px;
  padding: 3px 8px;
  font-size: 11px;
  font-weight: 600;
  cursor: pointer;
  flex: none;
}
.queue-card .qc-btn:hover {
  background: var(--hover);
}
.queue-card .qc-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  padding: 3px;
  border-radius: 6px;
  flex: none;
}
.queue-card .qc-icon:hover {
  background: var(--hover);
  color: var(--text);
}
/* ===== new task ===== */
.newhome {
  flex: 1;
  overflow-y: auto;
  overflow-x: clip;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 32px;
}
/* Wider than the old 680px so the hero composer stretches Juicebox-style;
   the composer itself keeps its regular (chat-pane) height. */
.newhome-inner {
  width: 100%;
  max-width: 725px;
}
/* One shared glow behind BOTH the title and the composer — the composer's
   own opaque card covers the middle of it, same as a Venn overlap, instead
   of two separate glows scoped to each piece. */
.hero-ai-glow-wrap {
  position: relative;
  isolation: isolate;
}
.hero-ai-glow-wrap > :not(.ai-atmosphere) {
  position: relative;
  z-index: 1;
}
.home-hero-title {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: nowrap;
  /* The loader art carries transparent padding of its own; the gap below is
     on top of that so the mark reads clearly separated from the title. */
  gap: 12px;
  width: min(620px, calc(100vw - 64px));
  margin: 0 0 28px 50%;
  transform: translateX(-50%);
  /* Rise in from below like the composer (.swap) — the centering translateX
     must ride along in every keyframe or the animation would drop it. */
  animation: heroTitleIn 0.34s cubic-bezier(0.22, 0.61, 0.36, 1) both;
}
@keyframes heroTitleIn {
  from {
    opacity: 0;
    transform: translateX(-50%) translateY(14px);
  }
  to {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }
}
.home-hero-title-auth {
  gap: 10px;
  width: min(560px, calc(100vw - 64px));
  margin-bottom: 24px;
}
.home-loader-mark {
  position: relative;
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  margin: 0;
  opacity: 0.94;
  flex: none;
  filter: drop-shadow(0 12px 32px rgba(0, 0, 0, 0.26));
  animation: homeMarkIn 0.42s cubic-bezier(0.22, 0.61, 0.36, 1) both;
}
.home-hero-title-auth .home-loader-mark {
  width: 44px;
  height: 44px;
}
.home-loader-img {
  grid-area: 1 / 1;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.home-loader-img-static {
  display: none;
}
@keyframes homeMarkIn {
  from {
    opacity: 0;
    transform: translateY(8px) scale(0.96);
  }
  to {
    opacity: 0.94;
    transform: none;
  }
}
.bigtitle {
  display: flex;
  flex-wrap: nowrap;
  align-items: baseline;
  justify-content: center;
  gap: 0;
  min-width: 0;
  color: var(--heading);
  font-size: 38px;
  font-weight: 760;
  text-align: center;
  line-height: 1.16;
  letter-spacing: 0;
  margin: 0;
}
.home-hero-title-auth .bigtitle {
  font-size: 32px;
  font-weight: 760;
  line-height: 1.18;
}
/* The same headline asked inside a conversation column instead of on a hero.
   The column is a fraction of the hero's width, so the type steps down with
   it — and it may wrap there, which the hero never has to. */
.bigtitle-convo {
  flex-wrap: wrap;
  font-size: 22px;
  line-height: 1.24;
  /* Wrapped, the carousel's line box must not collapse onto the fixed parts;
     the phrase heights are ems, so they follow the smaller size on their own. */
  row-gap: 2px;
}
/* Screening keeps the exact sourcing headline typography and spacing. Its
   copy is longer, so only the available one-line canvas is wider. */
.home-hero-title:has(.bigtitle-screening) {
  width: min(980px, calc(100vw - 64px));
}
.headline-prefix + .headline-carousel {
  margin-left: 0.18em;
}
.headline-carousel {
  position: relative;
  display: inline-grid;
  flex: none;
  /* Width rides a keyframe animation synced to the phrase cycle so the
     underline hugs whichever phrase is showing instead of holding the
     longest phrase's width; the phrases are centered, so a too-small width
     would clip both edges — keep each stop slightly generous. */
  width: 5.5em;
  height: 1.22em;
  overflow: hidden;
  text-align: center;
  vertical-align: bottom;
  border-bottom: 1px solid color-mix(in srgb, var(--heading) 30%, transparent);
  box-shadow: inset 0 -1px color-mix(in srgb, var(--heading) 6%, transparent);
  animation: headlineWidthCycle 5.8s cubic-bezier(0.22, 0.61, 0.36, 1) 0.18s
    forwards;
}
/* One stop per HEADLINE_PHRASES entry, same timing as headlinePhraseCycle.
   Stops are the measured phrase widths plus ~0.2em of air. */
@keyframes headlineWidthCycle {
  0%,
  18% {
    width: 5.5em; /* Python master (Python 고수, 5.31em) */
  }
  27%,
  45% {
    width: 4.85em; /* AI engineer (AI 엔지니어, 4.67em) */
  }
  54%,
  72% {
    width: 4.35em; /* GTM leader (GTM 리더, 4.19em) */
  }
  82%,
  100% {
    width: 3.85em; /* any talent (어떤 인재, 3.69em) */
  }
}
/* English keeps "Looking for" fixed and rotates only the talent description.
   The descriptions are still wider than their Korean counterparts, so the en
   locale rides its own width cycle (same timing). Keyed off the carousel's
   own lang attribute (the component's rendered locale), NOT html[lang]: on
   /en the subtree is pinned to en while the document lang follows the cookie. */
.headline-carousel[lang="en"] {
  width: 7.4em;
  animation-name: headlineWidthCycleEn;
}
@keyframes headlineWidthCycleEn {
  0%,
  18% {
    width: 7.4em; /* Python experts */
  }
  27%,
  45% {
    width: 6.1em; /* AI engineers */
  }
  54%,
  72% {
    width: 6.15em; /* GTM leaders */
  }
  82%,
  100% {
    width: 5.65em; /* great talent */
  }
}
.headline-carousel-screening {
  --screening-headline-w1: 5.1em;
  --screening-headline-w2: 7.35em;
  --screening-headline-w3: 6.1em;
  width: var(--screening-headline-w1);
  animation-name: screeningHeadlineWidthCycle;
}
@keyframes screeningHeadlineWidthCycle {
  0%,
  25% {
    width: var(--screening-headline-w1);
  }
  38%,
  62% {
    width: var(--screening-headline-w2);
  }
  75%,
  100% {
    width: var(--screening-headline-w3);
  }
}
.headline-carousel-screening[lang="en"] {
  --screening-headline-w1: 6.8em;
  --screening-headline-w2: 9.6em;
  --screening-headline-w3: 10.7em;
  /* Override the more-specific generic English sourcing selector above.
     Without this, the copy measures correctly but headlineWidthCycleEn
     squeezes the screening carousel back to the sourcing phrase widths. */
  animation-name: screeningHeadlineWidthCycle;
}
.headline-carousel-screening .headline-track {
  animation-name: screeningHeadlinePhraseCycle;
}
.headline-track {
  display: flex;
  flex-direction: column;
  /* As a grid item the track's implicit min-width is the widest phrase, so
     it refuses to shrink with the animated carousel width and clips on the
     right instead; min-width: 0 lets it follow the container. */
  min-width: 0;
  animation: headlinePhraseCycle 5.8s cubic-bezier(0.22, 0.61, 0.36, 1) 0.18s
    forwards;
  will-change: transform;
}
.headline-item {
  height: 1.22em;
  line-height: 1.16;
  white-space: nowrap;
}
.headline-item-copy {
  display: inline-block;
  width: max-content;
  max-width: none;
}
.headline-fixed {
  white-space: nowrap;
}
@keyframes headlinePhraseCycle {
  0%,
  18% {
    transform: translateY(0);
  }
  27%,
  45% {
    transform: translateY(-25%);
  }
  54%,
  72% {
    transform: translateY(-50%);
  }
  82%,
  100% {
    transform: translateY(-75%);
  }
}
@keyframes screeningHeadlinePhraseCycle {
  0%,
  25% {
    transform: translateY(0);
  }
  38%,
  62% {
    transform: translateY(-33.3333%);
  }
  75%,
  100% {
    transform: translateY(-66.6667%);
  }
}
.segwrap {
  display: flex;
  justify-content: center;
  margin-bottom: 18px;
}
.segmented {
  display: inline-flex;
  gap: 3px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 4px;
}
.segmented button {
  position: relative;
  border: 0;
  background: transparent;
  color: var(--text2);
  padding: 8px 16px;
  border-radius: 9px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  display: inline-flex;
  gap: 7px;
  align-items: center;
  font-family: inherit;
  white-space: nowrap;
}
.seg-icon,
.seg-lock {
  flex: none;
}
.seg-label {
  min-width: 0;
}
.segmented button:hover {
  color: var(--text);
}
.segmented button.active {
  background: var(--active);
  color: var(--text);
}
.composer-top .segwrap {
  justify-content: flex-start;
  margin-bottom: 0;
  max-width: 100%;
}
.composer-top .segmented {
  max-width: 100%;
  flex-wrap: wrap;
  gap: 4px;
  border: 0;
  background: transparent;
  padding: 0;
}
.composer-top .segmented button {
  min-height: 30px;
  padding: 6px 10px;
  border-radius: 8px;
  font-size: 12.5px;
}
.composer-top .segmented button.active {
  background: var(--active);
  color: var(--text);
}
.landing-screening-upload {
  width: 100%;
}
.landing-screening-drop {
  min-height: 190px;
  border-radius: 11px;
  background: transparent;
  box-shadow: none;
}
/* The home composer should feel anchored to the page, not like a side panel.
   Bring the search block up from below; example chips stagger separately.
   riseIn is the shared rise-from-below entrance (also the pricing page). */
.swap {
  animation: riseIn 0.34s cubic-bezier(0.22, 0.61, 0.36, 1) both;
  will-change: transform, opacity;
}
@keyframes riseIn {
  from {
    opacity: 0;
    transform: translateY(18px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
/* Home entrance plays as a sequence — hero title, then the composer, then
   the chips. Scoped to .newhome: .swap elsewhere (dashboard tab switches)
   should still respond instantly. */
.newhome .swap {
  animation-delay: 0.12s;
}
.swap .examples .ex {
  animation: exampleChipIn 0.34s cubic-bezier(0.22, 0.61, 0.36, 1) both;
  will-change: transform, opacity;
}
.swap .examples .ex:nth-child(1) {
  animation-delay: 0.24s;
}
.swap .examples .ex:nth-child(2) {
  animation-delay: 0.3s;
}
.swap .examples .ex:nth-child(3) {
  animation-delay: 0.36s;
}
@keyframes exampleChipIn {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@media (prefers-reduced-motion: reduce) {
  .home-loader-mark {
    animation: none;
  }
  .home-loader-img-dynamic {
    display: none;
  }
  .home-loader-img-static {
    display: block;
  }
  .headline-track {
    animation: none;
    transform: translateY(-75%);
  }
  /* Track parks on the last phrase (any talent / 어떤 인재) — pin the underline
     to match. */
  .headline-carousel {
    animation: none;
    width: 3.85em;
  }
  .headline-carousel[lang="en"] {
    width: 5.65em; /* great talent */
  }
  .headline-carousel-screening,
  .headline-carousel-screening[lang="en"] {
    width: var(--screening-headline-w3);
  }
  .headline-carousel-screening .headline-track {
    transform: translateY(-66.6667%);
  }
  .swap,
  .swap .examples .ex {
    animation: none;
  }
  .home-hero-title,
  .pricing-head,
  .pricing-card.set-card {
    animation: none;
  }
  .sstep-bar {
    transition: none;
  }
}
.applied {
  display: flex;
  gap: 8px;
  justify-content: center;
  margin-top: 18px;
  flex-wrap: wrap;
}
.memchip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--text2);
  border: 1px dashed var(--border-2);
  border-radius: 8px;
  padding: 5px 10px;
}
.examples {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 14px;
}
.ex {
  border: 1px solid var(--border);
  background: var(--panel);
  color: var(--text2);
  border-radius: 20px;
  padding: 7px 14px;
  font-size: 12.5px;
  cursor: pointer;
}
.ex:hover {
  background: var(--hover);
  color: var(--text);
}
.recent-demo {
  width: 100%;
  max-width: 680px;
  margin-top: 42px;
}
.rd-head {
  font-size: 13px;
  font-weight: 700;
  margin-bottom: 12px;
}
.rd-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
}
@media (max-width: 760px) {
  .rd-grid {
    grid-template-columns: 1fr;
  }
}
.rd-card {
  border: 1px solid var(--border);
  background: var(--panel);
  border-radius: 12px;
  padding: 14px;
  cursor: pointer;
}
.rd-card:hover {
  background: var(--hover);
}
.rd-card .t {
  font-weight: 600;
  font-size: 13px;
  display: flex;
  align-items: center;
  gap: 7px;
}
.rd-card .d {
  color: var(--text2);
  font-size: 12px;
  margin-top: 7px;
}
/* ===== screening (target picker → rubric → ranking) =====================
   A picking surface, so it takes the app's wide-workspace layout (.pad >
   .pad-inner, like the talent pool) rather than the sourcing hero's centred
   card. Its state is carried by counts, pills and a progress rule — never by
   prose. */
.scr-shell {
  display: flex;
  flex-direction: column;
  gap: 14px;
  height: 100%;
  min-height: 0;
}

/* --- the way to begin, under the hero question (sourcing's composer sits in
       the same place). Screening starts from files, so the archive target is
       what occupies it — same width as that composer, so the two modes open
       with one shape at two jobs. --- */
.scr-sources {
  display: flex;
  flex-direction: column;
  gap: 14px;
  width: 100%;
  max-width: 592px;
  /* Its own air under the question, rather than the 24px every hero shares:
     the target is a large object and sitting it that close read as one block
     with the heading. Set here, not on the shared hero, so the sourcing home
     is untouched. */
  margin: 18px auto 0;
}
/* Screening people already in the product: the other way in, and a narrower
   one. A line of text, not a second panel — the screen holds ONE box, the
   archive target, and framing this door too made the two read as equal
   choices. Weight is what says which is the main move. */
.scr-alt {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  width: 100%;
  padding: 8px 12px;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
}
/* The arrow belongs to the words: together they read as somewhere to go
   rather than as a setting to pick. */
.scr-alt-line {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text2);
  transition: color 0.15s;
}
.scr-alt:hover .scr-alt-line {
  color: var(--text);
}
.scr-alt-go {
  transition: transform 0.15s;
}
.scr-alt:hover .scr-alt-go {
  transform: translateX(2px);
}
@media (prefers-reduced-motion: reduce) {
  .scr-alt,
  .scr-alt-go {
    transition: none;
  }
  .scr-alt:hover .scr-alt-go {
    transform: none;
  }
}

/* --- source toggle sits in the toolbar row, like every other list surface --- */
.scr-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: none;
}
.scr-seg {
  display: inline-flex;
  padding: 2px;
  border: 1px solid var(--border);
  border-radius: 9px;
  background: var(--panel);
}
.scr-seg button {
  padding: 5px 14px;
  border: 0;
  border-radius: 7px;
  background: none;
  color: var(--text2);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
}
.scr-seg button:hover {
  color: var(--text);
}
.scr-seg button.active {
  background: var(--elev);
  color: var(--text);
  box-shadow: var(--shadow);
}
.scr-toolbar-hint {
  font-size: 12px;
  color: var(--muted);
}

/* --- the step body fills what's left; the panes scroll, the page doesn't --- */
.scr-step {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.scr-picker {
  display: grid;
  grid-template-columns: 300px minmax(0, 1fr);
  gap: 12px;
  flex: 1;
  min-height: 0;
}
.scr-rail {
  display: flex;
  flex-direction: column;
  min-height: 0;
  border: 1px solid var(--border);
  background: var(--panel);
  border-radius: 13px;
  padding: 6px;
}
.scr-rail .pos-scroll {
  overflow-y: auto;
  min-height: 0;
}

.scr-pane {
  flex: 1;
  min-height: 0;
  overflow: auto;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--panel-2);
}
.scr-pane-head {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
  background: var(--panel-2);
}
.scr-empty {
  padding: 28px 16px;
  text-align: center;
  font-size: 12.5px;
  color: var(--muted);
}

/* --- the one table shape, used by both the picker and the results --- */
/* Two or three columns spread across a 1400px pane pushes the name and its
   verdict to opposite edges. Hold the content to a readable measure and let
   the pane keep the whitespace. */
.scr-table {
  width: 100%;
  max-width: 1080px;
  border-collapse: collapse;
  font-size: 13px;
}
.scr-table th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--panel-2);
  text-align: left;
  font-size: 11px;
  font-weight: 600;
  color: var(--muted);
  padding: 9px 10px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.scr-table td {
  padding: 7px 10px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.scr-table tbody tr {
  cursor: pointer;
}
.scr-table tbody tr:hover {
  background: var(--hover);
}
.scr-table tbody tr.sel {
  background: var(--accent-tint);
}
/* A candidate who missed a gate can't be ranked back up — recede, don't hide. */
.scr-table tbody tr.gated {
  opacity: 0.6;
}
.scr-table .c-check {
  width: 34px;
}
.scr-table .c-check input {
  accent-color: var(--accent);
  cursor: pointer;
}
.scr-table .c-rank {
  width: 40px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.scr-table .c-state,
.scr-table .c-gates {
  width: 116px;
}
.scr-table .c-score {
  width: 92px;
}
.scr-score {
  display: flex;
  align-items: center;
  gap: 8px;
}
.scr-score b {
  font-size: 14px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  min-width: 22px;
}
/* Avatar sizing is per-surface in this app (.crow .av, .cc-av, .d-av) — an
   unsized wrapper lets .av-img's width:100% expand to the source image. */
.scr-av {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--active);
  color: var(--text2);
  display: grid;
  place-items: center;
  font-size: 10.5px;
  font-weight: 700;
  flex: none;
  overflow: hidden;
}
.scr-table .who {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
}
.scr-table .who-t {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.scr-table .who-t .n {
  font-weight: 600;
  font-size: 12.5px;
}
.scr-table .who-t .o {
  font-size: 11.5px;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.scr-pill {
  display: inline-block;
  font-size: 10.5px;
  font-weight: 600;
  border-radius: 999px;
  padding: 2px 8px;
  border: 1px solid var(--border-2);
  color: var(--text2);
  white-space: nowrap;
}
.scr-pill.ok {
  background: var(--active);
  color: var(--text);
}
.scr-pill.dim {
  border-style: dashed;
  color: var(--muted);
}

/* --- criteria step: the rubric conversation --- */
.scr-criteria {
  gap: 14px;
}
/* One column until there is a rubric to sit beside the conversation. */
.scr-crit-cols {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(0, 760px);
  /* One column reads as a column, not as a page pinned to its left edge. */
  justify-content: center;
  gap: 18px;
}
.scr-crit-cols.split {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  justify-content: stretch;
}
.scr-chat,
.scr-rubric-col {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 0;
}
/* The opening prompt and its examples, as one block — the hero's own shape,
   held to the hero's own measure. The glow (.scr-ai-atmosphere) is sized off
   THIS box, not off the pane: the four lobes are percentages of their parent
   while the blur that softens them is a fixed 13px, so a parent twice as wide
   turns a haze into a hard yellow field. Same box, same haze. */
.scr-chat-open {
  position: relative;
  isolation: isolate;
  width: 100%;
  max-width: 725px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
/* Everything real rides above the wash; only the glow sits under. */
.scr-chat-open > :not(.ai-atmosphere) {
  position: relative;
  z-index: 1;
}
/* The question sits on the composer it is asking about — one block with it,
   the way the hero's title sits on the hero's composer. */
.scr-chat-open .bigtitle-convo {
  margin: 0 0 2px;
  justify-content: center;
}
/* Two different things share the screen — a conversation and the rubric it is
   writing — so a rule separates them instead of whitespace alone. */
.scr-crit-cols.split .scr-rubric-col {
  border-left: 1px solid var(--border);
  padding-left: 24px;
}
/* The criteria scroll, and the run button scrolls with them: it belongs to the
   rubric, not to the page. */
.scr-rubric-scroll {
  flex: 1;
  min-height: 0;
  overflow: auto;
}
/* Directly under the last criterion — near enough to read as "and go", far
   enough not to look like another row of the list. No rule above it: the end
   of the criteria is already the boundary. */
.scr-rubric-foot {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
  padding: 16px 0 4px;
}
/* A run that would not start states why on the left, beside the button that
   refused. */
.scr-rubric-foot .admin-err {
  margin: 0 auto 0 0;
}
/* The transcript scrolls; the composer stays put at the bottom. */
.scr-chat-scroll {
  flex: 1;
  min-height: 0;
  overflow: auto;
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding-right: 4px;
}
/* Nothing said yet: the composer sits in the middle of the pane, the way the
   sourcing hero opens, instead of hugging the floor of an empty screen. */
.scr-chat.empty {
  justify-content: center;
}
.scr-chat.empty .scr-chat-scroll {
  flex: 0 0 auto;
}
/* A pasted job description is one message — let it scroll inside its bubble
   instead of pushing the whole conversation off screen. */
.scr-chat .msg.user .bubble {
  max-height: 190px;
  overflow: auto;
  white-space: pre-wrap;
}
/* The openers reuse the hero's .examples / .ex chips verbatim. */
.scr-lab {
  margin: 0;
  font-size: 10.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--muted);
}
.scr-field {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel-2);
  color: var(--text);
  font: inherit;
  font-size: 12.5px;
  padding: 7px 10px;
}
.scr-field:focus-visible {
  outline: none;
  border-color: var(--border-2);
}
.scr-field:disabled {
  opacity: 0.6;
}

.scr-rubric {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.scr-crit-list {
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.scr-crit-row {
  display: flex;
  align-items: center;
  gap: 6px;
}
.scr-crit-add {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 9px;
  border: 1px dashed var(--border-2);
  border-radius: 8px;
  background: none;
  color: var(--text2);
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
}
.scr-crit-add:hover {
  background: var(--hover);
  color: var(--text);
}
.scr-dims {
  display: flex;
  flex-direction: column;
}
/* Each criterion is one block: name + weight, its share, then what it means.
   Without the divider the share bar reads as an underline on the sentence
   below it. */
.scr-dim {
  padding: 10px 0 12px;
  border-bottom: 1px solid var(--border);
}
.scr-dim:first-child {
  padding-top: 2px;
}
.scr-dim:last-of-type {
  border-bottom: 0;
}
.scr-dim-head {
  display: flex;
  align-items: center;
  gap: 10px;
}
.scr-dim-label {
  flex: 1;
  min-width: 0;
}
/* The share is the whole point of the slider — keep it fixed-width so the
   numbers stay comparable as they change. */
.scr-dim-pct {
  min-width: 38px;
  text-align: right;
  font-size: 12px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
/* A short control beside its number, not a lime rail across the pane. */
.scr-dim-range {
  flex: none;
  width: 104px;
  accent-color: var(--text2);
}
.scr-dim-bar {
  display: block;
  height: 2px;
  margin-top: 8px;
  border-radius: 2px;
  background: var(--border);
  overflow: hidden;
}
.scr-dim-bar i {
  display: block;
  height: 100%;
  background: var(--text2);
  border-radius: 2px;
}
.scr-dim-desc {
  margin: 8px 0 0;
  font-size: 11.5px;
  line-height: 1.6;
  color: var(--muted);
}

/* --- the cost of pressing the button, stated beside it (see .scr-rubric-foot:
       the run belongs with the rubric it runs, not at the foot of the page) --- */
.scr-credits {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--text2);
  font-variant-numeric: tabular-nums;
}
.scr-credits .sep {
  color: var(--muted);
}
.scr-credits.low {
  color: var(--credit-low);
}
.scr-credits.empty {
  color: var(--credit-empty);
  font-weight: 600;
}

/* --- the run + its ranking, one surface --- */
.scr-session {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: auto;
  padding: 18px 32px 28px;
}
.scr-session-head {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
}
.scr-count {
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
/* Progress is a rule that fills, not a percentage anyone has to read. */
.scr-bar {
  flex: 1;
  height: 3px;
  border-radius: 2px;
  background: var(--border);
  overflow: hidden;
}
.scr-bar i {
  display: block;
  height: 100%;
  background: var(--accent);
  transition: width 240ms ease-out;
}
@media (prefers-reduced-motion: reduce) {
  .scr-bar i {
    transition: none;
  }
}

/* --- archive upload: dropzone, then what was found inside it --- */
/* Dropping an archive is the whole screen, but it is not the whole WIDTH: a
   dashed box stretched wall to wall reads as the page's border rather than as
   something to drop onto, and the label ends up marooned in the middle of a
   very long line. Held to a readable measure and centred instead. */
.scr-upload {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  width: 100%;
}
/* Nothing uploaded yet: the target sits in the middle of the empty screen,
   because it is the only thing to do — and held to a readable measure, since a
   dashed box stretched wall to wall reads as the page's border. Once an
   archive is in, the roster fills the pane like every other list in the app;
   holding IT to 560px is what made a verified batch look like a stray card
   floating at the top of an empty screen. */
.scr-upload:has(.screening-drop) {
  gap: 12px;
  max-width: 560px;
  margin: 0 auto;
  justify-content: center;
}
.screening-drop {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  /* Tall enough to read as a drop target, not as a toolbar. */
  min-height: 180px;
  border: 1.5px dashed var(--border-2);
  border-radius: 12px;
  background: transparent;
  color: var(--text2);
  padding: 28px 24px;
  cursor: pointer;
  font-family: inherit;
  transition: border-color 0.15s, background 0.15s;
}
.screening-drop:hover,
.screening-drop.over {
  border-color: var(--text2);
  background: var(--hover);
  color: var(--text);
}
.screening-drop:disabled {
  opacity: 0.5;
  cursor: default;
}
/* The same target as the hero of the screening home, where it is the only
   thing on the screen and has to carry it. */
.screening-drop.hero {
  min-height: 208px;
  border-radius: 16px;
  background: var(--panel-2);
  box-shadow: var(--shadow);
  gap: 10px;
}
/* The mark scales with the panel — at list size it reads as a stray glyph in
   the middle of a large empty box. */
.screening-drop.hero > .ico {
  width: 26px;
  height: 26px;
  margin-bottom: 2px;
}
.screening-drop.hero:hover,
.screening-drop.hero.over {
  background: var(--elev);
}
.screening-drop.hero .screening-drop-title {
  font-size: 15px;
}
.screening-drop-title {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text);
}
.screening-drop-hint {
  font-size: 12px;
  color: var(--muted);
}
/* What the archive turned out to hold wears the picker's roster shape (.roster
   → .roster-head → .roster-tbl), so the two ways of choosing who gets screened
   are one screen with two sources rather than two screens. Only what the
   roster has no concept of lives here: the archive's name, the count against
   the ceiling, and the step's own two buttons. */
/* The archive the count came out of. Attached to the heading with a middot
   rather than boxed beside it: a bordered pill next to a bold number reads as
   a second control on the line, and this one is a label. */
.scr-intake-src {
  min-width: 0;
  flex: 0 1 auto;
  color: var(--muted);
  font-size: 12px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.scr-intake-src::before {
  content: "·";
  margin-right: 7px;
}
/* The step's actions sit on the head line, where the picker's roster carries
   its own trailing controls. */
.scr-intake-act {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 8px;
}
/* The count against the ceiling IS the rule — when it goes over, it says so
   by turning, and the next button goes dead. No sentence needed. */
/* Said only when the ceiling is actually in play. */
/* The roster before the archive has been read into one: the columns that are
   coming, over rows that are not there yet. Same head, same row height as the
   table it becomes, so the read finishing fills these rather than replacing
   them and shifting the page. */
.scr-skel-bar {
  display: inline-block;
  height: 10px;
  border-radius: 4px;
  /* NOT --panel-2: it is pure white on light, the same as the table under it,
     which renders the whole silhouette invisible — the trap the outreach
     editor's skeleton already had to work around. --border-2 is the one step
     off the surface that exists in both themes. */
  background: var(--border-2);
  animation: scr-skel-pulse 1.5s ease-in-out infinite;
}
.scr-skel-bar.av {
  width: 22px;
  height: 22px;
  border-radius: 50%;
}
.scr-skel-bar.nm {
  width: 92px;
}
.scr-skel-bar.file {
  width: 168px;
}
.scr-skel-bar.pill {
  width: 44px;
  height: 18px;
  border-radius: 999px;
}
/* Three rows reading as one object, not three things loading in sequence. */
.scr-skel:nth-child(2) .scr-skel-bar {
  animation-delay: 0.15s;
}
.scr-skel:nth-child(3) .scr-skel-bar {
  animation-delay: 0.3s;
}
@keyframes scr-skel-pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.45;
  }
}
@media (prefers-reduced-motion: reduce) {
  .scr-skel-bar {
    animation: none;
  }
}
/* The submitted file names, in the roster's secondary voice — they are what
   the recruiter checks the parse against, not the row's subject. */
.scr-intake-files {
  color: var(--text2);
  font-size: 12px;
  overflow-wrap: anywhere;
}
.scr-intake-statecol {
  width: 110px;
}
/* People past the ceiling are shown, not hidden — the recruiter should see
   who would be dropped. */
.roster-tbl tbody tr.over {
  opacity: 0.45;
}
.scr-intake-error {
  margin: 0;
  padding: 0 20px 10px;
  font-size: 12.5px;
  color: var(--credit-empty);
}
/* A roster row opens the person's papers, so it is focusable — which hands it
   the browser's own blue focus ring, sitting behind the modal it just opened
   and reading as a second selection the recruiter did not make. Suppressed,
   then repainted on :focus-visible in the app's own ink, like .cand-row: a
   keyboard user still sees where they are, a mouse user sees nothing. */
.roster-tbl tbody tr[role="button"]:focus {
  outline: none;
}
.roster-tbl tbody tr[role="button"]:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: -2px;
}

/* --- submitted documents, full screen -----------------------------------
   Reading what someone sent is the widest thing this step does: an A4 page at
   a legible size plus its own file list. So the modal takes the window rather
   than the dossier's 780px measure.

   The height is DEFINITE (not max-height): a PDF is shown in the browser's own
   viewer, and an <iframe> in an auto-height column collapses to its 150px
   intrinsic default — the document arrives as a letterbox strip. Every link in
   the chain below therefore passes a real height down to the frame. */
.modal.docm {
  max-width: min(1100px, 94vw);
  height: 92vh;
  max-height: 92vh;
}
.modal.docm .modal-body {
  /* .modal is the column flex container; claiming the leftover height here is
     what gives the viewer something to fill. */
  flex: 1;
  min-height: 0;
  padding: 0;
  /* The viewers scroll themselves — a scrolling body would double the bars. */
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
/* One tab per submitted file, on the app's standard underline tabs (.d-tabs)
   rather than a row of pills — the same grammar the criteria versions use, so
   "which of these am I looking at" reads the same everywhere. */
.docm-tabs {
  flex: none;
  display: flex;
  gap: 2px;
  padding: 0 22px;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
  overflow-x: auto;
  scrollbar-width: none;
}
.docm-tabs::-webkit-scrollbar {
  display: none;
}
.docm-tab {
  flex: none;
  display: inline-flex;
  align-items: center;
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  padding: 9px 11px;
  font-family: inherit;
  font-size: 13px;
  color: var(--muted);
  cursor: pointer;
  white-space: nowrap;
}
.docm-tab:hover,
.docm-tab:focus-visible {
  color: var(--text);
  outline: none;
}
.docm-tab.on {
  color: var(--text);
  font-weight: 600;
  border-bottom-color: var(--text);
}
.docm-tab-nm {
  max-width: 260px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.docm-doc {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
/* Said only when what is on screen is NOT the document — a .docx shows the
   transcript extraction produced, and that difference is worth one line. */
.docm-note {
  flex: none;
  margin: 0;
  padding: 9px 22px;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
  color: var(--text2);
  font-size: 12px;
}
/* The browser's own PDF viewer, given the whole body. */
.docm-frame {
  flex: 1;
  min-height: 0;
  width: 100%;
  border: 0;
  background: var(--panel);
}
.docm-img {
  flex: 1;
  min-height: 0;
  width: 100%;
  object-fit: contain;
  background: var(--panel);
  padding: 18px;
}
/* Text formats keep a reading measure instead of stretching to 1100px. */
.docm-text,
.docm-pre {
  flex: 1;
  min-height: 0;
  overflow: auto;
  padding: 24px 28px;
}
.docm-text .md {
  max-width: 76ch;
  margin: 0 auto;
}
.docm-pre {
  margin: 0;
  font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 12.5px;
  line-height: 1.7;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
/* Nothing this browser can show. Naming the file and handing it over IS the
   answer, so it gets the whole pane rather than a corner of one. */
.docm-none {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 24px;
  color: var(--text2);
  text-align: center;
}
.docm-none b {
  font-size: 14px;
  color: var(--text);
  overflow-wrap: anywhere;
}
.docm-none p {
  margin: 0;
  font-size: 12.5px;
}

/* --- session: what they were measured against, beside who came out where ---
   The rubric is the argument the ranking makes, so the two stay on screen
   together. A band across the top loses the criteria the moment you scroll
   the table, and spreads each claim across the whole window; one column holds
   them at a readable measure and gives the bars a shared scale. */
/* Both classes: .candpane declares the column flex layout further down the
   sheet, so a bare .scr-results would lose to it. */
.candpane.scr-targets,
.candpane.scr-outreach,
.candpane.scr-results {
  flex: 1 1 auto;
}
.candpane.scr-results {
  display: grid;
  grid-template-columns: minmax(0, 340px) minmax(0, 1fr);
}
/* 선별 대상 stage: the set that was screened, read-only and full width — the
   rubric has nothing to say about who was put in. */
.candpane.scr-targets,
/* 아웃리치 stage: one column, no rubric rail. Past the ranking the criteria
   have done their work and the question is the conversation. */
  .candpane.scr-outreach {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}
.chipbtn.scr-target-upload {
  cursor: default;
}
.chipbtn.scr-target-upload:hover {
  background: transparent;
  color: var(--text2);
}
.scr-crit-side {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  padding: 14px 18px 16px;
  border-right: 1px solid var(--border);
}
/* The criteria scroll on their own — reading the rubric must never move the
   ranking, and vice versa. */
.scr-crit-scroll {
  flex: 1;
  min-height: 0;
  overflow: auto;
  /* The weights sit hard against the column's right edge, which is exactly
     where the scrollbar appears — without this gutter the bar rides on top of
     "35%". The track is reserved whether or not it is in use, so the rubric
     does not shift sideways the moment it grows past one screen. */
  padding-right: 10px;
  scrollbar-gutter: stable;
}
.scr-results-main {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}
/* Too narrow to hold two columns: the rubric goes back over the table, capped
   so it can never push the ranking off screen. */
@media (max-width: 1100px) {
  .candpane.scr-results {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
  }
  .scr-crit-side {
    border-right: 0;
    border-bottom: 1px solid var(--border);
    max-height: 34vh;
  }
}
/* One header line, packed left: the section's name, the runs to switch
   between (only once there is more than one), then what the open run is.
   Never space-between — spread across a wide screen the three stop reading as
   one header. Wraps rather than crushing when the pane is narrow. */
.scr-crit-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px 14px;
  margin-bottom: 8px;
}
.scr-crit-head .scr-vers {
  margin-bottom: 0;
}
.scr-crit-title {
  margin: 0;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text);
}
/* What the open run is: when its rubric was fixed. Secondary to the criteria,
   but still meant to be read — this line answers "what am I looking at". */
.scr-crit-meta {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 12.5px;
  color: var(--text2);
  font-variant-numeric: tabular-nums;
}
/* Beside the title, and pushed to the column's right edge: the section is one
   thing and the open run's facts are another, so they sit at opposite ends of
   the same line rather than running together. */
.scr-crit-head .scr-crit-meta {
  margin-left: auto;
}
/* Versions on the app's standard underline tabs — and nothing else on the
   rail. The tabs and the criteria under them share one left edge; the criteria
   modal's own gutter would push the first version off it. */
.scr-crit-side .scr-vers {
  padding: 0;
  /* Spacing between versions is the gap, never side padding: an indicator that
     runs wider on one side than the other reads as a mis-aligned label. */
  gap: 18px;
  /* The rail carries no rule of its own — the column's own border closes it. */
  border-bottom: 0;
  /* Runs accumulate with every re-score. Past the fourth the rail is wider
     than the column, so it scrolls sideways instead of wrapping into a block
     of tabs or shoving the header apart. No visible scrollbar: it would sit
     under the underline indicator and read as a second, broken rule. */
  flex: none;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
  margin-bottom: 10px;
}
.scr-crit-side .scr-vers::-webkit-scrollbar {
  display: none;
}
.scr-crit-side .crit-tab {
  flex: none;
  white-space: nowrap;
}
/* A run is a thing you pick, so an unpicked one has to look unpicked — but
   still like something you may click. --muted reads as disabled next to a
   heading. */
.scr-vers .crit-tab {
  font-size: 13px;
  /* Shallow, so the underline sits close to the label instead of floating a
     row below the heading it shares a line with. */
  padding: 4px 0;
  font-variant-numeric: tabular-nums;
  color: var(--text2);
  font-weight: 500;
}
.scr-vers .crit-tab:hover:not(.active) {
  color: var(--text2);
}
.scr-vers .crit-tab.active {
  color: var(--text);
  font-weight: 700;
}

/* Heaviest criterion first: the list IS the ranking's own priorities. One
   criterion is one block — rank, name, share, the bar, then the claim — so it
   reads top-down instead of across three columns of headers. */
.rubric-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.rubric-item {
  padding: 13px 0 15px;
  border-bottom: 1px solid var(--border);
}
.rubric-item:first-child {
  padding-top: 2px;
}
.rubric-item:last-child {
  border-bottom: 0;
}
.rubric-head {
  display: flex;
  align-items: baseline;
  gap: 9px;
}
/* Position in the priority order, stated once and quietly. */
.rubric-rank {
  flex: none;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  min-width: 12px;
}
.rubric-label {
  flex: 1;
  min-width: 0;
  font-size: 13.5px;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.rubric-share {
  flex: none;
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
/* Full width, so the criteria compare against each other rather than against
   a stub of a column. Monochrome — the weight is a fact, not the key action. */
.rubric-bar {
  display: block;
  height: 3px;
  margin: 8px 0 9px;
  background: var(--border);
  border-radius: 2px;
  overflow: hidden;
}
.rubric-bar i {
  display: block;
  height: 100%;
  background: var(--text2);
}
.rubric-desc {
  margin: 0;
  padding-left: 21px;
  font-size: 12.5px;
  color: var(--muted);
  line-height: 1.6;
}
/* Beside a ranking the column is narrow, so the claim gets the room and the
   ornament goes: the rank number is redundant next to a share, and the block
   tightens up to fit five criteria without scrolling. */
.scr-crit-side .rubric-item {
  padding: 10px 0 12px;
}
.scr-crit-side .rubric-rank {
  display: none;
}
/* The claim is what a criterion MEANS — beside the ranking it is the column's
   whole reason for being there, so it is read, not skimmed past. */
.scr-crit-side .rubric-desc {
  padding-left: 0;
  font-size: 12px;
  color: var(--text2);
}

/* One column per criterion: the number, and how far along the scale it sits.
   The evidence rides on the cell's tooltip; the full assessment is one row
   click away.

   The criteria ARE the comparison, so they get the width: a fixed layout
   hands every criterion the same share instead of letting an elastic name
   column swallow the middle of the table and strand 적합도 far from the person
   it belongs to. */
.roster-tbl.rk-rubric {
  table-layout: fixed;
  /* Fixed layout ignores min-width on cells, so the floor lives on the table.
     The number itself is set per-render from the criterion count (see
     CandidateRoster) — two criteria and eight need different room, and the
     roster scrolls sideways rather than shaving every column thin. */
  min-width: 860px;
}
/* 적합도 is the verdict the criteria add up to, so it sits between the person
   and the first criterion rather than crowding the criteria — the name column
   gives up the slack it was hoarding. */
.roster-tbl.rk-rubric .rk-namecol {
  width: 16%;
}
/* The verdict column reads as one chip, centred in its own column: the live
   badge is wider than the score it replaces, so anchoring either one to the
   left edge leaves the other looking shoved sideways. Centring holds both in
   the same place. */
.roster-tbl.rk-rubric .rk-fitcol,
.roster-tbl.rk-rubric td.rk-fit {
  width: 14%;
  text-align: center;
}
/* The badge carries a left margin for its usual inline home; centred in a
   column it would sit 8px off. */
.rk-fit .badge.evaluating,
.rk-fit .badge.unassessed {
  margin: 0;
}
/* A run that produced nothing for this person. Muted rather than red: the
   applicant did not fail anything, the analysis did — it is an absence to
   follow up, not a verdict against them. */
.rk-fit .badge.unassessed {
  color: var(--muted);
  border-color: var(--border);
  background: transparent;
  font-weight: 500;
}
.roster-tbl.rk-rubric .rk-nm {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.roster-tbl th.rk-dim {
  white-space: normal;
  line-height: 1.3;
}
/* The number alone. A bar per criterion turns the table into a thicket of
   rules that compete with the scores themselves; the numbers are already on a
   common 0-100 scale and read faster side by side. */
.rk-dim-v {
  font-size: 12.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  cursor: help;
}
/* Confidence is in the ink: a weak read is quieter than a verified one. */
.rk-dim-v.weak {
  opacity: 0.45;
}
.rk-dim-v.likely {
  opacity: 0.75;
}
.rk-dim-na {
  color: var(--muted);
  cursor: help;
}

/* The run's own line: it fills, then it is gone. */
.scr-run {
  flex: none;
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 20px;
  border-bottom: 1px solid var(--border);
  font-size: 11.5px;
  color: var(--muted);
  overflow: hidden;
}
.scr-run-fill {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  background: var(--accent-tint);
  transition: width 0.4s ease;
}
.scr-run-text {
  position: relative;
}
/* The row's own live state, matching the strip above it. */
.scr-pill.live {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--text2);
}

/* ===== session pipeline (stepper strip above the session workspaces) ===== */
.sview {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}
.sstep-strip {
  flex: none;
  padding: 12px 32px 0;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
}
.sstep {
  position: relative;
  display: flex;
  align-items: flex-start;
  max-width: 820px;
  margin: 0 auto;
}
/* The shared current-stage underbar. JS seats it under the aria-current node;
   left/width transition is what makes a stage switch read as movement. */
.sstep-bar {
  position: absolute;
  bottom: 0;
  height: 2.5px;
  border-radius: 2px;
  background: var(--accent);
  opacity: 0;
  pointer-events: none;
  transition: left 0.22s cubic-bezier(0.22, 0.61, 0.36, 1), width 0.22s
    cubic-bezier(0.22, 0.61, 0.36, 1), opacity 0.15s ease;
}
.sstep-cell {
  display: flex;
  align-items: flex-start;
}
.sstep-cell + .sstep-cell {
  flex: 1;
}
/* The process rail sits at the icon circles' vertical center. Its visible
   stroke reaches beneath each node's quiet side padding so it reads as one
   flow, not several short rules floating between buttons. */
.sstep-conn {
  flex: 1;
  min-width: 48px;
  position: relative;
  height: 2px;
  margin-top: 17px;
}
.sstep-conn::before {
  content: "";
  position: absolute;
  top: 0.5px;
  left: -24px;
  right: -24px;
  height: 1px;
  border-radius: 999px;
  background: var(--step-flow-rest);
  opacity: 0.85;
  transition:
    top 0.22s ease, height 0.22s ease, opacity 0.22s ease,
    background 0.22s ease, box-shadow 0.22s ease;
}
.sstep-conn.reached::before {
  top: 0;
  height: 2px;
  background: linear-gradient(
    90deg,
    var(--step-flow-start),
    var(--step-flow-end)
  );
  box-shadow: var(--step-flow-glow);
  opacity: 1;
}
.sstep-conn.todo::before {
  opacity: 0.52;
}
@media (prefers-reduced-motion: reduce) {
  .sstep-conn::before {
    transition: none;
  }
}
.sstep-node {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  min-width: 104px;
  padding: 4px 14px 9px;
  background: none;
  border: 0;
  border-radius: 10px;
  color: inherit;
  font: inherit;
  cursor: pointer;
}
/* Hover: no block highlight — a clickable stage gets a soft lime halo around
   the icon, a lifted label, and a muted underbar previewing the tab bar. */
.sstep-node:not(.todo):not(.marker):not(:disabled):hover
  .sstep-dot {
  box-shadow: 0 0 0 5px var(--accent-tint);
}
.sstep-node:not(.todo):not(.marker):not(:disabled):hover
  .sstep-lbl {
  color: var(--text);
}
.sstep-node:not(.todo):not(.marker):not(:disabled):not(
    .here
  ):hover::after {
  content: "";
  position: absolute;
  left: 22%;
  right: 22%;
  bottom: 0;
  height: 2.5px;
  border-radius: 2px;
  background: var(--border-2);
}
/* Stage icon in a key-color circle; the count sits on its corner as a small
   badge (.sstep-badge). Iconless nodes print the count in the circle. */
.sstep-dot {
  position: relative;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--elev);
  border: 1px solid var(--border-2);
  color: var(--accent-mark);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  transition: box-shadow 0.15s ease, border-color 0.18s ease, color 0.18s ease;
}
.sstep-node.reached .sstep-dot {
  background: var(--accent);
  border-color: transparent;
  color: var(--on-accent);
}
.sstep-badge {
  position: absolute;
  top: -5px;
  right: -7px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 8px;
  background: var(--heading);
  color: var(--panel);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 9.5px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  /* A panel-color ring separates the badge from the circle it overlaps. */
  box-shadow: 0 0 0 1.5px var(--panel);
}
/* The count rolls inside the existing badge; the badge itself only breathes
   once, just enough for peripheral recognition. */
.sstep-badge:has(> .rolling-number.is-changing),
.sstep-dot:has(> .rolling-number.is-changing) {
  animation: sstep-count-pop 360ms cubic-bezier(0.22, 0.61, 0.36, 1);
}
@keyframes sstep-count-pop {
  48% {
    transform: scale(1.1);
  }
}
.sstep-lbl {
  font-size: 12.5px;
  color: var(--text2);
  white-space: nowrap;
  transition: color 0.15s ease;
}
/* The view being shown: emphasized label + a key-color tab bar underneath —
   no rings. */
.sstep-node.here .sstep-lbl {
  color: var(--text);
  font-weight: 700;
}
.sstep-node.todo,
.sstep-node.marker,
.sstep-node:disabled {
  cursor: default;
}
/* A stage still waiting on its input: hollow badge behind a dashed connector,
   keeping its count so the strip still says how much is waiting there. */
.sstep-node.todo .sstep-dot {
  background: transparent;
  border: 1.5px dashed var(--border-2);
  color: var(--muted);
}
.sstep-node.todo .sstep-lbl {
  color: var(--muted);
}
@media (max-width: 720px) {
  .sstep-strip {
    padding: 8px 12px 0;
  }
  .sstep-node {
    min-width: 0;
    padding: 4px 8px 8px;
  }
  .sstep-conn {
    min-width: 20px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .rolling-number.is-changing::before {
    display: none;
    animation: none;
  }
  .rolling-number.is-changing .rolling-number-value,
  .credit-pill:has(.credit-roll.is-changing),
  .sstep-badge:has(> .rolling-number.is-changing),
  .sstep-dot:has(> .rolling-number.is-changing) {
    animation: none;
  }
}

/* -- saved roster (관심 후보 view): flat table + multi-select ------------- */
.roster {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.roster-empty {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  padding: 40px;
  text-align: center;
}
.roster-head {
  flex: none;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 20px 10px;
  /* Tall enough for the selection badge from the start — its appearance must
     not nudge the table below by a pixel. */
  min-height: 41px;
}
.roster-head b {
  font-size: 13px;
}
.roster-selbadge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 19px;
  height: 19px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--on-accent);
  font-size: 11.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.roster-scroll {
  flex: 1;
  min-height: 0;
  overflow: auto;
  /* Room for the floating selection bar — the last rows must stay clickable
     while it is up. */
  padding-bottom: 76px;
}
.roster-tbl {
  width: 100%;
  border-collapse: collapse;
}
/* A column head has to be readable at a glance — it is the only label the
   number under it ever gets. */
.roster-tbl th {
  position: sticky;
  top: 0;
  z-index: 1;
  text-align: left;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text2);
  padding: 9px 12px;
  background: var(--bg);
  border-bottom: 1px solid var(--border-2);
}
.roster-tbl td {
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.roster-tbl tbody tr {
  cursor: pointer;
}
.roster-tbl tbody tr:hover {
  background: var(--hover);
}
.roster-tbl tbody tr.sel,
.roster-tbl tbody tr.sel:hover {
  background: var(--accent-tint);
}
/* The checkbox column opens the table on the same left edge as the header
   line above it — `.roster-tbl th/td` would otherwise win on specificity and
   start the table 8px inside everything else. */
.roster-tbl .rk-cell {
  width: 46px;
  padding-left: 20px;
}
/* A roster with nothing to select has no checkbox column, so its first and
   last cells carry the gutter instead — otherwise the table runs flush into
   both edges of the pane. Same 20px the header line above it sits on. */
.roster-tbl.rk-readonly th:first-child,
.roster-tbl.rk-readonly td:first-child {
  padding-left: 20px;
}
.roster-tbl.rk-readonly th:last-child,
.roster-tbl.rk-readonly td:last-child {
  padding-right: 20px;
}
/* Native checkbox restyled to the lime selection language. */
.rk-check {
  appearance: none;
  -webkit-appearance: none;
  width: 16px;
  height: 16px;
  margin: 0;
  border-radius: 4px;
  border: 1.5px solid var(--border-2);
  background: var(--panel-2);
  display: inline-grid;
  place-content: center;
  cursor: pointer;
}
.rk-check:checked {
  background: var(--accent);
  border-color: var(--accent-mark);
}
.rk-check:checked::after {
  content: "";
  width: 9px;
  height: 9px;
  background: var(--on-accent);
  clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
}
.rk-check:disabled {
  opacity: 0.4;
  cursor: default;
}
.roster-name {
  display: flex;
  align-items: center;
  gap: 10px;
}
.rk-av {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--hover);
  border: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  color: var(--text2);
  flex: none;
  overflow: hidden;
}
.rk-nm {
  display: block;
  font-weight: 600;
  line-height: 1.3;
}
.rk-co {
  display: block;
  font-size: 12px;
  color: var(--text2);
}
.rk-mailcol {
  width: 34%;
}
.rk-mail {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 12.5px;
  color: var(--text2);
  word-break: break-all;
}
.rk-nomail {
  color: var(--muted);
  font-size: 12.5px;
}
/* Widened roster (saved view): the Talent Pool profile column set rides
   along, so the table keeps a floor width and the wrapper scrolls sideways
   instead of squishing nine columns. */
.roster-tbl.rk-full {
  min-width: 960px;
}
.roster-tbl.rk-full .rk-mailcol {
  width: auto;
}
.rk-cd {
  font-size: 12.5px;
  color: var(--text2);
  max-width: 180px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rk-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.roster-tbl th.rk-num {
  text-align: right;
}
.candidate-roster td.rk-num::after,
.outreach-roster td.rk-num::after {
  content: "↑↓";
  visibility: hidden;
  display: inline-block;
  margin-left: 2px;
  font-size: 10px;
  letter-spacing: -0.12em;
}
.btn-accent {
  background: var(--accent);
  color: var(--on-accent);
}
.btn-accent:hover {
  opacity: 0.92;
}
.roster-compose {
  margin-left: auto;
}

/* -- outreach composer (관심 후보 → 메시지 작성) -------------------------- */
.compose {
  flex: 1;
  display: grid;
  grid-template-columns: 264px 1fr;
  min-height: 0;
}
.compose-rail {
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-right: 1px solid var(--border);
  background: var(--panel);
}
.compose-rail-head {
  flex: none;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
}
.compose-rail-list {
  flex: 1;
  min-height: 0;
  overflow: auto;
}
.compose-rcpt {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 14px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
}
/* The identity area doubles as the preview selector. */
.compose-rcpt-btn {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0;
  background: none;
  border: 0;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.compose-rcpt:hover {
  background: var(--hover);
}
.compose-rcpt.cur,
.compose-rcpt.cur:hover {
  background: var(--accent-tint);
}
.compose-rcpt.sent {
  opacity: 0.75;
}
.compose-rcpt-id {
  flex: 1;
  min-width: 0;
}
.compose-rcpt-mail {
  display: block;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 11px;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.compose-rm {
  opacity: 0;
}
.compose-rcpt:hover .compose-rm,
.compose-rm:focus-visible {
  opacity: 1;
}
.compose-chip {
  flex: none;
  font-size: 11px;
  font-weight: 600;
  border-radius: 999px;
  padding: 2px 8px;
}
.compose-chip.ok {
  background: var(--accent);
  color: var(--on-accent);
}
.compose-chip.bad {
  background: var(--credit-empty-bg);
  border: 1px solid var(--credit-empty-border);
  color: var(--credit-empty);
}
.compose-chip.mut {
  background: var(--hover);
  color: var(--text2);
}
.compose-chip.ink {
  background: var(--text);
  color: var(--bg);
}
.compose-chip.dash {
  background: transparent;
  border: 1px dashed var(--border-2);
  color: var(--muted);
}
.rk-stagecol {
  width: 132px;
}
.rk-actionscol {
  width: 336px;
  white-space: nowrap;
}
.roster-row-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 5px;
}
.candidate-roster-actions .rk-actionscol {
  width: 280px;
}
.candidate-roster-actions .roster-row-actions {
  justify-content: flex-start;
}
.candidate-roster-actions .rk-namecol {
  width: 16%;
}
.roster-row-action {
  appearance: none;
  border: 1px solid var(--border-2);
  border-radius: 7px;
  background: var(--panel);
  color: var(--text2);
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-height: 28px;
  padding: 4px 7px;
  font: inherit;
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  transition: background 140ms ease, border-color 140ms ease, color 140ms ease;
}
.roster-row-action:hover {
  background: var(--hover);
  border-color: var(--text2);
  color: var(--text);
}
.roster-row-action.in-pool,
.roster-row-action.in-pool:hover {
  /* Like the detail panel's added state, membership is carried by the mark
     itself. The button chrome stays neutral so a saved person does not read
     as a second primary action. */
  color: var(--text2);
  border-color: var(--border-2);
  background: var(--panel);
}
.roster-row-action.in-pool:hover {
  color: var(--text);
  background: var(--hover);
}
.roster-row-action.in-pool .ico {
  color: var(--text);
}
.roster-row-action.in-pool .ico svg {
  fill: var(--accent);
}
.roster-row-action-icon {
  width: 28px;
  padding: 0;
  justify-content: center;
}
/* The shortlist action is a saved bookmark rather than a destructive trash
   control: it reads as an active state, and toggles that state off on click. */
.roster-row-action.shortlisted {
  color: var(--text2);
  border-color: var(--border-2);
  background: var(--panel);
}
.roster-row-action.shortlisted:hover {
  color: var(--text);
  border-color: var(--text2);
  background: var(--hover);
}
.roster-row-action.shortlisted .ico {
  color: var(--text);
}
.roster-row-action.shortlisted .ico svg {
  fill: var(--accent);
}
/* Portalled above the table scroller, so an icon action's description never
   clips against the table's overflow boundary. */
.action-tooltip-trigger {
  display: inline-flex;
}
.action-tooltip {
  position: fixed;
  z-index: 120;
  transform: translate(-50%, -100%);
  width: max-content;
  max-width: calc(100vw - 24px);
  padding: 6px 8px;
  border: 1px solid var(--border-2);
  border-radius: 6px;
  background: var(--elev);
  box-shadow: var(--shadow);
  color: var(--text);
  font-size: 11.5px;
  font-weight: 500;
  line-height: 1.2;
  white-space: nowrap;
  overflow-wrap: normal;
  word-break: keep-all;
  pointer-events: none;
}
.action-tooltip.bottom {
  transform: translate(-50%, 0);
}
/* Last-send column: a date, so it never needs more than its own width. */
.rk-outcol {
  width: 104px;
  font-variant-numeric: tabular-nums;
}
/* Score cell — the home table's gauge + number. The gauge is inline-block
   with its own trailing margin, so the cell stays a real table cell. */
.rk-fit {
  width: 104px;
  white-space: nowrap;
}
.rk-fit .gauge {
  vertical-align: middle;
}
.rk-fit b {
  font-size: 12.5px;
  font-weight: 650;
  vertical-align: middle;
  font-variant-numeric: tabular-nums;
}

/* composer — a LARGE centered popup over the page (not a full-screen page
   swap): bulk-compose on step 1, per-person review/send on step 2. Primary
   action always lives top-right in the header; back/close top-left. */
.ocmp-overlay {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: var(--scrim);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 3vh 3vw;
}
.ocmp {
  --ocmp-rail-width: 280px;
  width: min(1240px, 100%);
  height: min(860px, 100%);
  min-width: 0;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  border: 1px solid var(--border-2);
  border-radius: 14px;
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}
.ocmp-head {
  flex: none;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 22px;
  border-bottom: 1px solid var(--border);
}
.ocmp-sub {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--text2);
  font-size: 12.5px;
}
.ocmp-recipient-stack {
  display: inline-flex;
  align-items: center;
}
.ocmp-recipient-avatar {
  width: 16px;
  min-width: 16px;
  max-width: 16px;
  height: 16px;
  min-height: 16px;
  max-height: 16px;
  border: 1px solid var(--bg);
  border-radius: 50%;
  background: var(--active);
  color: var(--text2);
  display: grid;
  place-items: center;
  flex: 0 0 16px;
  overflow: hidden;
  font-size: 7px;
  font-weight: 700;
}
.ocmp-recipient-avatar + .ocmp-recipient-avatar {
  margin-left: -6px;
}
/* 1 메시지 작성 → 2 검토·발송 step indicator */
.ocmp-steps {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-left: 8px;
}
.ocmp-steps .st {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
}
.ocmp-steps .st .n {
  width: 17px;
  height: 17px;
  border-radius: 50%;
  border: 1px solid var(--border-2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 10.5px;
  font-variant-numeric: tabular-nums;
}
.ocmp-steps .st.on {
  color: var(--text);
}
.ocmp-steps .st.on .n {
  background: var(--accent);
  border-color: var(--accent-mark);
  color: var(--on-accent);
}
.ocmp-steps .sep {
  width: 18px;
  height: 1px;
  background: var(--border-2);
}
.ocmp-head-right {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 12px;
}
.ocmp-head-right .hint {
  font-size: 12px;
  color: var(--muted);
}
/* Standard dialog chrome: ← far left (review), ✕ far right — icon buttons,
   not labeled ghosts. */
.ocmp-backbtn {
  margin-right: 2px;
}
.ocmp-x {
  margin-left: 2px;
}
/* ---- step 1: settings rail + centered editor ---- */
.ocmp-compose {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: var(--ocmp-rail-width) minmax(0, 1fr);
}
.ocmp-settings {
  border-right: 1px solid var(--border);
  background: var(--panel);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.ocmp-field {
  display: flex;
  flex-direction: column;
  gap: 7px;
}
.f-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--muted);
}
/* Rail section labels must read as headings, not fine print — the rail IS
   the popup's control surface (채널/언어/작성 방식/채용 정보). */
.ocmp-settings .f-label {
  font-size: 12px;
  font-weight: 700;
  color: var(--text);
}
/* Rail buttons size to their text like everywhere else in the popup — a
   column child would otherwise stretch full width and read as a banner. */
.ocmp-settings .btn {
  align-self: flex-start;
}
.seg-label {
  font-size: 12px;
  color: var(--muted);
}
.ocmp-seg {
  display: inline-flex;
  border: 1px solid var(--border-2);
  border-radius: 8px;
  overflow: hidden;
  align-self: flex-start;
}
.ocmp-seg button {
  border: 0;
  background: var(--panel-2);
  color: var(--text2);
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  padding: 5px 12px;
  cursor: pointer;
}
.ocmp-seg button.on {
  background: var(--text);
  color: var(--bg);
}
/* 보냄으로 표시 after it has been pressed: the same button, now reading 기록
   취소. It has to look pressed-in rather than spent — a disabled-looking undo
   is the thing the recruiter is trying to click. The dashed edge says "this is
   a state you can still leave", which a solid one would not. */
.btn.ocmp-marked {
  border-style: dashed;
  color: var(--text2);
}
.btn.ocmp-marked:hover:not(:disabled) {
  color: var(--text);
  border-style: solid;
}
/* A channel that exists but is not offered yet (see CHANNELS in
   OutreachComposer): dimmed in place, so it reads as coming rather than as
   never having been there. Scoped to an ENABLED rail — while a draft is
   generating the whole fieldset is disabled, and that is a different state
   that must not look like this one. */
.ocmp-railset:enabled .ocmp-seg button:disabled {
  opacity: 0.45;
  cursor: default;
}
/* ---- ONE field skin for every control in the popup ----------------------
   Two sizes only: compact controls (rail selects, inline inputs) and writing
   surfaces (subject/body). They share border, ground, radius scale and focus
   so the rail, the review meta rows and the editor never read as three
   different form systems. Below, each element overrides ONLY what genuinely
   differs (mono address, widths, min-heights). */
.ocmp-tplsel,
.ocmp-instructions,
.ocmp-rewrite-inst,
.ocmp-namer input,
.ocmp-job-field input,
.ocmp-toentry input,
.ocmp-issue input {
  border: 1px solid var(--border-2);
  border-radius: 8px;
  background: var(--panel-2);
  color: var(--text);
  font: inherit;
  font-size: 12.5px;
  padding: 7px 10px;
}
.ocmp-subject,
.ocmp-psubject,
.ocmp-bodyedit,
.ocmp-pbody {
  border: 1px solid var(--border-2);
  border-radius: 10px;
  background: var(--panel-2);
  color: var(--text);
  font: inherit;
  font-size: 13.5px;
}
.ocmp-subject,
.ocmp-psubject {
  font-weight: 600;
  padding: 9px 13px;
}
.ocmp-bodyedit,
.ocmp-pbody {
  resize: vertical;
  line-height: 1.75;
  padding: 12px 14px;
}
.email-editor.ocmp-bodyedit,
.email-editor.ocmp-pbody {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 0;
  resize: none;
  overflow: visible;
}
/* One focus signal for every field — a control that does not answer focus
   reads as disabled. */
.ocmp-tplsel:focus,
.ocmp-instructions:focus,
.ocmp-rewrite-inst:focus,
.ocmp-namer input:focus,
.ocmp-job-field input:focus,
.ocmp-toentry input:focus,
.ocmp-issue input:focus,
.ocmp-subject:focus,
.ocmp-psubject:focus,
.ocmp-bodyedit:focus,
.ocmp-pbody:focus {
  outline: none;
  border-color: var(--text2);
}
.email-editor.ocmp-bodyedit:focus,
.email-editor.ocmp-pbody:focus {
  border-color: var(--border-2);
}
.email-editor-toolbar {
  position: relative;
  min-height: 42px;
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 6px 8px;
  border-bottom: 1px solid var(--border);
  background: color-mix(in srgb, var(--panel-2) 88%, var(--bg));
  border-radius: 9px 9px 0 0;
}
.email-editor-toolgroup {
  display: inline-flex;
  align-items: center;
  gap: 2px;
}
.email-editor-tool {
  width: 29px;
  height: 29px;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--text2);
  display: inline-grid;
  place-items: center;
  cursor: pointer;
  font: inherit;
  font-size: 12px;
  line-height: 1;
}
.email-editor-tool:hover:not(:disabled) {
  background: var(--panel);
  color: var(--text);
}
.email-editor-tool.on {
  background: var(--soft);
  color: var(--text);
}
.email-editor-tool:disabled {
  opacity: 0.3;
  cursor: default;
}
.email-editor-tool .ico {
  width: 15px;
  height: 15px;
}
.email-editor-underline {
  text-decoration: underline;
  text-underline-offset: 2px;
}
.email-editor-redo {
  transform: scaleX(-1);
}
.email-editor-divider {
  width: 1px;
  height: 18px;
  margin: 0 2px;
  background: var(--border);
}
.email-editor-spacer {
  flex: 1;
}
.email-editor-linkbox {
  position: absolute;
  z-index: 4;
  top: calc(100% + 6px);
  left: 8px;
  width: min(360px, calc(100% - 16px));
  display: flex;
  gap: 6px;
  padding: 8px;
  border: 1px solid var(--border-2);
  border-radius: 9px;
  background: var(--panel);
  box-shadow: var(--shadow-lg);
}
.email-editor-linkbox input {
  min-width: 0;
  flex: 1;
  border: 1px solid var(--border-2);
  border-radius: 6px;
  background: var(--panel-2);
  color: var(--text);
  font: inherit;
  font-size: 12px;
  padding: 6px 8px;
  outline: none;
}
.email-editor-linkbox button {
  border: 1px solid var(--border);
  border-radius: 6px;
  background: transparent;
  color: var(--text2);
  font: inherit;
  font-size: 11.5px;
  font-weight: 700;
  padding: 5px 8px;
  cursor: pointer;
}
.email-editor-linkbox button.primary {
  background: var(--text);
  border-color: var(--text);
  color: var(--bg);
}
.email-editor-content {
  flex: 1;
  min-height: 0;
  overflow: auto;
}
.email-editor-content .ProseMirror {
  min-height: 100%;
  padding: 14px 16px;
  outline: none;
  color: var(--text);
  font: inherit;
  line-height: 1.7;
}
.email-editor-content .ProseMirror p {
  margin: 0 0 0.8em;
}
.email-editor-content .ProseMirror p:last-child {
  margin-bottom: 0;
}
.email-editor-content .ProseMirror ul,
.email-editor-content .ProseMirror ol,
.ocmp-richtext ul,
.ocmp-richtext ol {
  margin: 0.4em 0 0.85em;
  padding-left: 1.6em;
}
.email-editor-content .ProseMirror ul,
.ocmp-richtext ul {
  list-style: disc;
}
.email-editor-content .ProseMirror ol,
.ocmp-richtext ol {
  list-style: decimal;
}
.email-editor-content .ProseMirror a,
.ocmp-richtext a {
  color: var(--accent-ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.email-editor-content
  .ProseMirror:has(> p:only-child > br.ProseMirror-trailingBreak)::before {
  content: attr(data-placeholder);
  color: var(--muted);
  pointer-events: none;
  float: left;
  height: 0;
}
.ocmp-tplsel {
  width: 100%;
}
/* Small print inside the popup: every hint reads the same, everywhere. */
.ocmp .hint {
  font-size: 11.5px;
  line-height: 1.55;
  color: var(--muted);
}
.ocmp-fieldrow {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
/* Name + save ride one row, same grammar as every other action row here. */
.ocmp-namer {
  display: flex;
  align-items: center;
  gap: 6px;
}
.ocmp-namer input {
  flex: 1;
  min-width: 0;
}
.ocmp-namer .btn {
  flex: none;
  align-self: center;
}
/* Free-text AI instructions (추가 지시) — small but genuinely typeable. */
.ocmp-instructions {
  width: 100%;
  min-height: 64px;
  resize: vertical;
  line-height: 1.55;
}
.ocmp-instructions::placeholder {
  color: var(--muted);
}
/* A second labeled group inside the same rail field (AI로 템플릿 만들기 등). */
.ocmp-sublabel {
  margin-top: 12px;
}
.ocmp-ai-fail {
  font-size: 12px;
  color: var(--credit-empty);
}
/* Sender identity (이름/직위/소속) under the persona toggle — always
   visible, unboxed (unlike the collapsible job-facts card below it). */
.ocmp-sender-fields {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 8px;
}
/* Shared job-facts form (지원 회사 etc.) — one value for every recipient.
   Plain and unboxed, same as every other optional field in the rail (the
   sender-fields group right above it): these are inputs, not a card. */
.ocmp-job {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 8px;
}
.ocmp-sender-fields input[aria-invalid="true"],
.ocmp-job input[aria-invalid="true"] {
  border-color: var(--credit-empty-border);
}
.ocmp-job-field {
  display: flex;
  flex-direction: column;
  gap: 3px;
  font-size: 11.5px;
  color: var(--muted);
}
/* Template↔preview toggle on the left, per-person nav (once previewing) on
   the right — channel/language/seat already show in the rail, so this row
   no longer repeats them as chips. */
.ocmp-srcrow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
}
/* Rail section break. */
.ocmp-divider {
  height: 1px;
  background: var(--border);
  margin: 2px 0;
}
/* 작성 방식 seg spans the rail — it is the rail's headline decision. */
.ocmp-modeseg {
  align-self: stretch;
  display: flex;
}
.ocmp-modeseg button {
  flex: 1;
}
/* Optional job facts: a native checkbox states the condition directly. The
   label shares the exact rail-heading type used by channel/language/role. */
.ocmp-job-option {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  align-self: flex-start;
  cursor: pointer;
}
.ocmp-job-check {
  appearance: none;
  -webkit-appearance: none;
  width: 15px;
  height: 15px;
  margin: 0;
  border: 1.5px solid var(--border-2);
  border-radius: 4px;
  background: var(--panel-2);
  display: inline-grid;
  place-content: center;
  flex: none;
  cursor: pointer;
}
.ocmp-job-check:checked {
  border-color: var(--accent-mark);
  background: var(--accent);
}
.ocmp-job-check:checked::after {
  content: "";
  width: 8px;
  height: 8px;
  background: var(--on-accent);
  clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
}
.ocmp-job-check:focus-visible {
  outline: 2px solid var(--text2);
  outline-offset: 2px;
}
.ocmp-optional {
  font-size: 10.5px;
  font-weight: 500;
  color: var(--muted);
}
/* Inline To-line address entry (review step). */
.ocmp-toentry {
  width: min(440px, 100%);
  display: flex;
  align-items: center;
  gap: 6px;
}
.ocmp-toentry input {
  width: auto;
  min-width: 0;
  flex: 1;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
}
/* Review card header: whose message, plus the skip toggle. */
.ocmp-pcard-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.ocmp-pname {
  font-size: 14px;
}
/* ---- notice boxes: one shape for every strip in the popup --------------
   Slot notice, per-person blocker, AI evidence and the lint strip differ
   only in their colour role — never in geometry. */
.ocmp-slotbox,
.ocmp-issue,
.ocmp-evidence,
.ocmp-lint {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  border-radius: 10px;
  padding: 9px 13px;
  font-size: 12.5px;
}
/* Unfilled-slot notice WITH its fix — the fill button rides the hint. */
.ocmp-slotbox {
  border: 1px dashed var(--accent-mark);
  background: var(--accent-tint);
  color: var(--text);
}
.ocmp-slotbox .btn {
  margin-left: auto;
  flex: none;
}
/* Quiet secondary path (LinkedIn↔email switch) — a text link, not a button. */
.ocmp-minor {
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  font-size: 12px;
  color: var(--text2);
  cursor: pointer;
  text-decoration: underline dashed;
  text-underline-offset: 3px;
}
.ocmp-minor:hover {
  color: var(--text);
}
/* Review-step rewrite controls: style + prompt + go, one quiet row. */
.ocmp-rewrite {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 10px;
}
.ocmp-rewrite .ocmp-tplsel {
  flex: 1;
  min-width: 0;
}
.ocmp-rewrite-inst {
  flex: 2;
  min-width: 0;
}
.ocmp-rewrite .btn {
  flex: none;
}
.ocmp-editor {
  min-width: 0;
  overflow: auto;
  padding: 22px 28px 28px;
}
.ocmp-editor-inner {
  width: min(760px, 100%);
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.ocmp-bodyedit {
  min-height: 340px;
}
/* The rail's one action — full-width so it reads as THE next step. */
.ocmp-generate {
  width: 100%;
  justify-content: center;
  text-align: center;
}
.ocmp-previewsel {
  max-width: 160px;
}
.ocmp-fromsel {
  max-width: 260px;
}
/* Substituted per-person preview: read-only sheet in the editor's place. */
.ocmp-preview {
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--panel);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 340px;
}
.ocmp-preview-subject {
  font-weight: 700;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
}
.ocmp-preview-body {
  white-space: pre-wrap;
  font-size: 14.5px;
  line-height: 1.6;
}
.ocmp-preview-body:has(.ocmp-richtext) {
  white-space: normal;
}
.ocmp-richtext p {
  margin: 0 0 0.85em;
}
.ocmp-richtext p:last-child {
  margin-bottom: 0;
}
.ocmp-preview-placeholder {
  color: var(--muted);
  font-weight: 400;
}
.ocmp-preview-variable {
  color: var(--accent-ink);
  font-weight: 700;
}
/* AI-generation cover replaces the live editor: a green/lime glow (see
   .ocmp-ai-atmosphere) plus skeleton lines (.ocmp-gen-skeleton) typing in
   behind it, so the wait reads as "writing your message" rather than a
   generic spinner. */
.ocmp-editor-loading {
  position: relative;
  min-height: 462px;
  display: grid;
  place-items: center;
  overflow: hidden;
  isolation: isolate;
}
/* Sits BEHIND the glow (z-index 0), not in front of it — the lines read as
   content the AI is typing, glimpsed through the ambient wash rather than
   competing with it for attention. Each line fills in left-to-right, one
   after another (subject, then each body line), like a cursor typing it
   out, instead of just fading in as a block. */
.ocmp-gen-skeleton {
  position: absolute;
  z-index: -1;
  inset: 56px 64px auto 64px;
  display: flex;
  flex-direction: column;
  gap: 13px;
  pointer-events: none;
}
.ocmp-gen-line {
  position: relative;
  height: 11px;
  width: 88%;
  border-radius: 6px;
  /* Lighter than the subject bar — content, not the headline. */
  background: color-mix(in srgb, var(--text) 11%, transparent);
  clip-path: inset(0 100% 0 0);
  /* Types in once and stays typed — no fade-out loop. Runs forward only
     (fill-mode forwards), so once revealed a line holds instead of
     vanishing and re-typing, which read as pointless busywork. Slow —
     a real generation run takes longer than the earlier pacing assumed. */
  animation: ocmp-gen-type 1.5s ease-out forwards;
}
.ocmp-gen-line.subject {
  width: 44%;
  /* Taller than a body line (still the headline bar), but the SAME tint —
     size is what marks it as the subject, not a darker color. Extra margin
     below separates it from the body block as its own group. */
  height: 20px;
  border-radius: 5px;
  margin-bottom: 14px;
}
.ocmp-gen-line.short {
  width: 55%;
}
/* Marks the second paragraph's opening line — a bit more separation than
   the regular line-to-line gap so the two blocks read as separate
   paragraphs, not one long run of lines. */
.ocmp-gen-line.para {
  margin-top: 10px;
}
/* Sign-off block — "감사합니다 / 전지호 드림"-shaped: two short lines, much
   narrower than a body line, not just the "short" body-line width. */
.ocmp-gen-line.sign {
  width: 30%;
}
.ocmp-gen-line.sign.narrow {
  width: 20%;
}
.ocmp-gen-line.subject {
  animation-delay: 0s;
}
.ocmp-gen-line:nth-child(2) {
  animation-delay: 2.1s;
}
.ocmp-gen-line:nth-child(3) {
  animation-delay: 4.2s;
}
.ocmp-gen-line:nth-child(4) {
  animation-delay: 6.3s;
}
.ocmp-gen-line:nth-child(5) {
  animation-delay: 8.4s;
}
.ocmp-gen-line:nth-child(6) {
  animation-delay: 10.5s;
}
.ocmp-gen-line:nth-child(7) {
  animation-delay: 12.6s;
}
.ocmp-gen-line:nth-child(8) {
  animation-delay: 14.7s;
}
.ocmp-gen-line:nth-child(9) {
  animation-delay: 16.8s;
}
.ocmp-gen-line:nth-child(10) {
  animation-delay: 18.9s;
}
@keyframes ocmp-gen-type {
  0% {
    clip-path: inset(0 100% 0 0);
  }
  100% {
    clip-path: inset(0 0% 0 0);
  }
}
@media (prefers-reduced-motion: reduce) {
  .ocmp-gen-line {
    animation: none;
    clip-path: inset(0 0% 0 0);
  }
}
.ocmp-loading-status {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  pointer-events: none;
}
.ocmp-loading-status .ai-mark {
  width: 44px;
  height: 44px;
  flex: none;
}
.ocmp-gen-label {
  margin: 0;
  font-size: 16px;
  font-weight: 650;
  color: var(--text);
  text-shadow: 0 1px 12px var(--bg);
}
/* Light backgrounds wash the glow and the skeleton bars out — turn the
   glow up and the skeleton down so each stays legible against white. */
[data-theme="light"] .ocmp-ai-atmosphere.is-active {
  opacity: 0.8;
}
[data-theme="light"] .ocmp-gen-line {
  background: color-mix(in srgb, var(--text) 7%, transparent);
}
@keyframes ocmp-dust-green {
  0%,
  100% {
    opacity: 0.56;
    transform: translate(-8px, 34px) scale(0.9);
  }
  50% {
    opacity: 0.92;
    transform: translate(16px, -28px) scale(1.08);
  }
}
@keyframes ocmp-dust-lime {
  0%,
  100% {
    opacity: 0.52;
    transform: translate(10px, 46px) scale(0.88);
  }
  50% {
    opacity: 0.84;
    transform: translate(-18px, -36px) scale(1.06);
  }
}
@keyframes ocmp-dust-soft {
  0%,
  100% {
    opacity: 0.42;
    transform: translate(-12px, 30px) scale(0.96);
  }
  50% {
    opacity: 0.72;
    transform: translate(12px, -22px) scale(1.12);
  }
}
@media (prefers-reduced-motion: reduce) {
  .ocmp-dust-layer {
    animation: none;
  }
}

.ocmp-vars {
  display: flex;
  align-items: center;
  gap: 7px;
  flex-wrap: wrap;
}
.ocmp-var {
  border: 1px solid var(--border-2);
  background: var(--panel-2);
  border-radius: 999px;
  padding: 3px 10px;
  font-size: 11.5px;
  font-weight: 600;
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  color: var(--text2);
  cursor: pointer;
}
.ocmp-var:hover {
  background: var(--hover);
  color: var(--text);
}
.ocmp-var:disabled,
.ocmp-var:disabled:hover {
  opacity: 0.45;
  cursor: default;
  background: var(--panel-2);
  color: var(--text2);
}
/* Chosen full-draft variant — key color. */
.ocmp-var.on {
  background: var(--accent-tint);
  border-color: var(--accent-mark);
  color: var(--accent-ink);
  font-family: inherit;
}
/* Preview-nav cluster (◀ person ▶ · n/N). */
.ocmp-preview-nav {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.ocmp-lint {
  color: var(--text2);
  border: 1px solid var(--border);
  border-left: 3px solid var(--border-2);
  background: var(--panel);
}

/* ---- step 2: recipient rail + per-person review ---- */
.ocmp-review {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: var(--ocmp-rail-width) minmax(0, 1fr);
}
.ocmp-queue {
  border-right: 1px solid var(--border);
  background: var(--panel);
  overflow: auto;
  padding: 12px 10px;
}
.ocmp-triage {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 8px 10px;
  flex-wrap: wrap;
}
.tri {
  font-size: 11.5px;
  font-weight: 600;
  border-radius: 999px;
  padding: 3px 10px;
  border: 1px solid var(--border-2);
  background: var(--panel-2);
  color: var(--text2);
  font-variant-numeric: tabular-nums;
}
.tri.ok {
  background: var(--accent-tint);
  border-color: var(--accent-mark);
  color: var(--accent-ink);
}
.tri.warn {
  background: var(--credit-low-bg);
  border-color: var(--credit-low-border);
  color: var(--credit-low);
}
.ocmp-queue-label {
  font-size: 10.5px;
  letter-spacing: 0.1em;
  color: var(--muted);
  font-weight: 600;
  padding: 0 8px 8px;
}
.ocmp-qrow {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 9px;
  border: 0;
  border-radius: 8px;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  padding: 8px 10px;
  cursor: pointer;
  margin-bottom: 2px;
}
.ocmp-qrow:hover {
  background: var(--hover);
}
.ocmp-qrow.on {
  background: var(--accent-tint);
}
.ocmp-qrow.skip .rk-nm {
  color: var(--muted);
  text-decoration: line-through;
}
.ocmp-qdot {
  flex: none;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 1.5px solid var(--border-2);
  background: var(--panel-2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--on-accent);
  font-size: 10px;
  font-weight: 700;
}
.ocmp-qdot.sent,
.ocmp-qdot.reviewed {
  background: var(--accent);
  border-color: var(--accent-mark);
}
.ocmp-qdot.warn {
  border-color: var(--credit-low-border);
  background: var(--credit-low-bg);
  color: var(--credit-low);
}
.ocmp-qdot.excluded {
  background: var(--hover);
}
.ocmp-qid {
  min-width: 0;
  flex: 1;
}
.ocmp-qorg {
  display: block;
  font-size: 11px;
  color: var(--muted);
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.ocmp-review-main {
  min-width: 0;
  min-height: 0;
  overflow: auto;
  display: flex;
  flex-direction: column;
}
.ocmp-pcard {
  width: min(720px, 100%);
  margin: 0 auto;
  padding: 24px 28px 28px;
  display: flex;
  flex-direction: column;
  gap: 16px;
  flex: 1;
}
.ocmp-pcard .ocmp-pcard-head {
  padding-bottom: 2px;
}
.ocmp-empty {
  align-items: center;
  justify-content: center;
  color: var(--muted);
  display: flex;
  flex: 1;
}
.ocmp-meta {
  display: grid;
  gap: 0;
  padding: 4px 0;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  font-size: 12.5px;
}
.ocmp-meta .r {
  display: grid;
  grid-template-columns: 80px minmax(0, 1fr);
  align-items: center;
  gap: 14px;
  min-height: 44px;
  padding: 6px 0;
}
.ocmp-meta .k {
  color: var(--muted);
  font-weight: 600;
  font-size: 11.5px;
}
.ocmp-to-control {
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
}
.ocmp-meta .v.mono {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 12px;
  color: var(--text2);
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.ocmp-liurl {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--accent-ink);
  text-decoration: underline dashed;
  text-underline-offset: 3px;
}
.ocmp-psubject {
  width: 100%;
  min-width: 0;
}
/* Per-person blocker/warning strip (no email · recent contact) — resolved
   inline: convert to LinkedIn or enter an address. */
.ocmp-issue {
  border: 1px solid var(--credit-low-border);
  background: var(--credit-low-bg);
  color: var(--credit-low);
}
.ocmp-issue input {
  background: var(--bg);
  width: 210px;
}
.ocmp-pbody {
  min-height: 280px;
  padding: 16px;
  line-height: 1.65;
  resize: vertical;
}
.ocmp-pact {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.ocmp-pact-right {
  margin-left: auto;
  display: inline-flex;
  gap: 8px;
}
.ocmp-variants {
  display: flex;
  align-items: center;
  gap: 7px;
}
/* Per-candidate AI evidence line under the review actions */
.ocmp-evidence {
  color: var(--text2);
  border: 1px dashed var(--border-2);
}
/* Full-draft cards — the Messages tab's om-card grammar inside the popup;
   the draft currently in use carries the key color on its border. */
.ocmp-drafts {
  display: grid;
  gap: 10px;
}
.ocmp-drafts .om-card.on {
  border-color: var(--accent-mark);
}
.ocmp-sendall {
  flex: none;
  position: sticky;
  bottom: 0;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 22px;
  border-top: 1px solid var(--border);
  background: var(--panel);
  font-size: 12px;
  color: var(--text2);
}
.ocmp-sendall-recent {
  color: var(--credit-low);
  font-weight: 600;
}
/* Mailbox-connect gate — the popup's own sticky footer, self-contained so it
   cannot inherit stray layout from other compose surfaces. */
.ocmp-gate {
  flex: none;
  position: sticky;
  bottom: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 22px;
  border-top: 1px solid var(--credit-low-border);
  background: var(--credit-low-bg);
  color: var(--credit-low);
  font-size: 12.5px;
}
.ocmp-gate > span {
  /* Icon and text sit together on the left; only the button floats right. */
  flex: none;
  min-width: 0;
}
.ocmp-gate .btn {
  flex: none;
  white-space: nowrap;
  margin-left: auto;
}
.ocmp-gate svg {
  flex: none;
}
@media (max-width: 900px) {
  .ocmp-compose {
    grid-template-columns: 1fr;
  }
  .ocmp-settings {
    border-right: 0;
    border-bottom: 1px solid var(--border);
    max-height: 40vh;
  }
  .ocmp-review {
    grid-template-columns: 1fr;
  }
  .ocmp-queue {
    max-height: 180px;
    border-right: 0;
    border-bottom: 1px solid var(--border);
  }
  .ocmp-pcard {
    padding: 18px 20px 24px;
  }
  .ocmp-meta .r {
    grid-template-columns: 72px minmax(0, 1fr);
    gap: 10px;
  }
}
.compose-none {
  padding: 20px 14px;
  color: var(--muted);
  font-size: 12.5px;
}
.compose-main {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}
.compose-row {
  flex: none;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 20px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
}
.compose-row .k {
  flex: none;
  width: 72px;
  font-size: 12.5px;
  color: var(--muted);
}
.compose-subject {
  flex: 1;
  border: 0;
  outline: none;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-weight: 600;
}
.compose-account {
  max-width: 320px;
  background: var(--panel);
  border: 1px solid var(--border-2);
  border-radius: 7px;
  padding: 4px 8px;
  color: var(--text);
  font: inherit;
  font-size: 12.5px;
}
.compose-account-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--border-2);
  background: var(--panel);
  border-radius: 999px;
  padding: 2px 10px;
  font-size: 12.5px;
}
.compose-account-chip svg {
  color: var(--accent-mark);
}
.compose-body {
  flex: 1;
  min-height: 140px;
  resize: none;
  border: 0;
  outline: none;
  background: transparent;
  color: var(--text);
  padding: 14px 20px;
  font: inherit;
  line-height: 1.7;
}
.compose-preview {
  flex: none;
  margin: 0 20px 12px;
  border: 1px dashed var(--border-2);
  border-radius: 8px;
  padding: 10px 12px;
  font-size: 12.5px;
  color: var(--text2);
  white-space: pre-wrap;
  max-height: 120px;
  overflow: auto;
}
.compose-preview-k {
  display: block;
  font-size: 11px;
  font-weight: 600;
  color: var(--muted);
  margin-bottom: 4px;
}
.compose-foot {
  flex: none;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 20px;
  border-top: 1px solid var(--border);
}
.compose-foot .hint {
  font-size: 12px;
  color: var(--muted);
}
.compose-foot-right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 10px;
}
.compose-done {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--accent-ink);
}
.compose-gate {
  flex: none;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 20px;
  border-top: 1px solid var(--credit-low-border);
  background: var(--credit-low-bg);
  color: var(--credit-low);
  font-size: 13px;
}
.compose-gate > span {
  flex: 1;
}
@media (max-width: 980px) {
  .compose {
    display: flex;
    flex-direction: column;
  }
  .compose-rail {
    flex: none;
    max-height: 180px;
    border-right: 0;
    border-bottom: 1px solid var(--border);
  }
}

/* ===== sourcing split ===== */
.split {
  flex: 1;
  display: grid;
  grid-template-columns: clamp(300px, var(--cw, 380px), 62%) 1fr;
  min-width: 0;
  min-height: 0;
  position: relative;
}
.pane-resizer {
  position: absolute;
  top: 0;
  bottom: 0;
  left: clamp(300px, var(--cw, 380px), 62%);
  width: 11px;
  transform: translateX(-6px);
  cursor: col-resize;
  z-index: 5;
  touch-action: none;
}
.pane-resizer::before {
  content: "";
  position: absolute;
  inset: 0 5px;
  background: transparent;
  transition: background 0.15s ease;
}
.pane-resizer:hover::before,
.pane-resizer.dragging::before,
.pane-resizer:focus-visible::before {
  background: var(--text2);
}
/* Always-visible grip pill: says "this edge drags" without waiting for a
   hover. Sits above both panes; the panel-color ring lifts it off the
   border line it straddles. */
.pane-resizer::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 5px;
  height: 44px;
  border-radius: 3px;
  background: var(--border-2);
  box-shadow: 0 0 0 1.5px var(--panel);
  transition: background 0.15s ease;
}
.pane-resizer:hover::after,
.pane-resizer.dragging::after,
.pane-resizer:focus-visible::after {
  background: var(--text2);
}
.pane-resizer:focus-visible {
  outline: none;
}
@media (max-width: 980px) {
  .split {
    display: flex;
    flex-direction: column;
  }
  .convo {
    flex: 0 0 44%;
    border-right: 0;
    border-bottom: 1px solid var(--border);
  }
  .candpane {
    flex: 1 1 auto;
  }
  .pane-resizer {
    display: none;
  }
}
.convo {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  border-right: 1px solid var(--border-2);
  /* Panel tone sets the chat surface apart from the candidate workspace —
     the same chrome treatment as the sidebar. */
  background: var(--panel);
}
.convo-head {
  padding: 13px 18px 8px;
}
.convo-head .t {
  font-weight: 700;
  font-size: 13.5px;
  display: flex;
  align-items: center;
  gap: 7px;
}
.convo-head .role {
  font-size: 11.5px;
  color: var(--muted);
  margin-top: 3px;
}
.convo-scroll {
  flex: 1;
  overflow: auto;
  padding: 18px 18px;
}
/* A session with nothing said in it yet. The feed's whole area carries the
   question instead of sitting blank above the composer; the first turn
   replaces it. */
.convo-empty {
  min-height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}
/* Only the signed-in sourcing session has an overlaid composer. Public shared
   session logs reuse `.convo-scroll` but must keep their compact read-only
   spacing. */
.sourcing-convo {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  /* The chat stays neutral; its AI identity is only a barely-there dust glow
     rising from the lower edge. */
  background: var(--panel);
}
.ai-atmosphere {
  position: absolute;
  z-index: 0;
  right: 0;
  bottom: 0;
  left: 0;
  /* Compact band flush with the floor, not a tall region reaching a third
     of the way up the panel — the previous height + heavy blur + heavy
     overlap merged all 7 peaks into one indistinct wash where neither the
     shape nor its motion read at all. Tall enough (30%, not 22%) to leave
     headroom above the tallest peaks + blur + bob — at 22% the tall edge
     peaks had only ~5% of the band left above them and got clipped by this
     element's own overflow:hidden the moment they rose. */
  height: 30%;
  /* visible, not hidden — the 30% band is just where the peaks are rooted,
     not a mask on how high the bob can rise. The outer .sourcing-convo
     still clips at the panel's own edge, so this can't bleed past the chat
     column itself. */
  overflow: visible;
  pointer-events: none;
  /* Just a container now — the wave is 7 individually-animated .ai-peak
     children (see below), not one flat background moving as a block. */
  opacity: 0;
  transition: opacity 700ms ease-out;
}
/* Chat-panel-only (ancestor-scoped, not the shared .ai-atmosphere base) — a
   static wash pinned to the floor, painted BEHIND the .ai-peak spans (a
   pseudo-element always paints before its element's real children). The
   peaks bob up and down above it, but this never moves, so the very bottom
   edge is never left empty mid-cycle while they're lifted. Scoping it to
   .sourcing-convo keeps the hero and outreach glows (which reuse the same
   base class) untouched. */
.sourcing-convo .ai-atmosphere::before {
  content: "";
  position: absolute;
  right: 0;
  bottom: -20%;
  left: 0;
  height: 40%;
  background: linear-gradient(
    90deg,
    rgba(160, 232, 90, 0.24),
    rgba(223, 244, 27, 0.26),
    rgba(160, 232, 90, 0.24)
  );
  filter: blur(11px);
}
.ai-atmosphere::after {
  display: none;
}
/* All this toggles now is visibility — the peaks keep bobbing underneath
   whether or not it's shown. */
.ai-atmosphere.is-active {
  opacity: 0.95;
}
/* Verified against an actual rendered screenshot, not just spec reasoning —
   the previous pass (20% wide, blur(5px)) rendered as 7 separate polka dots
   with visible gaps, nothing like a wave. Wide (42%) and heavily blurred
   (13px) so adjacent peaks melt into one continuous, undulating ridge; the
   long transparent-at-88% falloff is what actually blends the seams. Each
   on its OWN duration/delay so they bob independently, not in lockstep. */
.ai-peak {
  position: absolute;
  bottom: -32%;
  width: 42%;
  height: 100%;
  border-radius: 50%;
  filter: blur(13px);
  /* Plain `transform`, not the individual translate/scale properties used
     elsewhere — nothing else on this element touches transform, so there's
     no reason to avoid the shorthand, and it's the safer, more universally
     supported form to animate in @keyframes. */
  transform: translateY(0);
  animation: ai-peak-bob 4s ease-in-out infinite;
}
.ai-peak:nth-child(1) {
  left: -10%;
  height: 92%;
  background: radial-gradient(
    ellipse 44% 74% at 50% 62%,
    rgba(160, 232, 90, 0.6) 0,
    rgba(160, 232, 90, 0.22) 50%,
    transparent 88%
  );
  animation-duration: 4.4s;
  animation-delay: 0s;
}
.ai-peak:nth-child(2) {
  left: 2%;
  height: 76%;
  background: radial-gradient(
    ellipse 44% 74% at 50% 62%,
    rgba(160, 232, 90, 0.5) 0,
    rgba(160, 232, 90, 0.18) 50%,
    transparent 88%
  );
  animation-duration: 3.6s;
  animation-delay: 0.5s;
}
.ai-peak:nth-child(3) {
  left: 16%;
  height: 40%;
  background: radial-gradient(
    ellipse 44% 74% at 50% 62%,
    rgba(223, 244, 27, 0.46) 0,
    rgba(223, 244, 27, 0.16) 50%,
    transparent 88%
  );
  animation-duration: 5.1s;
  animation-delay: 1.1s;
}
.ai-peak:nth-child(4) {
  left: 32%;
  height: 74%;
  background: radial-gradient(
    ellipse 44% 74% at 50% 62%,
    rgba(223, 244, 27, 0.56) 0,
    rgba(223, 244, 27, 0.2) 50%,
    transparent 88%
  );
  animation-duration: 4.1s;
  animation-delay: 0.2s;
}
.ai-peak:nth-child(5) {
  left: 48%;
  height: 50%;
  background: radial-gradient(
    ellipse 44% 74% at 50% 62%,
    rgba(160, 232, 90, 0.48) 0,
    rgba(160, 232, 90, 0.16) 50%,
    transparent 88%
  );
  animation-duration: 4.8s;
  animation-delay: 1.4s;
}
.ai-peak:nth-child(6) {
  left: 64%;
  height: 82%;
  background: radial-gradient(
    ellipse 44% 74% at 50% 62%,
    rgba(160, 232, 90, 0.48) 0,
    rgba(160, 232, 90, 0.16) 50%,
    transparent 88%
  );
  animation-duration: 4.2s;
  animation-delay: 0.8s;
}
.ai-peak:nth-child(7) {
  left: 78%;
  height: 92%;
  background: radial-gradient(
    ellipse 44% 74% at 50% 62%,
    rgba(223, 244, 27, 0.6) 0,
    rgba(223, 244, 27, 0.22) 50%,
    transparent 88%
  );
  animation-duration: 4.6s;
  animation-delay: 0.35s;
}
@keyframes ai-peak-bob {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    /* Confirmed against the real running app, not just a screenshot — the
       smaller amplitudes tried earlier (16-24px) were all genuinely too
       subtle to read as motion at a glance. */
    transform: translateY(-65px);
  }
}
/* In the outreach editor the status itself is the focal point, so the shared
   atmosphere gathers around it instead of rising from the panel floor. */
.ocmp-ai-atmosphere {
  top: 50%;
  right: auto;
  bottom: auto;
  left: 50%;
  /* Cancel the chat panel's individual translate/scale (composes with,
     rather than replaces, this element's own `transform` shorthand below,
     which would otherwise double up and knock the centering off). */
  translate: 0;
  scale: 1;
  /* Smaller and hazier than the hero's — this sits in a tight editor
     overlay where a big saturated cluster reads as loud, not ambient. */
  width: min(430px, 68%);
  height: 240px;
  /* Same 4-lobe layout and green/lime-only palette as the landing hero's
     glow, toned down (lower alpha, more blur) for this tighter overlay. */
  background: radial-gradient(
      ellipse 46% 40% at 52% 20%,
      rgba(223, 244, 27, 0.24) 0%,
      rgba(223, 244, 27, 0.08) 48%,
      transparent 78%
    ),
    radial-gradient(
      ellipse 30% 34% at 13% 56%,
      rgba(160, 232, 90, 0.22) 0%,
      rgba(160, 232, 90, 0.07) 48%,
      transparent 78%
    ),
    radial-gradient(
      ellipse 30% 32% at 89% 42%,
      rgba(223, 244, 27, 0.2) 0%,
      rgba(223, 244, 27, 0.06) 46%,
      transparent 76%
    ),
    radial-gradient(
      ellipse 32% 36% at 62% 82%,
      rgba(160, 232, 90, 0.22) 0%,
      rgba(160, 232, 90, 0.07) 48%,
      transparent 78%
    );
  filter: blur(15px);
}
.ocmp-ai-atmosphere::after {
  display: none;
}
.ocmp-ai-atmosphere.is-active {
  opacity: 0.62;
  transform: translate(-50%, -50%) scale(1);
  animation: ocmp-ai-cloud-breathe 4.1s ease-in-out infinite;
}
@keyframes ocmp-ai-cloud-breathe {
  0%,
  100% {
    opacity: 0.78;
    transform: translate(-52%, -47%) scale(0.95, 0.92) rotate(0deg);
  }
  50% {
    opacity: 0.96;
    transform: translate(-48%, -53%) scale(1.06, 1.08) rotate(1.4deg);
  }
}
/* Spans the title-to-composer wrapper as one piece — the composer's own
   opaque card covers the middle of it, same as the reference mockup, so
   only the parts overlapping the title and peeking around the card show. */
.home-ai-atmosphere,
.scr-ai-atmosphere {
  top: 50%;
  right: auto;
  bottom: auto;
  left: 50%;
  width: calc(100% + 80px);
  height: calc(100% + 40px);
  /* Hazy and blurred, not a flat sticker — 4 soft lobes roughly where the
     mockup put them: a big one behind the title, two mid-height at the
     sides, one low behind the composer. */
  background: radial-gradient(
      ellipse 46% 40% at 52% 20%,
      rgba(223, 244, 27, 0.42) 0%,
      rgba(223, 244, 27, 0.16) 48%,
      transparent 78%
    ),
    radial-gradient(
      ellipse 30% 34% at 13% 56%,
      rgba(160, 232, 90, 0.4) 0%,
      rgba(160, 232, 90, 0.14) 48%,
      transparent 78%
    ),
    radial-gradient(
      ellipse 30% 32% at 89% 42%,
      rgba(223, 244, 27, 0.38) 0%,
      rgba(223, 244, 27, 0.13) 46%,
      transparent 76%
    ),
    radial-gradient(
      ellipse 32% 36% at 62% 82%,
      rgba(160, 232, 90, 0.4) 0%,
      rgba(160, 232, 90, 0.14) 48%,
      transparent 78%
    );
  filter: blur(13px);
  opacity: 0.5;
  /* translate (position, keystroke-driven) and scale (continuous morph) are
     separate properties on purpose — a `transition` on one and an
     `animation` on the other can run at once without either fighting the
     other for control of a shared `transform`. */
  translate: -50% -50%;
  scale: 1 1;
  /* No bounce — a smooth, unhurried glide reads as elegant; overshoot on a
     recurring per-keystroke move just reads as jittery no matter how mild. */
  transition: translate 1100ms cubic-bezier(0.16, 1, 0.3, 1);
  animation: home-ai-morph 6.5s ease-in-out infinite;
}
.home-ai-atmosphere::after,
.scr-ai-atmosphere::after {
  display: none;
}
/* The hero's glow wraps a TITLE as well as the prompt, so it has room to
   spread; this one wraps the prompt alone and would be squeezed into a thin
   band at the same percentages. Given the hero's height back, it opens into
   the same field rather than a stripe. */
.scr-ai-atmosphere {
  height: max(calc(100% + 40px), 380px);
}
/* The hero's glow drifts as the recruiter types (.pos-N below); the rubric
   chat has no keystroke to follow, so it only breathes on the shared morph. */
.home-ai-atmosphere.pos-1 {
  translate: -54% -47%;
}
.home-ai-atmosphere.pos-2 {
  translate: -47% -54%;
}
.home-ai-atmosphere.pos-3 {
  translate: -51% -45%;
}
@keyframes home-ai-morph {
  0%,
  100% {
    scale: 1 1;
    rotate: 0deg;
    opacity: 0.5;
  }
  25% {
    scale: 1.1 0.92;
    rotate: 1.6deg;
    opacity: 0.62;
  }
  50% {
    scale: 0.94 1.09;
    rotate: -1.2deg;
    opacity: 0.44;
  }
  75% {
    scale: 1.05 0.96;
    rotate: 0.7deg;
    opacity: 0.58;
  }
}
@media (prefers-reduced-motion: reduce) {
  .ai-atmosphere,
  .ai-atmosphere::after {
    transition: none;
    animation: none;
  }
  .ai-peak {
    animation: none;
  }
  .home-ai-atmosphere,
  .home-ai-atmosphere::after {
    animation: none;
  }
  .home-ai-atmosphere.pos-1,
  .home-ai-atmosphere.pos-2,
  .home-ai-atmosphere.pos-3 {
    translate: -50% -50%;
  }
  .ocmp-ai-atmosphere.is-active {
    animation: none;
  }
}
.sourcing-convo > :not(.convo-foot):not(.ai-atmosphere) {
  position: relative;
  z-index: 1;
}
.sourcing-convo .convo-scroll {
  /* The sourcing composer overlays this scroll area. Its live measured height
     is set by ChatPane so the last message always remains reachable. */
  padding: 18px 18px calc(18px + var(--convo-foot-height, 180px));
}
/* Shapeless on purpose — `/s/[id]` becomes either a sourcing split or a
   screening panel, so the boundary commits to neither. */
.session-route-loading {
  flex: 1;
  min-width: 0;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.sourcing-convo .convo-foot {
  /* Sourcing-only floating composer. It overlays the feed rather than taking
     a dedicated footer row; `.convo-scroll` reserves this element's measured
     height, including its queue and checklist. The composer card itself is
     the only visible chrome. */
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 1;
  margin: 0;
  padding: 16px 16px max(16px, env(safe-area-inset-bottom));
}
.convo-bar {
  padding: 11px 16px;
  border-bottom: 1px solid var(--border);
}
.credit-alert {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin: 12px 16px 0;
  padding: 12px 14px;
  border: 1px solid var(--border-2);
  border-left: 2px solid var(--text2);
  border-radius: 10px;
  background: var(--panel);
}
.credit-alert-copy {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.credit-alert-copy b {
  color: var(--text);
  font-size: 13px;
}
.credit-alert-copy span {
  color: var(--text2);
  font-size: 12px;
}
.credit-alert .btn {
  flex: none;
}
.credit-alert-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: none;
}
.credit-alert-dismiss {
  width: 30px;
  height: 30px;
}
.steer-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  margin-bottom: 8px;
  border: 1px solid var(--border-2);
  border-radius: 11px;
  background: var(--panel);
  font-size: 12px;
  color: var(--text2);
}
.steer-bar .sb-status {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}
.steer-bar .sb-steer {
  margin-left: auto;
  border: 1px solid var(--border-2);
  background: transparent;
  color: var(--text);
  border-radius: 7px;
  padding: 4px 10px;
  font-size: 11.5px;
  font-weight: 600;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.steer-bar .sb-steer:hover {
  background: var(--hover);
}
.queue-list {
  display: flex;
  flex-direction: column;
  gap: 5px;
  margin-bottom: 8px;
}
.queue-item {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 11.5px;
  color: var(--text2);
  border: 1px dashed var(--border-2);
  border-radius: 8px;
  padding: 5px 9px;
}
.queue-item .qx {
  margin-left: auto;
  cursor: pointer;
  color: var(--muted);
}
.msg {
  margin-bottom: 14px;
  max-width: 94%;
}
.msg.ai {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}
.ai-mark {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  flex: none;
}
.ai-mark img {
  display: block;
  /* 새 브랜드 키트 SVG는 여백 없이 꽉 차 있어 42px 박스 안에서 38px로
     렌더링(dynamic·static 공통) — 박스 크기는 행 정렬용으로 유지. */
  width: 38px;
  height: 38px;
  object-fit: contain;
}
.msg.ai.ai-thinking {
  margin-bottom: 18px;
}
.ai-thinking-text {
  color: var(--text2);
  font-size: 15px;
  line-height: 1.45;
}
/* Shrink to the content so short messages don't drag an empty bubble across the row. */
.msg.user {
  margin-left: auto;
  width: fit-content;
}
.msg.user .bubble {
  background: var(--active);
  border-radius: 13px 13px 4px 13px;
  padding: 8px 12px;
}
.bubble {
  font-size: 15px;
  white-space: pre-wrap;
  /* A pasted URL (or any long unbroken string) must wrap inside the bubble
     instead of overflowing its rounded box past the 94% row width. */
  overflow-wrap: anywhere;
}
/* Inline process lines (tool calls / reasoning) — muted so the orchestrator's
   own replies stay primary while sub-agent work is still visible. */
.proc {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: 1px 0 7px;
  color: var(--text2);
  font-size: 12px;
  line-height: 1.5;
}
.proc-dot {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--text2);
  flex: none;
  transform: translateY(-2px);
}
.proc-text {
  min-width: 0;
  word-break: break-word;
}
.proc-think {
  color: var(--muted);
  font-style: italic;
  white-space: pre-wrap;
  padding-left: 12px;
}
/* ===== markdown (assistant bubbles) ===== */
.md {
  white-space: normal;
}
.md > :first-child {
  margin-top: 0;
}
.md > :last-child {
  margin-bottom: 0;
}
.md p {
  margin: 0 0 8px;
  line-height: 1.6;
}
.md ul,
.md ol {
  margin: 6px 0 8px;
  padding-left: 22px;
}
.md ol {
  list-style: decimal;
}
.md ul {
  list-style: disc;
}
.md li {
  margin: 3px 0;
  line-height: 1.55;
}
.md li > p {
  margin: 0;
}
.md li::marker {
  color: inherit;
}
.md li > ul,
.md li > ol {
  margin: 3px 0;
}
.md strong {
  font-weight: 700;
}
.md em {
  font-style: italic;
}
.md a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.md h1,
.md h2,
.md h3,
.md h4 {
  margin: 14px 0 6px;
  font-weight: 700;
  line-height: 1.3;
}
.md h1 {
  font-size: 16.5px;
}
.md h2 {
  font-size: 15px;
}
.md h3 {
  font-size: 13.5px;
}
.md h4 {
  font-size: 13px;
}
.md code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.9em;
  background: var(--hover);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 1px 5px;
}
.md pre {
  background: var(--hover);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 14px;
  overflow: auto;
  margin: 8px 0;
}
.md pre code {
  background: none;
  border: 0;
  padding: 0;
  font-size: 12.5px;
  line-height: 1.5;
}
.md blockquote {
  margin: 8px 0;
  padding: 2px 0 2px 12px;
  border-left: 2px solid var(--border);
  color: var(--text2);
}
.md hr {
  border: 0;
  border-top: 1px solid var(--border);
  margin: 12px 0;
}
.md table {
  border-collapse: collapse;
  margin: 8px 0;
  font-size: 12.5px;
  width: 100%;
}
.md th,
.md td {
  border: 1px solid var(--border);
  padding: 5px 9px;
  text-align: left;
}
.md th {
  background: var(--hover);
  font-weight: 700;
}
.checkpoint {
  border: 1px solid var(--border);
  background: var(--panel);
  border-left: 2px solid var(--text2);
  border-radius: 10px;
  padding: 11px 13px;
  margin: 4px 0 14px;
}
.checkpoint .lab {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text2);
  font-weight: 700;
  margin-bottom: 6px;
}
.cp-actions {
  display: flex;
  gap: 8px;
  margin-top: 9px;
}
.btn {
  border-radius: 8px;
  padding: 7px 13px;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  border: 1px solid transparent;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: inherit;
}
.btn-primary {
  background: var(--text);
  color: var(--bg);
}
.btn-primary:hover {
  opacity: 0.9;
}
.btn-ghost {
  background: transparent;
  border-color: var(--border-2);
  color: var(--text);
}
.btn-ghost:hover {
  background: var(--hover);
}
.btn-locked {
  background: transparent;
  border-color: var(--border);
  color: var(--muted);
  cursor: default;
}
.btn-block {
  width: 100%;
  justify-content: center;
}
.btn[disabled] {
  opacity: 0.5;
  cursor: default;
}
/* Opt-in lime water fill (btn-wave). On hover the accent colour rises from
   the bottom of the button behind a rippling water surface — water filling
   the hull. Deliberately not part of the base .btn: only buttons that
   explicitly carry this class get the treatment. The fill layer sits at
   z-index -1 inside the button's own stacking context (isolation), so it
   paints above the button's background but below its label — works on
   default, primary and ghost. */
.btn-wave {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  transition: color 0.2s ease-out, border-color 0.2s ease-out;
  /* Fill colours + ripple tiles: a lime surface with a deeper green swell
     peeking behind it, half a period out of phase. The ripple SVGs duplicate
     the fill hexes because data URIs can't read CSS variables — keep each
     pair in sync. */
  --wave-fill: var(--accent);
  --wave-ripple: none;
  --wave-fill2: #039a84;
  /* Same curve as --wave-ripple but phase-shifted half a period inside the
     SVG itself, so the two ripples stay offset at any background-size. */
  --wave-ripple2: none;
}
/* Against white surfaces #dff41b all but disappears, so the light theme
   deepens both layers one step while staying in the same families. */
[data-theme="light"] .btn-wave {
  --wave-fill: #b9e00d;
  --wave-ripple: none;
  --wave-fill2: #02607a;
  --wave-ripple2: none;
}
.btn-wave::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  /* 50px taller than the button: room for the two-stage crest to park above
     the top edge once the fill completes, so the settled hover state is a
     clean full lime fill. */
  height: calc(100% + 51px);
  z-index: -1;
  /* Two waves in relay, 36px (≈ a button height) apart: the green swell
     (ripple y 0–14 + body) floods the button first, then the lime surface
     (ripple y 36–50 + body) rises through it — so the lime wave is always
     read against green, never against the button background. Each ripple
     overlaps its body by 1px so no hairline gap opens at the seams. */
  /* One wave tile spans the whole button, so the swell scales with button
     width instead of tiling into many ripples; 56px floors it so tiny
     buttons still get a readable curve. */
  background:
    var(--wave-ripple) 0 36px / max(56px, 100%) 14px no-repeat,
    linear-gradient(var(--wave-fill), var(--wave-fill)) left bottom / 100%
    calc(100% - 49px) no-repeat,
    var(--wave-ripple2) 0 0 / max(56px, 100%) 14px no-repeat,
    linear-gradient(var(--wave-fill2), var(--wave-fill2)) left bottom / 100%
    calc(100% - 13px) no-repeat;
  transform: translateY(101%);
  transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}
.btn-wave:hover:not([disabled])::before {
  transform: translateY(0);
}
.btn-wave:hover:not([disabled]) {
  color: var(--on-accent);
  border-color: transparent;
  /* Hosts often dim themselves on hover (.btn-primary/.send/.dash-cta set
     opacity 0.9) — over the lime fill that reads as a glitch, so the wave
     treatment neutralizes it for every adopter at once. */
  opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  .btn-wave,
  .btn-wave::before {
    transition: none;
  }
}
/* White chip under the real Google "G" (GoogleMark) — brand guidance wants
   the mark on white, which the chip preserves on dark-theme buttons too. */
.google-mark {
  display: inline-flex;
  width: 18px;
  height: 18px;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border-2);
  border-radius: 999px;
  background: #fff;
}
/* candidate main panel */
.candpane {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  /* Soft shadow falling from the divider: the chat pane reads as a raised
     layer over the candidate workspace, so the two surfaces separate even
     though their background tones are near-identical. */
  box-shadow: inset 10px 0 14px -12px rgba(0, 0, 0, 0.18);
}
.cand-head {
  position: relative;
  z-index: 2;
  padding: 13px 20px 11px;
  border-bottom: 1px solid var(--border);
}
.ch-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
/* Right-side cluster: live indicator + the criteria-sheet chip. */
.ch-top-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}
.ch-top b {
  font-size: 15px;
}
.ch-top b .muted {
  font-size: 12px;
  font-weight: 600;
  color: var(--text2);
}
.ch-top .live {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  color: var(--text2);
}
.livedot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--text);
  animation: pulse 1.8s infinite;
}
/* Evaluation filters, sort/filter controls and the optional result facets. */
.filters {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 11px;
  align-items: stretch;
}
.frow {
  display: flex;
  gap: 6px;
  align-items: center;
  flex-wrap: wrap;
}
.yrsel {
  font-size: 12px;
  padding: 5px 7px;
  border-radius: 8px;
  border: 1px solid var(--border);
  color: var(--text2);
  background: transparent;
  cursor: pointer;
}
.yrsel:hover {
  background: var(--hover);
  color: var(--text);
}
/* Fixed labels keep the result-facet controls aligned. */
.flabel {
  font-size: 11px;
  color: var(--muted);
  white-space: nowrap;
  flex: none;
  width: 52px;
}
html[lang="en"] .flabel {
  width: 66px;
}
.fbtn {
  font-size: 12px;
  padding: 5px 11px;
  border-radius: 8px;
  border: 1px solid var(--border);
  color: var(--text2);
  cursor: pointer;
  background: transparent;
}
.fbtn.active {
  background: var(--active);
  color: var(--text);
  border-color: var(--border-2);
  font-weight: 600;
}
.cand-toolbar-row,
.cand-filter-actions {
  display: flex;
  align-items: center;
}
.cand-filter-actions {
  margin-left: auto;
  gap: 6px;
}
.cand-filter-actions .fbtn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.cand-filter-actions .sortsel {
  margin-left: 0;
}
.candidate-facets {
  position: absolute;
  top: calc(100% + 8px);
  right: 20px;
  width: min(440px, calc(100% - 40px));
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  padding: 14px;
  border: 1px solid var(--border-2);
  border-radius: 12px;
  background: var(--elev);
  box-shadow: var(--shadow-lg);
  z-index: 200;
  animation: popUp 0.14s ease;
}
.candidate-facets::before {
  content: "";
  position: absolute;
  top: -5px;
  right: 42px;
  width: 9px;
  height: 9px;
  border-top: 1px solid var(--border-2);
  border-left: 1px solid var(--border-2);
  background: var(--elev);
  transform: rotate(45deg);
}
.candidate-facets-head {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 24px;
}
.candidate-facets-head strong {
  color: var(--text);
  font-size: 13px;
}
.candidate-facets-head button {
  padding: 3px 6px;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--text2);
  font: inherit;
  font-size: 11.5px;
  cursor: pointer;
}
.candidate-facets-head button:hover:not(:disabled) {
  background: var(--hover);
  color: var(--text);
}
.candidate-facets-head button:disabled {
  opacity: 0.4;
  cursor: default;
}
.candidate-facets label {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
  min-width: 0;
}
.candidate-facets .flabel {
  width: auto;
  color: var(--text2);
  font-weight: 600;
}
.candidate-facets .yrsel {
  width: 100%;
  height: 34px;
  padding: 0 9px;
  border-color: var(--border-2);
  background: var(--bg);
  color: var(--text);
  font-size: 12px;
  min-width: 0;
}
.facet-years-range {
  display: flex;
  align-items: center;
  flex: 1;
  gap: 4px;
  min-width: 0;
}
.facet-years-range .yrsel {
  width: 0;
  flex: 1;
}
.yr-sep {
  color: var(--muted);
  font-size: 12px;
}
/* Sort select, dressed as an fbtn (native dropdown keeps keyboard/a11y free). */
.sortsel {
  margin-left: auto;
  font-size: 12px;
  padding: 5px 8px;
  border-radius: 8px;
  border: 1px solid var(--border);
  color: var(--text2);
  background: transparent;
  cursor: pointer;
}
.sortsel:hover {
  background: var(--hover);
  color: var(--text);
}
.astrip {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding: 11px 20px;
  border-bottom: 1px solid var(--border);
}
.astrip:empty {
  display: none;
}
.acard {
  flex: none;
  width: 186px;
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 9px 11px;
  background: var(--panel-2);
  animation: slideIn 0.3s ease;
}
.acard .nm {
  font-weight: 600;
  font-size: 12.5px;
  color: var(--text);
}
.acard .st {
  font-size: 11px;
  color: var(--text2);
  margin-top: 5px;
  display: flex;
  align-items: center;
  gap: 6px;
}
.spinner {
  /* inline-block so width/height apply even as a bare <span> in a block
     container (page loading branches). Without it the span stays inline,
     ignores its size, and renders as a thin spinning bar (just its borders). */
  display: inline-block;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  border: 1.6px solid var(--border-2);
  border-top-color: var(--text2);
  animation: spin 0.7s linear infinite;
  flex: none;
  vertical-align: middle;
}
.loading-state {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  color: var(--muted);
  font-size: 13px;
  text-align: center;
}
.loading-state-page {
  flex: 1;
  height: 100%;
  min-height: calc(100dvh - 112px);
}
.loading-state-panel {
  min-height: 220px;
}
.loading-state-fill {
  min-height: 100%;
  height: 100%;
}
.loading-state-compact {
  min-height: 96px;
}
.loading-state-spinner {
  width: 14px;
  height: 14px;
  border-width: 1.8px;
}
.loading-state-label {
  line-height: 1.4;
}
/* On a button, the spinner inherits the label color so it stays legible on the
   filled primary background. */
.btn .spinner {
  border-color: color-mix(in srgb, currentColor 28%, transparent);
  border-top-color: currentColor;
}
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}
@keyframes slideIn {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
.cand-grid {
  flex: 1;
  overflow: auto;
  padding: 16px 20px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(258px, 1fr));
  gap: 12px;
  align-content: start;
}
.cand-empty {
  color: var(--muted);
  font-size: 13px;
  padding: 44px 30px;
  text-align: center;
  line-height: 1.7;
  grid-column: 1 / -1;
}

/* Table view of candidates (Talent Pool / project shortlist). Shares the
   admin-table look; rows are clickable and open the detail slideover. */
.cand-tablewrap {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: 8px;
  margin-top: 14px;
}
/* Matches .admin-table (Projects list) so the two list tables read identically;
   nowrap + the promoted-column widths below are the only candidate-specifics. */
.cand-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.cand-table th {
  text-align: left;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.cand-table td {
  padding: 12px 14px;
  color: var(--text);
  border-top: 1px solid var(--border);
  vertical-align: middle;
  white-space: nowrap;
}
.cand-table tr:first-child td {
  border-top: 0;
}
.cand-table th.right,
.cand-table td.right {
  text-align: right;
}
.cand-table th.cand-actionscol,
.cand-table td.cand-actionscol {
  width: 62px;
  padding-left: 8px;
  padding-right: 8px;
  text-align: center;
}
.cand-row-actions {
  display: flex;
  justify-content: center;
}
/* Actual pool deletion is intentionally red, unlike the shortlist's saved
   bookmark toggle: this removes the person from the organization-wide pool. */
.cand-row-delete {
  width: 28px;
  height: 28px;
  padding: 0;
  border: 1px solid color-mix(in srgb, var(--sale) 48%, var(--border));
  border-radius: 7px;
  background: color-mix(in srgb, var(--sale) 7%, var(--panel));
  color: var(--sale);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.cand-row-delete:hover {
  border-color: var(--sale);
  background: var(--sale-bg);
}
/* Sortable header: the label is a button styled as the header text; the arrow
   appears only for the active column (flipped = descending). */
.cand-table th {
  position: relative;
}
.th-sort {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  border: 0;
  background: none;
  padding: 0;
  margin: 0;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
  cursor: pointer;
}
.th-sort:hover,
.th-sort.on {
  color: var(--text);
}
.th-sort .ico.flip {
  transform: rotate(180deg);
}
/* Column resize: an invisible grab zone straddling each header divider; a
   short guide bar lights up on hover / while dragging. */
.th-rz {
  position: absolute;
  top: 0;
  bottom: 0;
  right: -5px;
  width: 10px;
  cursor: col-resize;
  user-select: none;
  touch-action: none;
  z-index: 1;
}
.th-rz::after {
  content: "";
  position: absolute;
  top: 20%;
  bottom: 20%;
  left: 4px;
  width: 2px;
  border-radius: 1px;
}
.th-rz:hover::after,
.th-rz:active::after {
  background: var(--border-2);
}
/* Once resized the layout is fixed — long content clips with an ellipsis
   instead of stretching the column back out. */
.cand-table.resized th,
.cand-table.resized td {
  overflow: hidden;
  text-overflow: ellipsis;
}
.cand-row {
  cursor: pointer;
  /* Off-screen rows skip layout/paint entirely (R23) — the intrinsic size
     keeps the scrollbar honest for hundreds of pool rows without a
     virtualization library. */
  content-visibility: auto;
  contain-intrinsic-size: auto 44px;
}
.cand-row:hover td {
  background: var(--hover);
}
.cand-row:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: -2px;
}
.cand-row.excluded td {
  color: var(--muted);
  opacity: 0.6;
}
.cand-table .cr-id {
  display: flex;
  align-items: center;
  gap: 8px;
}
.cand-table .cr-id .nm {
  font-weight: 500;
}
.cand-table .cr-av {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--active);
  display: grid;
  place-items: center;
  font-size: 10px;
  font-weight: 700;
  overflow: hidden;
  flex: none;
}
.cand-table .cr-analyzing,
.cand-table .cr-failed {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-left: 6px;
  font-size: 11px;
  white-space: nowrap;
  color: var(--muted, #8a8a8a);
}
.cand-table .cr-analyzing .spinner {
  width: 10px;
  height: 10px;
}
.cand-table .cr-failed {
  color: #d9736a;
}
.cand-table .cr-school {
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.proj-tags {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 5px;
  max-width: 220px;
}
.proj-tag {
  display: inline-flex;
  align-items: center;
  padding: 2px 8px;
  border-radius: 6px;
  background: var(--hover);
  border: 1px solid var(--border);
  color: var(--text2);
  font-size: 12px;
  white-space: nowrap;
  max-width: 160px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.prof-icons {
  display: inline-flex;
  gap: 9px;
  align-items: center;
}
.prof-icons a {
  color: var(--muted);
  display: inline-flex;
  align-items: center;
}
.prof-icons a:hover {
  color: var(--text);
}
/* Brand LinkedIn mark keeps its own color (no muted/hover tint inheritance). */
.li-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  vertical-align: middle;
}
.li-mark svg {
  display: block;
}
.cand-searching {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  color: var(--text2);
}
.cand-searching .cs-act {
  font-size: 12px;
  color: var(--muted);
  animation: popUp 0.2s ease;
}
.candcard {
  border: 1px solid var(--border);
  background: var(--panel-2);
  border-radius: 12px;
  padding: 13px 14px;
  cursor: pointer;
  transition: 0.14s;
  box-shadow: var(--shadow);
  display: flex;
  flex-direction: column;
}
.candcard:hover {
  border-color: var(--border-2);
  transform: translateY(-1px);
}
/* Status reads through the score/gauge tone and opacity — the card keeps a
   uniform 1px border on all sides (no left status bar). */
.candcard.excluded {
  opacity: 0.5;
}
.candcard.blurred {
  position: relative;
  overflow: hidden;
}
.candcard.blurred .cc-private {
  filter: blur(5px);
  opacity: 0.62;
  user-select: none;
}
.candcard.blurred .cc-lock {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--panel-2) 18%, transparent),
    color-mix(in srgb, var(--panel-2) 48%, transparent)
  );
}
.cc-lock-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--border-2);
  background: var(--panel);
  color: var(--text);
  border-radius: 999px;
  padding: 6px 10px;
  font-size: 12px;
  font-weight: 700;
  box-shadow: var(--shadow);
}
.cc-top {
  display: flex;
  align-items: center;
  gap: 10px;
}
.cc-private {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  flex: 1;
}
.cc-av {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--active);
  color: var(--text);
  display: grid;
  place-items: center;
  font-size: 13px;
  font-weight: 700;
  flex: none;
}
.cc-id {
  min-width: 0;
  flex: 1;
}
.cc-id .nm {
  font-weight: 600;
  font-size: 13.5px;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Role · company headline — up to two lines so a long role keeps its company
   instead of clipping it off behind an ellipsis. */
.cc-id .org {
  color: var(--text2);
  font-size: 11.5px;
  margin-top: 2px;
  line-height: 1.35;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.score {
  font-weight: 700;
  font-size: 14px;
  white-space: nowrap;
  display: flex;
  align-items: center;
}
.gauge {
  height: 5px;
  border-radius: 4px;
  background: var(--border-2);
  overflow: hidden;
  width: 40px;
  display: inline-block;
  margin-right: 7px;
}
.gauge > i {
  display: block;
  height: 100%;
}
/* Card body — the same job-function/years-of-experience/education facts as
   the detail panel, compact. Shares the .d-fact row shape; only
   sizing/spacing is tightened here. */
.cc-facts {
  display: flex;
  flex-direction: column;
  gap: 7px;
  margin: 12px 0 4px;
}
.cc-facts .d-fact {
  gap: 8px;
  font-size: 12px;
  align-items: baseline;
}
.cc-facts .d-fact .fk {
  width: 30px;
}
html[lang="en"] .cc-facts .d-fact .fk {
  width: 68px;
}
/* Fixed 4-line signal block: shorter text leaves space, longer text clamps
   with …, so the divider + footer sit at the same height on every card. */
.cc-sig {
  color: var(--text2);
  font-size: 11.5px;
  margin: 10px 0 11px;
  line-height: 1.5;
  height: 6em;
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.cc-foot {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: auto;
  /* 12px + the 1px divider = 13px above the row — equal to the card's 13px
     bottom padding, so the footer sits centered between divider and edge. */
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.cc-foot .badge {
  font-size: 10.5px;
  color: var(--text2);
}
/* Fit evaluation in flight: live spinner badge (border stays quiet — the
   motion is the signal), card-sized spinner. */
.cc-foot .badge.evaluating {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--text2);
  border-color: var(--border-2);
}
.cc-foot .badge.evaluating .spinner {
  width: 9px;
  height: 9px;
  border-width: 1.4px;
}
/* Must-have tally: quiet by default, full marks get the stronger ink. */
.cc-foot .badge.mh.full {
  color: var(--text);
  font-weight: 600;
}
/* Unmeasured-dimension count: a quiet "score carries some estimation" cue. */
.cc-foot .badge.est {
  color: var(--text2);
}
.savebtn {
  margin-left: auto;
  border: 1px solid var(--border-2);
  background: transparent;
  color: var(--text2);
  border-radius: 8px;
  padding: 5px 9px;
  font-size: 11.5px;
  font-weight: 600;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.savebtn:hover {
  background: var(--hover);
  color: var(--text);
}
/* Saved is a STATE, not an action — a quiet tint so it never competes with
   (or twins) the solid primary next to it; the lime bookmark is the one
   selection accent. */
.savebtn.on {
  background: var(--active);
  color: var(--text);
  border-color: var(--border-2);
}
.savebtn.on .ico {
  /* Saved mark: the TRUE #dff41b fills the bookmark in both themes (the brand
     constant), while the outline is theme INK like the label beside it —
     light ink on dark, dark ink on white. Naked lime alone has ≈white
     brightness and vanishes on light, so the ink outline carries the shape. */
  color: var(--text);
}
.savebtn.on .ico svg {
  fill: var(--accent);
}
.pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 12px;
  border-top: 1px solid var(--border);
}
.pgbtn {
  min-width: 30px;
  height: 30px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text2);
  border-radius: 8px;
  font-size: 12.5px;
  cursor: pointer;
  padding: 0 8px;
}
.pgbtn:hover {
  background: var(--hover);
  color: var(--text);
}
.pgbtn.active {
  background: var(--active);
  color: var(--text);
  border-color: var(--border-2);
  font-weight: 700;
}
.pgbtn[disabled] {
  opacity: 0.4;
  cursor: default;
}
/* detail slideover */
.detail {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  /* The profile column (.detail-main) is user-resizable via the left-edge
     handle (--dw mirrors detailW); the notes aside adds its own fixed width to
     the right. 92% cap keeps the list behind reachable on narrow viewports. */
  max-width: 92%;
  background: var(--panel);
  border-left: 1px solid var(--border-2);
  box-shadow: var(--shadow-lg);
  transform: translateX(108%);
  transition: transform 0.26s cubic-bezier(0.22, 0.61, 0.36, 1);
  display: flex;
  flex-direction: row;
  z-index: 20;
}
.detail.open {
  transform: none;
}
/* The profile column — the original single-column detail body. Holds the
   header, sticky identity/actions/section-nav, and the scroll region. */
.detail-main {
  width: var(--dw, 520px);
  min-width: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--panel);
}
/* Panel takes focus on open (so arrow-key paging doesn't land on a row behind
   it) — it's a container, not an interactive control, so no focus ring. */
.detail:focus,
.detail:focus-visible {
  outline: none;
}
.detail-resizer {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 11px;
  transform: translateX(-5px);
  cursor: col-resize;
  z-index: 5;
  touch-action: none;
}
.detail-resizer::before {
  content: "";
  position: absolute;
  inset: 0 5px;
  background: transparent;
  transition: background 0.15s ease;
}
.detail-resizer:hover::before,
.detail-resizer.dragging::before,
.detail-resizer:focus-visible::before {
  background: var(--text2);
}
.detail-resizer:focus-visible {
  outline: none;
}
.detail-head {
  flex: none;
  display: flex;
  align-items: center;
  box-sizing: border-box;
  height: 47px;
  padding: 0 10px;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
}
/* The aside toggle starts the right-hand button group (→| then ×), pushed hard
   right whether or not the prev/next nav renders. */
.detail-aside-toggle {
  margin-left: auto;
}
.detail-nav {
  display: inline-flex;
  gap: 2px;
}
.detail-nav .iconbtn:disabled {
  opacity: 0.3;
  cursor: default;
}
/* Fixed identity + section-nav header: who this is and which section stay put
   while only the section content scrolls beneath it. */
.detail-sticky {
  flex: none;
  background: var(--panel);
  padding: 16px 22px 0;
}
.detail-scroll {
  flex: 1;
  overflow: auto;
  padding: 16px 22px 10px;
}
.d-id {
  display: flex;
  gap: 16px;
  align-items: center;
}
.d-av {
  width: 74px;
  height: 74px;
  border-radius: 50%;
  background: var(--active);
  color: var(--text);
  display: grid;
  place-items: center;
  font-size: 26px;
  font-weight: 700;
  flex: none;
}
.d-name {
  font-size: 20px;
  font-weight: 700;
}
.d-name-row {
  display: flex;
  align-items: center;
  gap: 6px;
}
.d-name-share {
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--text2);
  cursor: pointer;
}
.d-name-share:hover {
  background: var(--hover);
  color: var(--text);
}
.d-loc {
  color: var(--text2);
  font-size: 13px;
  margin-top: 3px;
}
/* Profile external links grouped on one row under the name
   so they read as a link cluster, not stray links scattered across sections. */
.d-links {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
}
.d-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--text2);
  font-size: 12.5px;
  margin-top: 7px;
  cursor: pointer;
  text-decoration: none;
}
/* Overview card — wraps the derived quick-facts grid and the AI summary in a
   single bordered unit so the two read as one block, not two stray islands.
   `overflow: hidden` keeps the tinted summary band inside the rounded corners. */
.d-overview-card {
  margin: 16px 0 6px;
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
}
/* Derived quick-facts (job function / years of experience / education) — a
   labelled grid, all re-surfaced from data the backend already stores.
   Inside the Overview card it drops its own frame/margins; the card owns the
   border. */
.d-facts {
  display: flex;
  flex-direction: column;
  gap: 9px;
  margin: 16px 0 6px;
  padding: 13px 15px;
  border: 1px solid var(--border);
  border-radius: 12px;
}
.d-overview-card .d-facts {
  margin: 0;
  border: 0;
  border-radius: 0;
  padding: 14px 16px 15px;
}
.d-fact {
  display: flex;
  gap: 12px;
  align-items: baseline;
  font-size: 13px;
}
.d-fact .fk {
  flex: none;
  width: 58px;
  color: var(--text2);
  font-size: 11.5px;
}
/* English labels (Role/Experience/Education) outgrow the Korean-tuned
   two-syllable column — same-pattern per-language width override. */
html[lang="en"] .d-fact .fk {
  width: 74px;
}
.d-fact .fv {
  color: var(--text);
  font-weight: 500;
  min-width: 0;
}
.d-fact .f-contact {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  line-height: 1.45;
  overflow-wrap: anywhere;
}
.d-fact .f-link {
  color: inherit;
  text-decoration: none;
}
.d-fact .f-link:hover {
  text-decoration: underline;
  text-underline-offset: 2px;
}
.d-fact .fsub {
  margin-left: 8px;
  color: inherit;
  font-weight: inherit;
  font-size: inherit;
}
.d-fact .fsep {
  margin-right: 8px;
  color: inherit;
}
/* AI one-liner summary — a tinted footer band inside the Overview card,
   split off from the facts grid by a hairline. The tint + lime tick mark it
   as the "analysis" read while staying part of the same card. */
.d-summary {
  margin: 0;
  padding: 13px 16px 15px;
  background: var(--hover);
  border-top: 1px solid var(--border);
}
.d-summary .d-summary-tag {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text2);
  margin-bottom: 6px;
}
/* Small lime tick — the one key-color accent, marking this as the AI read. */
.d-summary .d-summary-tag::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent-mark);
}
.d-summary p {
  margin: 0;
  font-size: 14px;
  line-height: 1.65;
  color: var(--text);
}
.d-reason {
  border: 1px solid var(--border-2);
  border-radius: 12px;
  padding: 13px 15px;
  margin: 18px 0 6px;
}
.d-reason .rl {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  color: var(--text2);
  background: var(--active);
  border-radius: 6px;
  padding: 3px 8px;
  margin-bottom: 9px;
}
.d-reason p {
  margin: 0;
  font-size: 13px;
  line-height: 1.6;
}

/* Structured fit-evaluation panel (EvalPanel) */
.d-eval {
  border: 1px solid var(--border-2);
  border-radius: 12px;
  padding: 13px 15px;
  margin: 18px 0 6px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.d-ai-eval-section .d-eval {
  border: none;
  border-radius: 0;
  padding: 0;
  margin: 0 0 6px;
}
/* Section subheadings inside the eval panel — quiet uppercase captions, NOT
   the filled chip that real status tags (recommend / met marks / confidence)
   use. Keeps the group titles from competing with the badges they sit above,
   and gives the panel a scannable heading hierarchy instead of a wall of
   pills. */
.d-eval .rl {
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text2);
}
.d-eval .tag {
  font-size: 11px;
  font-weight: 600;
  color: var(--text2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 2px 7px;
}
/* The version tag opens the criteria modal. A plain bordered tag reads as a
   static label (like the recommend/hold badge beside it), so the button
   variant gets a resting filled fill + a caret to signal it is pressable — no
   color needed. */
.d-eval button.tag {
  font-family: inherit;
  cursor: pointer;
}
.d-eval button.tag.tag-btn {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  background: var(--hover);
  border-color: var(--border-2);
}
.d-eval .tag-caret {
  font-weight: 700;
  opacity: 0.5;
}
.d-eval button.tag.tag-btn:hover {
  background: var(--active);
  color: var(--text);
  border-color: var(--text2);
}
.d-eval button.tag.tag-btn:hover .tag-caret {
  opacity: 0.9;
}
.ev-head {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.ev-jd {
  font-size: 12px;
  color: var(--text2);
  line-height: 1.5;
}
.ev-score {
  display: flex;
  align-items: baseline;
  gap: 9px;
}
.ev-score b {
  font-size: 26px;
  line-height: 1;
  letter-spacing: -0.02em;
}
.ev-score span {
  color: var(--text2);
  font-size: 13px;
}
/* Summary header — the score reads as the hero, with the recommendation and
   version tag on its line and the JD + measurement note beneath. The old
   "Fit Evaluation" caption is dropped: the enclosing "AI Evaluation" section
   title already names it, so repeating it here only added a redundant chip. */
.ev-summary {
  display: flex;
  flex-direction: column;
  gap: 7px;
}
.ev-summary-row {
  display: flex;
  align-items: center;
  gap: 9px;
}
.ev-score-hero {
  display: flex;
  align-items: baseline;
  gap: 7px;
}
.ev-score-hero b {
  font-size: 30px;
  line-height: 1;
  letter-spacing: -0.02em;
}
.ev-score-hero .out {
  font-size: 14px;
  color: var(--text2);
}
/* Version tag pushed to the right edge of the score row. */
.ev-summary-ver {
  margin-left: auto;
  align-self: center;
}
.ev-summary .ev-trust {
  margin-left: 0;
}
/* Recommendation badge — the panel's headline verdict. A positive call
   (strongly recommend / recommend) earns the lime fill; hold/not-recommend
   stay achromatic so the key color only ever marks a "yes". */
.d-eval .ev-rec {
  font-size: 12px;
  font-weight: 700;
  border-radius: 6px;
  padding: 3px 9px;
}
.d-eval .ev-rec-strong_yes,
.d-eval .ev-rec-yes {
  color: var(--on-accent);
  background: var(--accent);
}
.d-eval .ev-rec-maybe {
  color: var(--text2);
  border: 1px solid var(--border-2);
}
.d-eval .ev-rec-no {
  color: var(--muted);
  border: 1px solid var(--border);
}
/* Trust summary beside the score: how much of it rests on measured evidence. */
.ev-trust {
  margin-left: auto;
  font-size: 11.5px;
  color: var(--muted);
}
/* Each group sits under its own hairline so the panel reads as a stack of
   labelled sections rather than one long run of text. */
.ev-group {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding-top: 15px;
  border-top: 1px solid var(--border);
}
.verdicts {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.verdicts li {
  display: flex;
  gap: 9px;
  align-items: flex-start;
  font-size: 13px;
  line-height: 1.5;
}
/* Verdict marker as a small square chip: a met (✓) criterion gets the lime
   fill; partial/none/unknown stay achromatic, weakening toward unconfirmed. */
.ev-mark {
  flex: none;
  width: 16px;
  height: 16px;
  margin-top: 1px;
  border-radius: 5px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 10px;
  font-weight: 700;
  background: var(--active);
  color: var(--text2);
}
/* The "met" mark stays monochrome — the key color is reserved for primary
   actions/selection, and a lime ✓ on every met criterion reads far too loud.
   Met vs not-met is carried by brightness (full text vs muted) instead. */
.ev-mark.m-yes {
  background: var(--active);
  color: var(--text);
}
.ev-mark.m-no,
.ev-mark.m-unknown {
  color: var(--muted);
}
.ev-crit {
  flex: 1;
  min-width: 0;
  font-weight: 500;
}
.ev-evidence {
  color: var(--text2);
  font-size: 12px;
  margin-top: 3px;
  line-height: 1.5;
  font-weight: 400;
}
/* Rubric dimensions — the ranking signal. */
.ev-dimlist {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.ev-dim {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.ev-dim-head {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
}
.ev-dim-label {
  font-weight: 600;
  color: var(--text);
}
.ev-dim-weight {
  font-size: 11px;
  color: var(--muted);
}
.ev-dim-weight::before {
  content: "비중 ";
}
/* The one piece of copy CSS renders itself — follow the dynamic <html lang>. */
html[lang="en"] .ev-dim-weight::before {
  content: "Weight ";
}
.ev-dim-score {
  margin-left: auto;
  font-size: 16px;
  font-weight: 600;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.ev-dim-na {
  font-size: 11.5px;
  font-weight: 400;
  color: var(--muted);
}
/* Score meter under each measured dimension — a quiet achromatic bar so the
   0–100 score reads at a glance without another number to parse. */
.ev-dim-bar {
  height: 3px;
  border-radius: 2px;
  background: var(--active);
  overflow: hidden;
}
.ev-dim-bar > i {
  display: block;
  height: 100%;
  border-radius: 2px;
  background: var(--text2);
}
/* Confidence badge: glyph + label only, distinguished by ink weight — never
   a color hue (the surface stays achromatic and it implies no good/bad). */
.ev-conf {
  font-size: 10.5px;
  color: var(--text2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 1px 6px;
  white-space: nowrap;
}
.ev-conf-verified {
  color: var(--text);
  border-color: var(--border-2);
  font-weight: 700;
}
.ev-conf-weak {
  color: var(--muted);
}
/* Interview-check block: the dimension name leading each question. */
.ev-iq-dim {
  font-weight: 600;
  color: var(--text);
}
.ev-points {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 5px;
  font-size: 13px;
  line-height: 1.5;
}
.ev-points li {
  display: flex;
  gap: 8px;
}
.ev-points li::before {
  content: "•";
  color: var(--text2);
  flex: none;
  /* Slightly larger dot, vertically centered on the first text line rather
     than clinging to the top: match the line box height and center within it. */
  font-size: 1.35em;
  line-height: 1.1;
  align-self: flex-start;
}
.ev-rationale {
  font-size: 13px;
  line-height: 1.6;
}
.ev-rationale p {
  margin: 0 0 6px;
}
.ev-rationale ul {
  margin: 0;
  padding-left: 18px;
}
.ev-rationale li {
  margin: 3px 0;
}
/* Markdown bullet lists inside evaluation areas use the same – dash as
   .ev-points, so one panel doesn't mix two bullet styles (– vs •). */
.ev-rationale .md ul,
.d-reason .md ul {
  list-style: none;
  padding-left: 0;
}
/* Hanging-indent marker via an absolute ::before — NOT display:flex, which
   would split a "**label**: text" item into separate flex items (detaching the
   colon from its bold label). This keeps each item's rich text flowing inline. */
.ev-rationale .md ul > li,
.d-reason .md ul > li {
  position: relative;
  padding-left: 14px;
}
.ev-rationale .md ul > li::before,
.d-reason .md ul > li::before {
  content: "–";
  color: var(--text2);
  position: absolute;
  left: 0;
  top: 0;
}
.d-actions {
  display: flex;
  gap: 8px;
  margin: 14px 0 4px;
}
.d-report-btn {
  flex: none;
  height: 32px;
  padding: 0 10px;
  gap: 5px;
  font-size: 11.5px;
  font-weight: 680;
  line-height: 1;
  white-space: nowrap;
}

/* The list card pushes .savebtn to the right (margin-left:auto); in the detail
   header it sits left, right under the name/links block. */
.d-actions .savebtn {
  margin-left: 0;
  height: 32px;
  padding: 0 10px;
}
/* Detail slideover section nav (Overview / AI Evaluation / Experience /
   Education / Skills). */
.d-tabs {
  display: flex;
  gap: 2px;
  background: var(--panel);
  border-bottom: 1px solid var(--border);
  margin: 14px -22px 0;
  padding: 0 22px;
}
.d-tab {
  flex: none;
  display: inline-flex;
  align-items: center;
  background: none;
  border: none;
  padding: 8px 11px;
  font-family: inherit;
  font-size: 13px;
  color: var(--muted);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  text-decoration: none;
  white-space: nowrap;
}
.d-tab:hover,
.d-tab:focus-visible {
  color: var(--text);
  outline: none;
}
.d-tab.on,
.d-tab[aria-current="true"] {
  color: var(--text);
  font-weight: 600;
  border-bottom-color: var(--text);
}
.d-section {
  padding-top: 4px;
  scroll-margin-top: 46px;
}
.d-section + .d-section {
  border-top: 1px solid var(--border);
  margin-top: 22px;
  padding-top: 18px;
}
.d-section > .d-sec:first-child {
  margin-top: 0;
}
.d-skills {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 14px;
}
.skill-chip {
  font-size: 12px;
  padding: 3px 9px;
  border: 1px solid var(--border);
  border-radius: 12px;
  color: var(--text);
  background: var(--panel);
}
.d-muted {
  color: var(--muted);
  font-size: 13px;
}

.d-sec {
  font-size: 14px;
  font-weight: 700;
  margin: 22px 0 12px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.d-sec .tag {
  font-size: 11px;
  font-weight: 600;
  color: var(--text2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 2px 7px;
}
.tl {
  position: relative;
  padding-left: 16px;
}
.tl-item {
  position: relative;
  padding: 0 0 16px 0;
}
.tl-item::before {
  content: "";
  position: absolute;
  left: -12px;
  top: 5px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--text2);
}
.tl-item::after {
  content: "";
  position: absolute;
  left: -9px;
  top: 12px;
  bottom: -2px;
  width: 1px;
  background: var(--border-2);
}
.tl-item:last-child::after {
  display: none;
}
.tl-t {
  font-weight: 600;
  font-size: 13px;
  color: var(--text);
}
.tl-p {
  color: var(--text2);
  font-size: 11.5px;
  margin-top: 2px;
}
/* ===== candidate detail · notes aside ===== */
/* The right-hand action panel (Notes / Sequences / Activity / …). Sits beside
   the profile column when open; its fixed width adds onto --dw so the profile
   keeps its resized width. Only Notes is live today — the tab strip is a config
   array so new surfaces slot in without touching the layout. */
.detail-aside {
  width: 540px;
  flex: none;
  height: 100%;
  display: flex;
  flex-direction: column;
  border-left: 1px solid var(--border);
  background: var(--panel-2);
}
/* →| flips to |← once the panel is open, reading as "collapse this". */
.detail.aside-open .detail-aside-toggle .ico svg {
  transform: scaleX(-1);
}
/* Single-surface header — shown while Notes is the only tab. Swaps to the tab
   strip automatically once a second surface is added to ASIDE_TABS. */
.d-aside-head {
  flex: none;
  padding: 13px 16px;
  border-bottom: 1px solid var(--border);
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
}
.d-aside-tabs {
  flex: none;
  align-items: stretch;
  box-sizing: border-box;
  height: 47px;
  overflow: visible;
}
.d-aside-tab {
  flex: none;
  white-space: nowrap;
}
.d-aside-body {
  flex: 1;
  overflow: auto;
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
/* Placeholder for the not-yet-built surfaces (Sequences/Activity/…). */
.d-aside-soon {
  margin: auto;
  text-align: center;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.6;
}

/* --- notes --- */
.note-compose {
  flex: none;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel);
}
.note-input {
  width: 100%;
  min-height: 76px;
  resize: vertical;
  border: none;
  background: transparent;
  color: var(--text);
  font: inherit;
  padding: 12px 14px;
  outline: none;
}
.note-input::placeholder {
  color: var(--muted);
}
.note-compose-foot {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding: 8px 10px;
  border-top: 1px solid var(--border);
}
/* Neutral primary action (mirrors .btn-primary: ink fill, page-bg text) — the
   lime key colour is reserved for save/select/badge accents, not this button. */
/* Fill/typography come from the shared .btn/.btn-primary family; the compose
   footer uses the aside's compact button height (the default .btn padding
   lands at 35px — visibly taller than the 30px chips around it). */
.note-add {
  height: 30px;
  padding: 0 12px;
  transition: opacity 0.14s ease;
}
.note-add:disabled {
  opacity: 0.4;
  cursor: default;
}
.note-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.note-item {
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel);
  padding: 12px 14px;
}
.note-head {
  display: flex;
  align-items: center;
  gap: 8px;
}
.note-av {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--active);
  color: var(--text);
  display: grid;
  place-items: center;
  font-size: 12px;
  font-weight: 700;
  flex: none;
}
.note-author {
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
}
.note-time {
  margin-left: auto;
  color: var(--muted);
  font-size: 12px;
}
.note-del {
  flex: none;
  border: none;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  padding: 2px;
  display: inline-flex;
  border-radius: 6px;
}
.note-del:hover {
  color: var(--bad);
  background: var(--elev);
}
.note-body {
  margin-top: 8px;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--text);
  white-space: pre-wrap;
  word-break: break-word;
}
.note-empty {
  margin: 28px auto;
  text-align: center;
  color: var(--muted);
  font-size: 13px;
}

/* --- outreach messages (the aside's Messages tab) --- */
/* Mirrors the notes grammar: one bordered compose box (quiet channel tabs,
   borderless textarea, footer actions with the shared ink-filled
   .btn-primary) and note-item-style cards. Lime appears only on the status
   badge, per the accent rule. */
.om-compose {
  flex: none;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel);
}
.om-channels {
  display: flex;
  gap: 4px;
  padding: 10px 12px 0;
}
.om-channel {
  border: none;
  background: transparent;
  color: var(--muted);
  font-size: 12.5px;
  font-weight: 600;
  padding: 5px 10px;
  border-radius: 8px;
  cursor: pointer;
  white-space: nowrap;
}
.om-channel:hover {
  color: var(--text2);
  background: var(--elev);
}
.om-channel.on {
  background: var(--active);
  color: var(--text);
}
.om-hint {
  margin: 6px 14px 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--muted);
}
/* Team-lead voice: the hint and the name input live together, right where
   the choice was made — no pointing at another panel. */
.om-hm {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 0 14px 10px;
}
.om-hm-hint {
  margin: 0;
}
.om-hm-name {
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--elev);
  color: var(--text);
  font: inherit;
  font-size: 12.5px;
  padding: 6px 8px;
}
.om-hm-name::placeholder {
  color: var(--muted);
}
.om-input {
  width: 100%;
  min-height: 52px;
  resize: vertical;
  border: none;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: 13px;
  padding: 10px 14px;
  outline: none;
}
.om-input::placeholder {
  color: var(--muted);
}
.om-job {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  padding: 0 14px 10px;
}
.om-job-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 11.5px;
  color: var(--muted);
}
.om-job-field input {
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--elev);
  color: var(--text);
  font-size: 12.5px;
  padding: 6px 8px;
}
.om-foot {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 10px;
  border-top: 1px solid var(--border);
}
.om-select,
.om-foot-toggle {
  height: 30px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: transparent;
  color: var(--text2);
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  padding: 0 8px;
  cursor: pointer;
}
.om-select {
  max-width: 132px;
}
.om-select:hover,
.om-foot-toggle:hover {
  color: var(--text);
  background: var(--hover);
}
.om-foot-toggle.on {
  background: var(--active);
  color: var(--text);
}
/* Compact aside height for the shared .btn-primary (same as .note-add). */
.om-generate {
  margin-left: auto;
  height: 30px;
  padding: 0 12px;
  transition: opacity 0.14s ease;
}
.om-generate:disabled {
  opacity: 0.4;
  cursor: default;
}
/* Monochrome error banner — same grammar as .jdm-error (no red flood). */
.om-error {
  margin: 10px 14px;
  font-size: 12px;
  color: var(--text);
  border: 1px solid var(--border-2);
  border-left: 3px solid var(--text);
  border-radius: 7px;
  padding: 6px 9px;
}
.om-empty {
  margin: 28px auto;
  text-align: center;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.6;
  max-width: 300px;
}
.om-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.om-card {
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel);
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.om-card-head {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
/* The angle name is the card's identity — plain bold text, like .note-author. */
.om-angle {
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
}
.om-tag {
  font-size: 11px;
  font-weight: 600;
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 1px 8px;
}
/* Copied/sent state — one of the accent rule's sanctioned badge uses. */
.om-status {
  font-size: 11px;
  font-weight: 700;
  border-radius: 999px;
  padding: 1px 8px;
  background: var(--accent);
  color: var(--on-accent);
}
.om-count {
  margin-left: auto;
  font-size: 12px;
  color: var(--muted);
}
.om-subject {
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
}
.om-body {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--text);
  white-space: pre-wrap;
  word-break: break-word;
}
.om-edit {
  border: 1px solid var(--border-2);
  border-radius: 8px;
  background: var(--elev);
  color: var(--text);
  font: inherit;
  font-size: 13px;
  line-height: 1.55;
  padding: 8px;
  min-height: 120px;
  resize: vertical;
}
.om-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}
/* Quoted dossier facts — same metrics as .skill-chip. */
.om-cite {
  font-size: 12px;
  padding: 3px 9px;
  border: 1px solid var(--border);
  border-radius: 12px;
  color: var(--text);
  background: var(--panel);
  max-width: 180px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.om-cite a {
  color: inherit;
  text-decoration: none;
}
.om-cite a:hover {
  text-decoration: underline;
}
/* Lint chips stay achromatic (design rule: lime is the only color). */
.om-warn {
  font-size: 11px;
  color: var(--warn);
  border: 1px dashed var(--border-2);
  border-radius: 999px;
  padding: 2px 8px;
}
.om-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.om-btn {
  height: 26px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: transparent;
  color: var(--text2);
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  padding: 0 10px;
  cursor: pointer;
}
.om-btn:hover {
  background: var(--hover);
  color: var(--text);
}
.om-btn[disabled] {
  opacity: 0.5;
  cursor: default;
}
.om-btn-strong {
  border-color: var(--border-2);
  color: var(--text);
  font-weight: 700;
}

/* report modal */
.modal-scrim {
  position: fixed;
  inset: 0;
  background: var(--scrim);
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 32px;
  animation: fade 0.15s ease;
}
@keyframes fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
.modal {
  width: 100%;
  max-width: 780px;
  max-height: 88vh;
  background: var(--bg);
  border: 1px solid var(--border-2);
  border-radius: 18px;
  box-shadow: var(--shadow-lg);
  display: flex;
  flex-direction: column;
  animation: popUp 0.2s ease;
}
.modal-head {
  display: flex;
  align-items: center;
  gap: 13px;
  padding: 18px 22px;
  border-bottom: 1px solid var(--border);
}
.modal-head .d-av {
  width: 46px;
  height: 46px;
  font-size: 17px;
}
.modal-head .mt {
  font-size: 16px;
  font-weight: 700;
}
.modal-head .ms {
  color: var(--text2);
  font-size: 12.5px;
  margin-top: 2px;
}
.modal-body {
  overflow: auto;
  padding: 22px 24px;
}
.confirm {
  width: 100%;
  max-width: 440px;
  background: var(--bg);
  border: 1px solid var(--border-2);
  border-radius: 16px;
  box-shadow: var(--shadow-lg);
  padding: 22px 22px 18px;
  animation: popUp 0.18s ease;
}
.confirm-title {
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.confirm-body {
  color: var(--text2);
  font-size: 13.5px;
  line-height: 1.6;
  margin-top: 12px;
}
.confirm-body b {
  color: var(--text);
  font-weight: 700;
}
.confirm-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 22px;
}
.confirm-btn {
  border-radius: 999px;
  padding: 8px 18px;
}
.rep-sec {
  margin-bottom: 22px;
}
.rep-sec h4 {
  font-size: 13px;
  font-weight: 700;
  margin: 0 0 10px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.rep-sec p {
  margin: 0;
  font-size: 13px;
  color: var(--text);
  line-height: 1.65;
}
.rep-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}
@media (max-width: 680px) {
  .rep-grid {
    grid-template-columns: 1fr;
  }
}
.rep-card {
  border: 1px solid var(--border);
  border-radius: 11px;
  padding: 13px 15px;
  background: var(--panel);
  font-size: 13px;
}
.rep-card .rl {
  font-size: 11.5px;
  color: var(--text2);
  margin-bottom: 6px;
  display: flex;
  align-items: center;
  gap: 6px;
}
.fit-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
}
.fit-row:last-child {
  border: 0;
}
.fit-row .mk {
  margin-left: auto;
  color: var(--text2);
  font-size: 12px;
}
/* criteria modal — grouped requirements */
.crit-top {
  margin-bottom: 4px;
}
.crit-role {
  font-size: 15px;
  font-weight: 700;
  margin: 0 0 10px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.crit-jd {
  margin: 0 0 12px;
  font-size: 13px;
  color: var(--text);
  line-height: 1.65;
}
.crit-ideal {
  margin: 0 0 13px;
  font-size: 12.5px;
  color: var(--text2);
  line-height: 1.6;
  display: flex;
  gap: 8px;
  padding: 9px 12px;
  background: var(--hover);
  border-radius: 9px;
}
.crit-ideal .ico {
  flex: none;
  margin-top: 2px;
}
.crit-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
  margin: 0 0 14px;
}
.crit-meta .m {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 12.5px;
  color: var(--text2);
}
.crit-meta .m b {
  color: var(--text);
  font-weight: 600;
}
.crit-domains {
  margin-bottom: 0;
}
.crit-group {
  margin-top: 20px;
}
.crit-glabel {
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text2);
  font-weight: 700;
  margin-bottom: 6px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.crit-glabel .n {
  color: var(--muted);
  font-weight: 600;
  letter-spacing: 0;
}
.crit-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.crit-item {
  display: flex;
  align-items: flex-start;
  gap: 11px;
  padding: 8px 0;
  font-size: 13px;
  line-height: 1.55;
  color: var(--text);
  border-bottom: 1px solid var(--border);
}
.crit-item:last-child {
  border-bottom: 0;
}
.crit-mk {
  flex: none;
  width: 20px;
  height: 20px;
  border-radius: 6px;
  display: grid;
  place-items: center;
  margin-top: 1px;
}
.crit-mk .ico {
  width: 12px;
  height: 12px;
}
.crit-mk-must {
  background: var(--text);
  color: var(--bg);
}
.crit-mk-nice {
  background: var(--hover);
  color: var(--text2);
}
.crit-mk-deal {
  border: 1px solid var(--border);
  color: var(--text2);
}
.crit-mk-etc {
  background: var(--hover);
  color: var(--text2);
}
/* Evaluation rubric: a criterion / weight table so each weight reads as a
   labeled percentage rather than a bare leading number. */
.crit-rubric-note {
  font-size: 12px;
  color: var(--text2);
  line-height: 1.5;
  margin: 0 0 8px;
}
.crit-rubric-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.crit-rubric-table th {
  text-align: left;
  font-size: 11px;
  font-weight: 600;
  color: var(--text2);
  padding: 0 0 7px;
  border-bottom: 1px solid var(--border);
}
.crit-rubric-table td {
  padding: 9px 0;
  line-height: 1.55;
  color: var(--text);
  vertical-align: top;
  border-bottom: 1px solid var(--border);
}
.crit-rubric-table tr:last-child td {
  border-bottom: 0;
}
.crit-rubric-table .w {
  text-align: right;
  white-space: nowrap;
  padding-left: 14px;
  font-variant-numeric: tabular-nums;
}
.crit-rubric-table td.w {
  font-weight: 700;
}
.crit-rubric-desc {
  color: var(--text2);
}
/* criteria modal: tabs / version history / diff / original-JD sources */
.crit-tabs {
  display: flex;
  gap: 2px;
  padding: 0 22px;
  border-bottom: 1px solid var(--border);
}
.crit-tab {
  border: 0;
  background: transparent;
  color: var(--text2);
  font-size: 13px;
  font-weight: 600;
  padding: 10px 12px;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.crit-tab.active {
  color: var(--text);
  border-bottom-color: var(--text);
}
/* Version history: a segmented pill row (standard for a few items) instead of
   a native <select>, which renders inconsistently and clashes with the theme. */
.crit-vers {
  margin-bottom: 16px;
}
.crit-vpills {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.crit-vpill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  border: 1px solid var(--border-2);
  background: transparent;
  color: var(--text2);
  border-radius: 8px;
  padding: 4px 11px;
  font-size: 12.5px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
}
.crit-vpill:hover {
  background: var(--hover);
  color: var(--text);
}
.crit-vpill.active {
  background: var(--text);
  color: var(--bg);
  border-color: transparent;
}
.crit-vcur {
  font-size: 10px;
  font-weight: 700;
  opacity: 0.65;
}
.crit-vmeta {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 8px;
}
.crit-vtime {
  font-size: 11.5px;
  color: var(--muted);
}
.crit-oldnote {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text2);
  background: var(--hover);
  border-radius: 6px;
  padding: 3px 9px;
}
.crit-new {
  display: inline-block;
  margin-left: 8px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--text2);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 1px 5px;
  vertical-align: 1px;
}
.crit-removed {
  color: var(--muted);
}
.crit-removed s {
  text-decoration-thickness: 1px;
}
.src-card {
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px 16px;
  margin-bottom: 14px;
}
.src-card:last-child {
  margin-bottom: 0;
}
.src-head {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
}
.src-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-decoration: none;
}
a.src-name:hover {
  text-decoration: underline;
}
.src-open {
  margin-left: auto;
  flex: none;
  font-size: 12px;
  color: var(--text2);
  text-decoration: none;
  border: 1px solid var(--border);
  border-radius: 7px;
  padding: 3px 9px;
}
.src-cap {
  font-size: 11.5px;
  color: var(--muted);
  margin-top: 5px;
}
.src-pdf {
  width: 100%;
  height: 440px;
  border: 1px solid var(--border);
  border-radius: 9px;
  margin-top: 12px;
  background: var(--hover);
}
.src-content {
  margin: 12px 0 0;
  max-height: 280px;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-word;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--text);
  background: var(--hover);
  border-radius: 9px;
  padding: 12px 14px;
  font-family: inherit;
}
.src-empty {
  color: var(--text2);
  font-size: 13px;
  line-height: 1.6;
  padding: 18px 4px;
}
.ev-stale {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  font-size: 12.5px;
  color: var(--text2);
  background: var(--hover);
  border-radius: 9px;
  padding: 9px 12px;
  margin: 10px 0 2px;
}
.ev-stale .chipbtn {
  flex: none;
}
.src {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--link);
  margin-right: 14px;
  text-decoration: none;
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  border: 1px solid var(--border);
  background: transparent;
  border-radius: 18px;
  padding: 4px 10px;
  font-size: 11.5px;
  color: var(--text2);
}
.chip.key {
  color: var(--text);
  border-color: var(--text2);
}
/* dashboard */
.pad {
  flex: 1;
  overflow: auto;
  padding: 26px 30px;
}
.pad-inner {
  max-width: 940px;
  margin: 0 auto;
}
.h1 {
  font-size: 19px;
  font-weight: 700;
  margin: 0 0 3px;
  letter-spacing: -0.01em;
}
.sub {
  color: var(--text2);
  font-size: 13px;
  margin-bottom: 20px;
}
/* ===== settings ===== */
.settings {
  flex: 1;
  display: flex;
  min-width: 0;
  min-height: 0;
}
.set-nav {
  width: 232px;
  flex: none;
  border-right: 1px solid var(--border);
  padding: 26px 16px;
  overflow: auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.set-title {
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.01em;
  padding: 0 8px 16px;
}
.set-sec {
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text2);
  font-weight: 700;
  padding: 6px 8px;
}
.set-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  background: transparent;
  border-radius: 9px;
  color: var(--text2);
  font-size: 13.5px;
  font-family: inherit;
  cursor: pointer;
  text-align: left;
}
.set-item .ico {
  color: var(--text2);
}
.set-item:hover {
  background: var(--hover);
  color: var(--text);
}
.set-item.active {
  background: var(--active);
  color: var(--text);
  font-weight: 600;
}
.set-item.active .ico {
  color: var(--text);
}
.set-divider {
  height: 1px;
  background: var(--border);
  margin: 10px 8px;
}
.set-main {
  flex: 1;
  overflow: auto;
  padding: 26px 30px;
  min-width: 0;
}
.set-h1 {
  font-size: 19px;
  font-weight: 700;
  margin: 0 0 18px;
  letter-spacing: -0.01em;
}
.set-card {
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 18px 20px;
  max-width: 560px;
  margin-bottom: 22px;
  background: var(--panel);
}
.set-id {
  display: flex;
  align-items: center;
  gap: 13px;
  padding-bottom: 16px;
  margin-bottom: 6px;
  border-bottom: 1px solid var(--border);
}
.set-avatar {
  width: 46px;
  height: 46px;
  border-radius: 50%;
  background: var(--active);
  color: var(--text);
  display: grid;
  place-items: center;
  font-size: 18px;
  font-weight: 700;
  flex: none;
}
.set-id-text {
  min-width: 0;
}
.set-name {
  font-size: 15px;
  font-weight: 600;
}
.set-muted {
  color: var(--text2);
  font-size: 12.5px;
}
.set-badge {
  margin-left: auto;
  font-size: 11px;
  font-weight: 700;
  color: var(--text2);
  border: 1px solid var(--border-2);
  border-radius: 999px;
  padding: 3px 9px;
  flex: none;
}
.set-field {
  display: flex;
  align-items: baseline;
  gap: 14px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
}
.set-field:last-child {
  border-bottom: 0;
}
.set-flabel {
  width: 88px;
  flex: none;
  color: var(--text2);
  font-size: 12.5px;
}
.set-fvalue {
  color: var(--text);
  font-size: 13.5px;
  min-width: 0;
}
.set-subh {
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text2);
  font-weight: 700;
  margin: 18px 0 8px;
}
.set-list {
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
  max-width: 560px;
}
.set-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
}
.set-row:last-child {
  border-bottom: 0;
}
.set-av {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--active);
  color: var(--text);
  display: grid;
  place-items: center;
  font-size: 11px;
  font-weight: 700;
  flex: none;
}
.set-row-name {
  font-weight: 500;
  color: var(--text);
}
.set-row .set-muted {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.set-count {
  margin-left: auto;
  color: var(--text2);
  font-size: 12px;
  flex: none;
}
.set-empty {
  color: var(--muted);
  font-size: 13px;
  padding: 24px 4px;
}
.set-lang-desc {
  color: var(--text2);
  font-size: 13px;
  margin: 0 0 12px;
  max-width: 560px;
}
button.set-lang-row {
  width: 100%;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--border);
  text-align: left;
  cursor: pointer;
  font: inherit;
  color: var(--text);
}
button.set-lang-row:last-child {
  border-bottom: 0;
}
button.set-lang-row:hover {
  background: var(--accent-soft);
}
/* Selection state is the one lime moment on this screen. */
.set-check {
  margin-left: auto;
  color: var(--accent-mark);
  display: flex;
  flex: none;
}
/* ===== pricing ===== */
/* Pricing centers like the home hero — both axes, guest and authed alike.
   The auto margins on head/grid do the vertical centering and stay
   overflow-safe: they collapse to 0 and the pane scrolls when the cards
   don't fit the viewport. */
.pricing {
  flex: 1;
  overflow: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 40px 30px;
}
.pricing-head,
.pricing-grid {
  width: 100%;
  max-width: 1320px;
}
.pricing-head {
  margin-top: auto;
  text-align: center;
  margin-bottom: 22px;
  /* Pricing entrance mirrors the home: the heading rises first, then the
     plan cards follow one by one (delays below). */
  animation: riseIn 0.34s cubic-bezier(0.22, 0.61, 0.36, 1) both;
}
.pricing-grid {
  margin-bottom: auto;
}
.pricing-card.set-card {
  animation: riseIn 0.34s cubic-bezier(0.22, 0.61, 0.36, 1) both;
  will-change: transform, opacity;
}
.pricing-grid .pricing-card:nth-child(1) {
  animation-delay: 0.1s;
}
.pricing-grid .pricing-card:nth-child(2) {
  animation-delay: 0.18s;
}
.pricing-grid .pricing-card:nth-child(3) {
  animation-delay: 0.26s;
}
.pricing-grid .pricing-card:nth-child(4) {
  animation-delay: 0.34s;
}
.pricing-head h1 {
  color: var(--heading);
  font-size: 24px;
  line-height: 1.2;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin: 0 0 8px;
}
.pricing-head p {
  color: var(--text2);
  font-size: 13.5px;
  margin: 0;
}
.pricing-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
  max-width: 1320px;
}
.pricing-card.set-card {
  max-width: none;
  margin-bottom: 0;
  display: flex;
  flex-direction: column;
  min-height: 384px;
}
.pricing-card.featured {
  border-color: var(--border-2);
  box-shadow: var(--shadow);
}
.pricing-card-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}
.pricing-plan {
  font-size: 16px;
  font-weight: 700;
}
.pricing-desc {
  color: var(--text2);
  font-size: 12.5px;
  margin: 5px 0 0;
}
.pricing-tag {
  flex: none;
  color: var(--on-accent);
  background: var(--accent);
  border-radius: 999px;
  padding: 3px 8px;
  font-size: 11px;
  font-weight: 800;
}
/* Launch-sale strike: the pre-discount price crossed out in the sale red,
   with a compact -NN% tag beside it, sitting right above the live price. */
.pricing-was-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 22px;
}
.pricing-was {
  color: var(--muted);
  font-size: 14px;
  font-weight: 600;
  text-decoration: line-through;
  text-decoration-color: var(--sale);
  text-decoration-thickness: 1.5px;
}
.pricing-off {
  color: var(--sale);
  background: var(--sale-bg);
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  padding: 3px 7px;
  border-radius: 999px;
}
.pricing-price {
  font-size: 28px;
  font-weight: 800;
  letter-spacing: -0.01em;
  margin-top: 22px;
}
/* "/월" billing-cycle suffix — quiet, so the amount stays the headline. */
.pricing-period {
  margin-left: 2px;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--muted);
}
/* When the strike row is present it owns the top gap. */
.pricing-was-row + .pricing-price {
  margin-top: 4px;
}
/* "Everything in Free, and" — a quiet caption above a plan's own features,
   marking that it builds on the tier below (Juicebox's "EVERYTHING IN …, AND:"). */
.pricing-inherit {
  margin-top: 22px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--text2);
}
.pricing-features {
  list-style: none;
  padding: 0;
  margin: 22px 0;
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 10px;
}
/* Tighten the gap when the inherit caption already spaced things out. */
.pricing-inherit + .pricing-features {
  margin-top: 10px;
}
.pricing-features li {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  color: var(--text);
  font-size: 13px;
}
.pricing-features .ico {
  color: var(--text2);
  margin-top: 2px;
}
.checkout-note {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: 8px;
  text-align: left;
  line-height: 1.55;
}
.dummy-payment-form {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.dummy-payment-summary,
.dummy-payment-notice {
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--panel-2);
  padding: 12px 13px;
}
.dummy-payment-summary .lab {
  color: var(--muted);
  font-size: 11px;
  font-weight: 700;
  margin-bottom: 6px;
}
.dummy-payment-summary .plan-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.dummy-payment-summary strong {
  font-size: 15px;
}
.dummy-payment-summary span {
  color: var(--text2);
  font-size: 14px;
  font-weight: 700;
}
/* Checkout-enquiry modal — a plan summary card that mirrors the pricing page
   copy, plus a labelled email field, spaced out so it doesn't read as one
   cramped stack. */
.checkout-form {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.checkout-plan {
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel-2);
  padding: 14px 15px;
}
.checkout-plan-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
}
.checkout-plan-lab {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text2);
}
.checkout-plan-name {
  font-size: 17px;
  font-weight: 700;
}
.checkout-plan-price {
  margin-left: auto;
  font-size: 14px;
  font-weight: 700;
  color: var(--text2);
}
.checkout-plan-desc {
  margin: 7px 0 0;
  font-size: 12.5px;
  color: var(--text2);
  line-height: 1.5;
}
.checkout-plan-features {
  list-style: none;
  margin: 12px 0 0;
  padding: 12px 0 0;
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 7px;
}
.checkout-plan-features li {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 13px;
  color: var(--text);
}
.checkout-plan-features .ico {
  color: var(--text2);
  margin-top: 1px;
}
.checkout-plan-inherit {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--text2);
}
.checkout-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.checkout-flabel {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text2);
}
/* Contact/feedback modal — checkout field styling plus a message box. */
.feedback-textarea {
  display: block;
  resize: none;
  min-height: 120px;
  line-height: 1.5;
}
/* Success note: icon and text on one centered line. */
.feedback-sent {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 20px 0;
  font-size: 13px;
  color: var(--text2);
  line-height: 1.5;
}
.feedback-sent .ico {
  flex: none;
}
.dummy-payment-notice {
  color: var(--text2);
  font-size: 12.5px;
  line-height: 1.55;
}
.dummy-payment-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.dummy-payment-field label {
  color: var(--text2);
  font-size: 12px;
  font-weight: 700;
}
.dummy-payment-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 10px;
}
.dummy-payment-hint {
  color: var(--muted);
  font-size: 12px;
}
@media (max-width: 1180px) {
  .pricing-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    max-width: 720px;
  }
}
@media (max-width: 980px) {
  .pricing-grid {
    grid-template-columns: 1fr;
    max-width: 560px;
  }
  .pricing {
    padding: 24px 20px;
  }
}
@media (max-width: 560px) {
  .dummy-payment-row {
    grid-template-columns: 1fr;
  }
  .credit-alert {
    align-items: stretch;
    flex-direction: column;
  }
  .credit-alert .btn {
    justify-content: center;
  }
}
/* ===== dashboard ===== */
.stages {
  display: flex;
  align-items: stretch;
  margin: 18px 0;
}
/* Layout-transparent: cards and connectors flex as siblings of .stages,
   so all three cards stay equal-width whether or not a connector precedes. */
.stg-cell {
  display: contents;
}
/* Connector: a fixed-length hairline tipped with a chevron — long enough to
   read as flow, short enough that the cards keep most of the room. */
.stg-sep {
  align-self: center;
  flex: none;
  width: 44px;
  height: 1px;
  margin: 0 12px;
  background: var(--muted);
  position: relative;
}
.stg-sep::after {
  content: "";
  position: absolute;
  right: 0;
  top: -3px;
  width: 6px;
  height: 6px;
  border-top: 1px solid var(--muted);
  border-right: 1px solid var(--muted);
  transform: rotate(45deg);
}
.stg {
  flex: 1;
  min-width: 0;
  text-align: left;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 11px 13px;
  cursor: pointer;
  color: var(--text2);
  font-family: inherit;
}
.stg:hover {
  background: var(--hover);
}
.stg.on {
  border-color: var(--text);
  color: var(--text);
}
.stg-l {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  font-weight: 600;
}
.stg-n {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 21px;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin-top: 2px;
  color: inherit;
}
.stg.on .stg-n {
  color: var(--text);
}
.stg .delta {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text2);
  white-space: nowrap;
}
.jobcard {
  border: 1px solid var(--border);
  background: var(--panel);
  border-radius: 13px;
  padding: 15px 17px;
  margin-bottom: 12px;
}
.jc-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.jc-title {
  font-weight: 700;
  /* Matches .rail-title — the dashboard's sibling column headers. */
  font-size: 13px;
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
.jc-meta {
  display: flex;
  align-items: center;
  gap: 7px;
  color: var(--text2);
  font-size: 12px;
  flex: none;
}
.jc-open {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--text);
  font-weight: 600;
  text-decoration: none;
  font-size: 12.5px;
  margin-left: 6px;
  border: 1px solid var(--border-2);
  border-radius: 8px;
  padding: 4px 9px;
  /* Also used as a <button> (JD/search criteria) — neutralize the UA chrome. */
  background: transparent;
  font-family: inherit;
  cursor: pointer;
}
.jc-open:hover {
  background: var(--hover);
}
.funnel {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 13px 0 4px;
  font-size: 12px;
  color: var(--text2);
}
.funnel .fstep b {
  color: var(--text);
  font-size: 14px;
  margin-right: 5px;
}
.funnel .fbar {
  position: relative;
  flex: 1;
  min-width: 80px;
  height: 6px;
  border-radius: 4px;
  background: var(--active);
  overflow: hidden;
  margin-left: 8px;
}
.funnel .fbar i {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  border-radius: 4px;
}
.funnel .fbar .sel {
  background: var(--border-2);
}
.funnel .fbar .sav {
  background: var(--accent);
}
.ctable {
  margin-top: 10px;
}
.crow {
  display: grid;
  /* rank · candidate · fit · then the Talent Pool column set verbatim:
     직무 · 회사 · 총 경력(년) · 평균 근속(년) · 학교 · 위치. The name column
     matches the other text columns (Talent Pool proportions) so 적합도 sits
     close to the name; the numeric columns are wide enough for their header
     label + sort arrows. */
  grid-template-columns:
    22px minmax(0, 1fr) 64px minmax(0, 1fr) minmax(0, 1fr) 84px 84px
    minmax(0, 1fr) minmax(0, 0.7fr);
  gap: 10px;
  align-items: center;
  width: 100%;
  padding: 8px 6px;
  border: 0;
  border-top: 1px solid var(--border);
  border-radius: 0;
  background: transparent;
  color: var(--text);
  font-family: inherit;
  font-size: 13px;
  text-align: left;
  cursor: pointer;
}
.crow:hover {
  background: var(--hover);
}
.crow.chead {
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  cursor: default;
  padding: 4px 6px;
  border-top: 0;
}
.crow.chead:hover {
  background: transparent;
}
/* Sortable header (이름 · 총 경력 · 평균 근속) — the ↑↓ pair is always
   visible; a long label ellipsizes before the arrows ever clip. Shared with
   the saved-roster table headers so both surfaces speak one sort language. */
.crow.chead .csort,
.roster-tbl th .csort {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  min-width: 0;
  border: 0;
  padding: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: inherit;
  cursor: pointer;
}
.crow.chead .csort .csort-label,
.roster-tbl th .csort .csort-label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.crow.chead .csort:hover,
.roster-tbl th .csort:hover {
  color: var(--text);
}
.crow.chead .csort.num,
.roster-tbl th .csort.num {
  justify-content: flex-end;
}
/* A rubric criterion's name is a phrase, and its column is narrow: it wraps
   instead of ellipsizing, with the arrows parked on the first line so they
   never float in the middle of a two-line header. */
.roster-tbl th .csort.wrap {
  align-items: flex-start;
  width: 100%;
}
.roster-tbl th .csort.wrap .csort-label {
  overflow: visible;
  white-space: normal;
}
.sort-arrows {
  display: inline-flex;
  flex: none;
  font-size: 10px;
  letter-spacing: -0.12em;
}
.sort-arrows i {
  font-style: normal;
  opacity: 0.45;
}
.sort-arrows i.on {
  opacity: 1;
  color: var(--text);
}
.crow .rank {
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.crow .who {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
}
.crow .av {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--active);
  display: grid;
  place-items: center;
  font-size: 10px;
  font-weight: 700;
  flex: none;
}
.crow .nm-row {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
}
.crow .nm {
  font-weight: 600;
  line-height: 1.3;
}
.crow .fit {
  display: flex;
  align-items: center;
}
.crow .fit b {
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}
/* Profile cells (Talent Pool column set) — quiet ink, truncate long values;
   numeric columns right-aligned like the pool table. */
.crow .cd {
  font-size: 12.5px;
  color: var(--text2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.crow .num {
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.sig {
  font-size: 10.5px;
  border: 1px solid var(--border);
  background: var(--panel-2);
  border-radius: 5px;
  padding: 2px 6px;
  color: var(--text2);
  white-space: nowrap;
}
.sig.stale {
  border-style: dashed;
  color: var(--text);
  font-weight: 600;
}
.sig.multi {
  color: var(--text);
}
.sig.note {
  color: var(--text);
}
.jc-empty {
  color: var(--muted);
  font-size: 12.5px;
  padding: 12px 2px 2px;
}
/* Master-detail: the position list scrolls in place (sticky, viewport-bound),
   so the dashboard stops growing taller with every session. */
.dash-md {
  display: flex;
  gap: 16px;
  align-items: flex-start;
}
.dash-positions {
  flex: none;
  /* Wide enough that a "FDE (Field Development Engineer) …"-style job title
     survives without truncating into noise. */
  width: 330px;
  border: 1px solid var(--border);
  background: var(--panel);
  border-radius: 13px;
  padding: 6px;
  position: sticky;
  top: 12px;
  max-height: calc(100vh - 230px);
  /* The aside itself must NOT clip: the project filter's dropdown opens over
     the list. Only the session list below the header scrolls (.pos-scroll). */
  display: flex;
  flex-direction: column;
}
.pos-scroll {
  overflow-y: auto;
  min-height: 0;
}
.dash-detail {
  flex: 1;
  min-width: 0;
  /* Keep the detail inside the available workspace width instead of letting
     wide candidate rows force the master-detail pair past its page edges. */
}
/* ── Overview section — heading + period/project controls, shortlist trend
   chart (tooltips, gridlines, grow-in bars) and sourced→shortlisted
   conversion. Monochrome CSS, no chart library. ── */
.dash-ov {
  border: 1px solid var(--border);
  background: var(--panel);
  border-radius: 15px;
  /* Roomy section: the overview reads as a calm summary, not a squeezed
     strip — and clear air before the stage tabs below. */
  padding: 22px 24px 20px;
  margin-bottom: 30px;
}
.ov-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}
.ov-h1 {
  font-size: 15px;
  font-weight: 700;
  color: var(--heading);
}
.ov-desc {
  margin-top: 2px;
  font-size: 12px;
  color: var(--text2);
}
.ov-controls {
  display: flex;
  align-items: center;
  gap: 8px;
}
/* Segmented period control (최근 30/90/180일). */
.ov-period {
  display: flex;
  border: 1px solid var(--border-2);
  border-radius: 9px;
  padding: 2px;
  gap: 2px;
}
.ov-pbtn {
  border: 0;
  background: transparent;
  color: var(--text2);
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  padding: 4px 9px;
  border-radius: 7px;
  cursor: pointer;
  white-space: nowrap;
}
.ov-pbtn:hover {
  background: var(--hover);
}
.ov-pbtn.on {
  background: var(--active);
  color: var(--heading);
}
/* The overview's project scope selector shares the rail picker's look. */
.ov-controls .dash-proj {
  margin: 0;
  width: 190px;
}
.ov-grid {
  display: flex;
  gap: 14px;
  margin-top: 18px;
}
.ov-card {
  flex: 1;
  min-width: 0;
  border: 1px solid var(--border);
  background: var(--bg);
  border-radius: 13px;
  padding: 16px 18px 14px;
}
.ov-card.ov-conv {
  flex: none;
  width: 320px;
  display: flex;
  flex-direction: column;
}
.ov-head {
  display: flex;
  align-items: center;
  gap: 8px;
}
.ov-title {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text);
}
.ov-delta {
  font-size: 11px;
  color: var(--text);
  font-weight: 600;
}
/* All-zero period — a quiet note keeps the card's height instead of a flat
   row of 0 bars that reads as broken. */
.ov-empty {
  display: grid;
  place-items: center;
  flex: 1;
  min-height: 120px;
  color: var(--muted);
  font-size: 12.5px;
  text-align: center;
  padding: 12px;
}
/* Bars plot — hairline grid behind the bars, baseline above the date row. */
.ov-plot {
  position: relative;
  display: flex;
  align-items: flex-end;
  gap: 6px;
  margin-top: 18px;
}
.ov-lines {
  position: absolute;
  left: 0;
  right: 0;
  top: 14px;
  bottom: 17px;
  border-bottom: 1px solid var(--border-2);
  background: repeating-linear-gradient(
    to top,
    transparent 0,
    transparent calc(33.4% - 1px),
    var(--border) calc(33.4% - 1px),
    var(--border) 33.4%
  );
  opacity: 0.7;
  pointer-events: none;
}
.ov-col {
  position: relative;
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  min-width: 0;
  z-index: 1;
}
/* Hover tooltip — "7/27 – 8/2 · 관심후보 2명" on an inverted chip. */
.ov-tip {
  position: absolute;
  top: -26px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--text);
  color: var(--bg);
  font-size: 11px;
  font-weight: 600;
  padding: 4px 8px;
  border-radius: 7px;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.12s ease;
  z-index: 5;
}
.ov-col:hover .ov-tip {
  opacity: 1;
}
.ov-n {
  font-size: 10.5px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.ov-bar {
  width: 100%;
  max-width: 46px;
  background: var(--text);
  opacity: 0.24;
  border-radius: 3px 3px 0 0;
  transform-origin: bottom;
  animation: ovGrow 0.45s ease backwards;
  animation-delay: calc(var(--i, 0) * 40ms);
  transition: opacity 0.12s ease;
}
.ov-col:hover .ov-bar {
  opacity: 0.6;
}
.ov-bar.now {
  opacity: 0.55;
}
.ov-bar.empty {
  opacity: 0.08;
}
@keyframes ovGrow {
  from {
    transform: scaleY(0);
  }
}
.ov-w {
  font-size: 10px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
/* Conversion card — mini funnel: full sourced bar over a rate-wide shortlist
   bar, with the % as a lime badge (the section's single key accent). */
.ov-badge {
  margin-left: auto;
  background: var(--accent);
  color: #1a1d1f;
  font-size: 11px;
  font-weight: 700;
  padding: 3px 8px;
  border-radius: 7px;
  white-space: nowrap;
}
.ov-funnel {
  display: flex;
  flex-direction: column;
  gap: 18px;
  /* Dead-center the funnel in the space under the card title. */
  margin: auto 0;
  padding: 16px 0;
}
.ov-frow {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.ov-fmeta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}
.ov-k {
  font-size: 12px;
  color: var(--text2);
}
.ov-fmeta b {
  color: var(--heading);
  font-size: 20px;
  font-weight: 700;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.ov-ftrack {
  height: 10px;
  border-radius: 6px;
  background: var(--active);
}
.ov-ftrack i {
  display: block;
  height: 100%;
  border-radius: 6px;
  background: var(--text);
  opacity: 0.35;
  transform-origin: left;
  animation: ovGrowX 0.55s ease backwards;
}
.ov-ftrack i.full {
  width: 100%;
  opacity: 0.18;
}
@keyframes ovGrowX {
  from {
    transform: scaleX(0);
  }
}
@media (prefers-reduced-motion: reduce) {
  .ov-bar,
  .ov-ftrack i {
    animation: none;
  }
}
/* Session-rail header — names the master list (소싱 세션); the project scope
   selector sits directly under it. Shares one typographic level with the
   detail card's session name (.jc-title) so the columns read as siblings. */
.rail-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--heading);
  padding: 6px 8px 8px;
}
/* Onboarding / scoped-to-empty note — centered in the full pane width (no
   rail chrome renders alongside it). */
.dash-empty-hero {
  margin: 48px auto 0;
  max-width: 480px;
}
/* Rail row + its chat-history trigger are sibling buttons (buttons can't
   nest); the bubble overlays the row's right edge. */
.pos-row {
  position: relative;
}
.pos-row .pos {
  padding-right: 36px;
}
.pos-chat {
  position: absolute;
  top: 50%;
  right: 7px;
  transform: translateY(-50%);
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  /* Outlined like a real button — it opens a popup, so it should read as
     pressable rather than as a status glyph. */
  border: 1px solid var(--border-2);
  border-radius: 8px;
  background: var(--panel);
  color: var(--text2);
  cursor: pointer;
}
.pos-chat:hover {
  background: var(--active);
  color: var(--text);
}
/* Session chat popup — read-only log of one session's conversation, with the
   criteria / open-session actions in its header. */
.chat-modal .modal-body {
  /* The log (not the modal body) is the scroller, so the bottom-anchor jump
     lands on the right element. */
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-height: 0;
  padding: 14px 18px;
}
/* Popup actions row — under the header (a long session title would squeeze
   header-side actions into the close button). */
.cm-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  /* A rule under the row, on the header's own line: the actions are chrome
     for the popup, and without it the first message reads as if it belonged
     to the button above it. */
  padding: 12px 22px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.cm-actions .jc-open {
  margin-left: 0;
}
.dc-scroll {
  overflow-y: auto;
  min-height: 0;
}
.dc-empty {
  color: var(--muted);
  font-size: 12.5px;
  padding: 4px 0 8px;
}
/* Compact bubbles — the popup reuses the session chat classes at list scale. */
.chat-modal .msg {
  margin-bottom: 10px;
  max-width: 100%;
}
.chat-modal .msg.ai {
  gap: 4px;
}
/* The agent mark shrinks to a footnote size in the compact log. */
.chat-modal .ai-mark,
.chat-modal .ai-mark img {
  width: 18px;
  height: 18px;
}
.chat-modal .msg.user {
  max-width: 88%;
}
.chat-modal .bubble {
  font-size: 12.5px;
  line-height: 1.55;
}
.chat-modal .md :is(p, ul, ol, pre, table) {
  margin: 0 0 8px;
  font-size: 12.5px;
}
.chat-modal .md :is(h1, h2, h3, h4) {
  font-size: 12.5px;
  margin: 10px 0 6px;
}
.pos-group {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 10px 8px 4px;
}
.pos {
  display: flex;
  flex-direction: column;
  gap: 3px;
  width: 100%;
  text-align: left;
  background: transparent;
  border: 0;
  border-radius: 8px;
  padding: 8px;
  cursor: pointer;
  color: var(--text);
  font-family: inherit;
}
.pos:hover {
  background: var(--hover);
}
.pos.on {
  background: var(--active);
}
.pos-title {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  font-size: 12.5px;
  font-weight: 600;
}
.pos-title .live-dot {
  flex: none;
}
.pos-sub {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  color: var(--text2);
}
.pos-session {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px;
  border-radius: 8px;
  color: var(--text);
  text-decoration: none;
  font-size: 12.5px;
}
.pos-session:hover {
  background: var(--hover);
}
.pos-session .ps-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1;
}
.pos-session .ps-title {
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pos-session .ps-sub {
  font-size: 11px;
  color: var(--text2);
}
/* Project scope selector — sits in the session rail under its title. */
.dash-proj {
  margin: 0 2px 6px;
}
.dash-cta {
  display: inline-flex;
  margin-top: 12px;
  padding: 8px 14px;
  border-radius: 9px;
  background: var(--text);
  color: var(--bg);
  font-weight: 700;
  font-size: 13px;
  text-decoration: none;
}
.dash-cta:hover {
  opacity: 0.9;
}
.saved-row {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
}
/* auth / login */
.auth-wrap {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 32px;
}
.auth-card {
  position: relative; /* anchors the floating back chip */
  width: 100%;
  max-width: 380px;
}
.auth-card .brand {
  justify-content: center;
  font-size: 22px;
  margin-bottom: 6px;
}
.auth-title {
  text-align: center;
  font-size: 15px;
  line-height: 24px;
  color: var(--text2);
  margin-bottom: 24px;
  /* Keep centered titles clear of the floated back chip on both sides. */
  padding: 0 56px;
}
.auth-input {
  width: 100%;
  border: 1px solid var(--border-2);
  border-radius: 11px;
  background: var(--panel-2);
  color: var(--text);
  font-family: inherit;
  font-size: 14px;
  padding: 11px 13px;
  outline: none;
}
.auth-input:focus {
  border-color: var(--text2);
}
/* The submit matches the input's mass and radius so the pair reads as one
   composed block. */
.auth-card .btn-block {
  padding: 10px 14px;
  border-radius: 11px;
}
.auth-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--muted);
  font-size: 12px;
  margin: 16px 0;
}
.auth-divider::before,
.auth-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border);
}
.auth-note {
  font-size: 12px;
  color: var(--text2);
  text-align: center;
  margin-top: 14px;
}

/* Juicebox-style entry buttons: a vertical stack of full-width choices on the
   first screen (Google / Email / SSO), each centering an icon + label. */
.auth-choices {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.auth-choice {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 13px 16px;
  border-radius: 11px;
  border: 1px solid var(--border-2);
  background: var(--panel-2);
  color: var(--text);
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.auth-choice:hover {
  background: var(--hover);
}
.auth-choice[disabled] {
  opacity: 0.5;
  cursor: default;
}
/* Back link on the email sub-view (returns to the choice screen). */
/* Ghost chip pinned to the card's left, vertically centred against the
   logo + title block (block spans 0–51px from the card top; 24px chip →
   top 13px puts both centres at ~25px). */
.auth-back {
  position: absolute;
  left: 0;
  top: 13px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  box-sizing: border-box;
  height: 24px;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--text2);
  font-family: inherit;
  font-size: 12px;
  cursor: pointer;
  padding: 0 10px 0 7px;
}
.auth-back:hover {
  color: var(--text);
  border-color: var(--border-2);
  background: var(--hover);
}
.auth-back .ico {
  transform: rotate(180deg);
}
/* Terms / privacy links — auth screens only. Quiet caption pinned to the very
   bottom of the viewport: plain grey text links, no key color. */
.auth-legal {
  position: fixed;
  bottom: 36px;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  color: var(--muted);
  font-size: 11.5px;
}
.auth-legal a {
  color: var(--text2);
  text-decoration: none;
}
.auth-legal a:hover {
  color: var(--text);
  text-decoration: underline;
}

/* Legal nav for the logged-out surfaces. `.auth-legal` above pins the same
   markup to the viewport on the auth card; here it sits in flow so it can be
   scrolled to on the guest home and at the foot of a long document. */
.guest-legal {
  /* Matches .guest-header: the guest shell is a 100vh column with overflow
     hidden, so chrome must refuse to shrink or it gets clipped away. */
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 20px 16px 28px;
  color: var(--muted);
  font-size: 11.5px;
}
.guest-legal a {
  color: var(--text2);
  text-decoration: none;
}
.guest-legal a:hover {
  color: var(--text);
  text-decoration: underline;
}

/* ===== legal documents (/terms, /privacy) ===== */
/* Public long-form pages under the guest top bar: one readable centered
   column, its own scroll container (.app clips overflow at the viewport). */
.legal-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}
.legal-doc {
  max-width: 680px;
  margin: 0 auto;
  padding: 48px 32px 96px;
  color: var(--text2);
  font-size: 14px;
  line-height: 1.75;
}
.legal-doc h1 {
  color: var(--text);
  font-size: 24px;
  font-weight: 700;
  margin: 0 0 6px;
}
.legal-doc h2 {
  color: var(--text);
  font-size: 15px;
  font-weight: 600;
  margin: 28px 0 6px;
}
.legal-doc p {
  margin: 0 0 12px;
}
.legal-effective {
  color: var(--muted);
  font-size: 12.5px;
  margin-bottom: 24px;
}
.legal-intro {
  margin-bottom: 8px;
}
/* Refund terms table. Kept as a real table (not flattened prose) so the
   reviewed wording per purchase type survives verbatim; scrolls inside its
   own box on narrow screens rather than widening the page. */
.legal-tablewrap {
  overflow-x: auto;
  margin: 10px 0 14px;
}
.legal-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  line-height: 1.6;
}
.legal-table th,
.legal-table td {
  border: 1px solid var(--border);
  padding: 8px 10px;
  text-align: left;
  vertical-align: top;
}
.legal-table th {
  color: var(--text);
  font-weight: 600;
  background: var(--panel);
  white-space: nowrap;
}
/* The purchase-type column is a short label ("크레딧 팩"); letting it wrap
   mid-phrase reads as two rows. The condition/outcome cells still wrap. */
.legal-table td:first-child {
  white-space: nowrap;
}
/* The reset strips list markers globally, so restore them here — these are
   enumerated legal restrictions and have to read as a list, not as lines. */
.legal-list {
  list-style: disc;
  margin: 0 0 12px;
  padding-left: 20px;
}
.legal-list-num {
  list-style: decimal;
}
.legal-list li {
  margin-bottom: 4px;
}
/* Numbered sub-clause heading inside a section (4.1, 2.1 …). */
.legal-subtitle {
  color: var(--text);
  font-size: 13.5px;
  font-weight: 600;
  margin: 18px 0 6px;
}
/* The Google Limited Use statement must appear verbatim for OAuth review —
   set apart so it reads as quoted policy text rather than our prose. */
.legal-quote {
  margin: 0 0 12px;
  padding: 10px 14px;
  border-left: 2px solid var(--border);
  background: var(--panel);
  color: var(--text);
}
/* Cross-reference between legal documents (약관 → 환불정책). Underlined
   rather than key-colored: these pages carry no accent. */
.legal-link {
  color: var(--text);
  text-decoration: underline;
}
/* Inline key-color action link: "Forgot password" / "Resend" / "Log out". */
.auth-link {
  background: transparent;
  border: none;
  padding: 0;
  font: inherit;
  color: var(--accent-ink);
  cursor: pointer;
}
.auth-link:hover {
  text-decoration: underline;
}
.auth-link[disabled] {
  opacity: 0.6;
  cursor: default;
}

/* ===== criteria-ready start card ===== */
.start-card {
  border: 1px solid var(--border-2);
  border-left: 2px solid var(--text2);
  border-radius: 12px;
  padding: 13px 15px;
  margin: 4px 0 14px;
  background: var(--panel);
}
.start-card .lab {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text2);
  font-weight: 700;
  margin-bottom: 7px;
}
.start-card .role {
  font-weight: 700;
  font-size: 14px;
  margin-bottom: 4px;
}
.start-card .hint {
  color: var(--text2);
  font-size: 12px;
  margin-bottom: 11px;
}
.start-card .sc-actions {
  display: flex;
  gap: 8px;
}

/* ===== JD upload modal ===== */
.modal.jdm {
  max-width: 480px;
}
/* Person share modal — a compact sharing dialog, sized close to the session
   sharing card rather than a general-purpose information modal. */
.modal.pshare {
  max-width: 360px;
}
.modal.pshare .modal-head {
  gap: 10px;
  padding: 14px 16px;
}
.modal.pshare .modal-head .d-av {
  width: 36px;
  height: 36px;
  font-size: 14px;
}
.modal.pshare .modal-body {
  padding: 16px;
}
.jdm-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  font-weight: 700;
  color: var(--text2);
  margin: 14px 0 6px;
}
.jdm-label:first-child {
  margin-top: 0;
}
.jdm-input {
  width: 100%;
  border: 1px solid var(--border-2);
  background: var(--bg);
  color: var(--text);
  border-radius: 9px;
  padding: 9px 11px;
  font-size: 13px;
  font-family: inherit;
}
.jdm-input:focus {
  outline: none;
  border-color: var(--text2);
}
.jdm-input:disabled {
  opacity: 0.5;
}
.jdm-textarea {
  display: block;
  resize: none;
  min-height: 58px;
  max-height: 140px;
  line-height: 1.5;
  overflow-y: auto;
}
.jdm-or {
  text-align: center;
  font-size: 11px;
  color: var(--text2);
  margin: 12px 0;
}
.jdm-drop {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  border: 1.5px dashed var(--border-2);
  background: transparent;
  color: var(--text2);
  border-radius: 11px;
  padding: 18px 12px;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
}
.jdm-drop:hover {
  color: var(--text);
  border-color: var(--text2);
}
.jdm-file {
  display: flex;
  align-items: center;
  gap: 8px;
  border: 1px solid var(--border-2);
  background: var(--panel);
  border-radius: 11px;
  padding: 10px 12px;
  font-size: 13px;
}
.jdm-file .name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
}
.jdm-error {
  margin-top: 10px;
  font-size: 12px;
  color: var(--text);
  border: 1px solid var(--border-2);
  border-left: 3px solid var(--text);
  border-radius: 7px;
  padding: 8px 10px;
}
.jdm-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 18px;
}

/* ===== candidate dossier (structured profile) ===== */
/* The report's PDF button states itself: dimmed while the server renders,
   marked while a failed attempt is still waiting to be retried. There is no
   toast in this app, and a button that silently did nothing reads as broken. */
.iconbtn[aria-busy="true"],
.btn[aria-busy="true"] {
  opacity: 0.55;
  cursor: default;
}
.iconbtn[data-state="failed"] {
  color: var(--warn);
  background: var(--hover);
}
/* Taking the report away is the modal header's one action, so it wears the
   accent — as a pill, matching the selection bar's shape. A failed attempt
   drops the accent: keeping it would advertise a button that just refused. */
.report-dl {
  border-radius: 999px;
  white-space: nowrap;
}
.report-dl[data-state="failed"] {
  background: transparent;
  border-color: var(--border-2);
  color: var(--warn);
}

.dos {
  max-width: 820px;
}
.dos-head {
  display: flex;
  align-items: flex-start;
  gap: 16px;
}
.dos-id {
  flex: 1;
  min-width: 0;
}
.dos-name {
  font-size: 22px;
  font-weight: 800;
  letter-spacing: -0.01em;
  margin: 0;
}
.dos-headline {
  font-size: 13.5px;
  color: var(--text2);
  margin-top: 3px;
}
.dos-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  margin-top: 7px;
}
.dos-meta .m {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  color: var(--text2);
}
/* Links match the location line's format — icon + text, no chip box. */
.dos-links {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  margin-top: 6px;
}
.dos-links .chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  font-size: 12.5px;
  color: var(--text2);
  text-decoration: none;
}
.dos-links .chip:where(:has([data-ico="linkedin"])),
.d-links .d-link:where(:has([data-ico="linkedin"])) {
  color: #2563eb;
}
.dos-links .chip[data-link-kind="github"],
.d-links .d-link[data-link-kind="github"] {
  color: var(--github-link);
}
.dos-links .chip[data-link-kind="portfolio"],
.d-links .d-link[data-link-kind="portfolio"] {
  color: var(--accent-ink);
}
.dos-links .chip[data-link-kind="press"],
.d-links .d-link[data-link-kind="press"] {
  color: var(--press-link);
}
.dos-links .chip:hover,
.d-links .d-link:hover {
  color: var(--text);
}
.dos-links .chip:has([data-ico="linkedin"]):hover,
.d-links .d-link:has([data-ico="linkedin"]):hover {
  color: color-mix(in srgb, #2563eb 80%, #1d2027);
}
.dos-links .chip[data-link-kind="github"]:hover,
.d-links .d-link[data-link-kind="github"]:hover {
  color: color-mix(in srgb, var(--github-link) 80%, var(--text2));
}
.dos-links .chip[data-link-kind="portfolio"]:hover,
.d-links .d-link[data-link-kind="portfolio"]:hover {
  color: color-mix(in srgb, var(--accent-ink) 80%, var(--heading));
}
.dos-links .chip[data-link-kind="press"]:hover,
.d-links .d-link[data-link-kind="press"]:hover {
  color: color-mix(in srgb, var(--press-link) 80%, var(--heading));
}
.dos-rec {
  flex: none;
  text-align: center;
}
.dos-score {
  font-size: 26px;
  font-weight: 800;
  line-height: 1;
}
.dos-verdict {
  margin-top: 5px;
  font-size: 11px;
  font-weight: 700;
  padding: 3px 9px;
  border-radius: 20px;
  border: 1px solid var(--border-2);
  color: var(--text2);
}
.dos-verdict.v-strong_yes,
.dos-verdict.v-yes {
  color: var(--text);
  border-color: var(--text);
}
.dos-reason {
  font-size: 12.5px;
  color: var(--text2);
  line-height: 1.6;
  margin: 12px 0 0;
  padding: 10px 12px;
  background: var(--hover);
  border-radius: 9px;
}
.dos-reason .md p:first-child {
  margin-top: 0;
}
.dos-reason .md p:last-child,
.dos-reason .md ul:last-child {
  margin-bottom: 0;
}
.dos-act-insight {
  font-size: 13px;
  color: var(--text);
  line-height: 1.7;
  margin: 0 0 12px;
}
.dos-sec {
  margin-top: 26px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
}
.dos-h {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 16.5px;
  color: var(--text);
  font-weight: 800;
  letter-spacing: -0.01em;
  margin-bottom: 14px;
}
.dos-h .n {
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
}
/* Section-heading glyphs carry the key color — the one place it's used in the
   dossier, as a scannable anchor for each section. */
.dos-h .ico {
  color: var(--accent-mark);
}
.dos-body {
  font-size: 13px;
}
/* Structured summary: lead sentence + labelled bullet groups (new report shape). */
/* Summary markdown: drop the bold lead-in label (Current role / Area of
   expertise / Achievements & strengths …) onto its own line so the body text
   below reads as a labelled block rather than a run-on paragraph. */
.dos-summary .md p > strong:first-child {
  display: block;
  margin-bottom: 1px;
}
/* Quick facts above the dossier summary — same rows as the detail panel, but
   unboxed so they read as a natural lead-in rather than a bordered card. */
/* Quick facts above the summary — boxed label|value rows, matching the detail
   panel's Overview card, per request. Uses the default .d-facts card styling. */
.dos-facts {
  margin: 6px 0 8px;
}
.dsum {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.dsum-now {
  margin: 0;
  font-size: 14.5px;
  line-height: 1.55;
  font-weight: 600;
  color: var(--text);
}
.dsum-label {
  margin-bottom: 6px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--text2);
}
.dsum-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.dsum-list li {
  position: relative;
  padding-left: 14px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text);
}
.dsum-list li::before {
  content: "";
  position: absolute;
  left: 3px;
  top: 8px;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--muted);
}
/* Markdown inside the dossier (summary / contribution / code style) must not
   draw its own "---" rules — section borders already separate headings — and
   its lists align flush with a hanging dash rather than a tab-like browser
   indent. */
.dos .md hr {
  display: none;
}
.dos .md ul {
  list-style: none;
  padding-left: 0;
}
.dos .md ul > li {
  position: relative;
  padding-left: 15px;
}
.dos .md ul > li::before {
  content: "";
  position: absolute;
  left: 3px;
  top: 0.6em;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--muted);
}
/* Items within a section are separated by spacing only — full-width rules are
   reserved for section (heading) boundaries, so the report doesn't read as a
   ladder of "---" lines between every company / repo. */
.dos-co,
.dos-repo,
.dos-paper {
  padding: 0;
  margin-top: 18px;
}
.dos-co:first-of-type,
.dos-repo:first-of-type,
.dos-paper:first-of-type {
  margin-top: 0;
}
.dos-co-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}
.dos-co-name {
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
  text-decoration: none;
}
a.dos-co-name:hover {
  text-decoration: underline;
}
.dos-co-when {
  flex: none;
  font-size: 12px;
  color: var(--muted);
}
.dos-co-fin {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 8px;
  margin: 8px 0 2px;
}
.dos-co-fin .kv,
.dos-gh-meta .kv {
  font-size: 11.5px;
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 7px;
  padding: 3px 8px;
}
.dos-co-fin .kv .k,
.dos-gh-meta .kv .k {
  color: var(--muted);
  margin-right: 5px;
}
/* Company facts as a compact "label value" list (not boxed chips). */
.dos-co-facts {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: 6px 0 0;
}
.dos-co-facts .fact {
  display: flex;
  gap: 5px;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--text);
}
/* Inline "Revenue: value" — no fixed-width label column (the tab-aligned look
   read as an empty gap between short labels and their values). */
.dos-co-facts .fact .k {
  flex: 0 0 auto;
  color: var(--muted);
  font-weight: 600;
}
.dos-co-facts .fact .k::after {
  content: ":";
}
/* Company blurb in body-text white, no label. Revenue/size/funding ·
   contribution evenly spaced. */
.dos-co-what {
  font-size: 12.5px;
  color: var(--text);
  line-height: 1.6;
  margin: 6px 0 0;
}
.dos-co-contrib {
  margin-top: 6px;
}
.dos-co-contrib .k {
  display: block;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--muted);
  margin-bottom: 5px;
}
.dos-co-contrib .dsum-list {
  font-size: 12.5px;
}
/* Overline-style sub-labels ("Code style", "Key projects", …): small, muted
   and letter-spaced so a label never reads as the first line of the body. */
.dos-sub-h {
  display: block;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 7px;
}
/* Sub-blocks inside one dossier section (e.g. GitHub's Code style / Key
   projects / Recent commits) — spaced apart so adjacent blocks don't run
   together. */
.dos-sub {
  margin-top: 20px;
}
.dos-sub:first-of-type {
  margin-top: 0;
}
/* .badge (e.g. 1st author) stays a real inline chip next to a title. */
.badge {
  display: inline-block;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--text);
  border: 1px solid var(--text);
  border-radius: 6px;
  padding: 1px 6px;
  margin: 0 0 0 8px;
}
/* Work-style module: the "observed, not judged" disclaimer, and confidence
   badges muted by strength so a weak signal never looks like a hard verdict. */
.dos-ws-note {
  font-size: 12px;
  color: var(--muted);
  margin: 8px 0 2px;
  line-height: 1.5;
}
.badge[data-conf="weak"] {
  color: var(--muted);
  border-color: var(--muted);
  font-weight: 600;
  opacity: 0.85;
}
.badge[data-conf="likely"] {
  color: var(--text2);
  border-color: var(--text2);
}
.dos-news {
  list-style: none;
  margin: 9px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.dos-news li {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 12.5px;
}
.dos-news a {
  color: var(--text);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.dos-news .src {
  color: var(--muted);
  font-size: 11.5px;
}
/* A quiet, inline pull-quote — NOT the home-screen `.ex` example chip (which is
   a rounded bordered pill). Own class so that global style never bleeds in. */
.dos-news .dos-ex {
  color: var(--text2);
  font-size: 12px;
  font-style: italic;
}
.dos-gh-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 12px;
  font-size: 12.5px;
}
.dos-gh-meta a {
  color: var(--text);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.dos-repo-contrib {
  font-size: 12.5px;
  color: var(--text);
  line-height: 1.55;
  margin: 6px 0 0;
}
/* A repo/paper's summary + contribution as one bullet list (reuses .dsum-list
   dots) — reads as structured points instead of stacked prose paragraphs. */
.dos-item-bullets {
  margin-top: 6px;
  font-size: 12.5px;
}
.dos-commits {
  list-style: none;
  /* Sits under its "Recent commits" sub-label — the label owns the gap. */
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.dos-commits li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
}
.dos-commits code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  background: var(--hover);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 1px 6px;
  color: var(--text2);
}
.dos-commits a {
  color: var(--text);
  text-decoration: none;
}
.dos-commits a:hover {
  text-decoration: underline;
}
.dos-commits .src {
  color: var(--muted);
  font-size: 11px;
  margin-left: auto;
}
.dos-ev {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.dos-ev-claim {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  display: flex;
  align-items: center;
  gap: 8px;
}
.dos-ev-claim .conf {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 1px 6px;
  border-radius: 5px;
  border: 1px solid var(--border);
  color: var(--muted);
}
.dos-ev-claim .conf.c-verified {
  color: var(--text);
  border-color: var(--text);
}
.dos-ev-find {
  font-size: 12.5px;
  color: var(--text2);
  line-height: 1.6;
  margin-top: 4px;
}
.dos-ev-src {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11.5px;
  color: var(--text2);
  text-decoration: none;
  margin-top: 5px;
}
.dos-ev-src:hover {
  color: var(--text);
}
/* Flush bullet list: a hanging "–" sits at the section's left edge and wrapped
   lines align under the text — no browser bullet indent that reads as a tab. */
.dos-q {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 13px;
  color: var(--text2);
  line-height: 1.7;
}
.dos-q li {
  position: relative;
  padding-left: 15px;
}
.dos-q li::before {
  content: "–";
  position: absolute;
  left: 0;
  top: 0;
  color: var(--muted);
}

/* ── Session sharing ─────────────────────────────────────────────────────── */
/* Share popover (owner side) — monochrome, anchored top-right. */
.sharewrap {
  position: relative;
}
.sharepop {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  width: 300px;
  background: var(--elev);
  border: 1px solid var(--border-2);
  border-radius: 14px;
  box-shadow: var(--shadow-lg);
  padding: 12px;
  z-index: 200;
  animation: popUp 0.14s ease;
}
.sharepop .sp-options {
  min-inline-size: 0;
  margin: 0;
  padding: 0;
  overflow: hidden;
  border: 1px solid var(--border-2);
  border-radius: 11px;
}
.sharepop .sp-title {
  font-size: 13px;
  font-weight: 600;
  padding: 2px 4px 10px;
}
.sharepop .sp-opt {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 11px 12px;
  margin: 0;
  background: transparent;
  border: 0;
  border-radius: 0;
  color: var(--text);
  cursor: pointer;
  font-size: 13px;
  font-family: inherit;
  text-align: left;
}
.sharepop .sp-opt:hover {
  background: var(--hover);
}
.sharepop .sp-opt + .sp-opt {
  border-top: 1px solid var(--border);
}
.sharepop .sp-opt.active {
  background: var(--active);
}
.sharepop .sp-name {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.sharepop .sp-desc {
  font-size: 11.5px;
  color: var(--text2);
  font-weight: 400;
}
.sharepop .sp-copy {
  width: 100%;
  justify-content: center;
  margin-top: 4px;
}
/* Reuse the .sp-* option styles inside the person share modal — drop the
   popover chrome (position/width/shadow) since the modal shell provides it. */
.share-modal.sharepop {
  position: static;
  width: auto;
  padding: 0;
  border: 0;
  box-shadow: none;
  background: transparent;
  animation: none;
  z-index: auto;
}
/* Read-only shared session page (/share/<token>) — public shell. */
.share-page {
  display: flex;
  flex-direction: column;
  height: 100dvh;
}
.share-top {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 18px;
  border-bottom: 1px solid var(--border);
}
.share-top .st-logo {
  font-weight: 700;
  letter-spacing: -0.02em;
}
.share-top .st-title {
  font-size: 13.5px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.share-top .st-meta {
  font-size: 12px;
  color: var(--text2);
  white-space: nowrap;
}
.share-top .st-cta {
  margin-left: auto;
}
.share-body {
  flex: 1;
  min-height: 0;
}
.share-body .split {
  height: 100%;
}
.share-body .split.share-screening {
  grid-template-columns: minmax(0, 1fr);
}
.share-screening .candpane {
  box-shadow: none;
}
.share-foot {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 9px 16px;
  border-top: 1px solid var(--border);
  font-size: 12px;
  color: var(--text2);
}
.share-loading,
.share-gone {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text2);
  font-size: 14px;
}
/* Public shared profile page (/share/person/<token>). The scroll area centers
   a bordered card so the profile reads as a self-contained document, not text
   floating on the page background. */
.sp-scroll {
  overflow-y: auto;
  display: flex;
  justify-content: center;
  padding: 28px 20px 56px;
}
.sp-card {
  width: 100%;
  max-width: 820px;
  height: fit-content;
  background: var(--elev);
  border: 1px solid var(--border);
  border-radius: 18px;
  padding: 40px 40px 44px;
}
/* Inside the elevated share card, the default --border facts box nearly
   vanishes — bump it to the stronger --border-2 so the box reads clearly. */
.sp-card .d-facts {
  border-color: var(--border-2);
}
/* Give every tag/chip in the card the same crisp outline as the Skills chips
   (.chip.key uses --text2), so the interests/topic chips aren't washed out. */
.sp-card .chip {
  border-color: var(--text2);
  color: var(--text);
}
.sp-hero {
  display: flex;
  gap: 18px;
  align-items: center;
  margin-bottom: 24px;
}
.sp-hero-av {
  width: 72px;
  height: 72px;
  border-radius: 50%;
  object-fit: cover;
  flex: none;
  background: var(--elev);
}
.sp-hero-av-fallback {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 28px;
  font-weight: 600;
  color: var(--text2);
  border: 1px solid var(--border);
}
/* Standalone profile photo above the dossier on the public share page. */
.sp-solo-av {
  display: block;
  margin-bottom: 18px;
}
.sp-hero-name {
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.02em;
}
.sp-hero-sub {
  font-size: 14px;
  color: var(--text2);
  margin-top: 3px;
}
.sp-hero-links {
  display: flex;
  gap: 14px;
  margin-top: 8px;
}
.sp-hero-links a {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 13px;
  color: var(--text2);
}
.sp-hero-links a:hover {
  color: var(--text);
}
.sp-section {
  margin-top: 28px;
}
.sp-section-h {
  font-size: 13px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text2);
  margin-bottom: 12px;
}
.sharepop .sp-err {
  padding: 8px 4px 2px;
  font-size: 12px;
  color: var(--text2);
}
/* Narrow-screen guard for the public share page — mirrors the authed shell
   (.app) rule above. The two-pane share layout is just as dense, so below
   1000px we hide it and let the shared .app-size-guard notice take over. */
@media (max-width: 999px) {
  /* The single-profile person share is readable on narrow screens, so it opts
     out of the guard (:not(.share-person)); only the dense 2-pane session
     share is hidden below 1000px. */
  .share-page:not(.share-person) > .share-top,
  .share-page:not(.share-person) > .share-body,
  .share-page:not(.share-person) > .share-foot {
    display: none;
  }
}

/* ── Wide layouts + responsive + Korean-aware wrapping ───────────────────── */
/* Secondary data pages keep a readable cap. */
.pad-inner.wide {
  max-width: 1246px;
}
/* Primary navigation workspaces use the full main pane. The outer .pad keeps
   their compact, consistent gutter beside the sidebar and viewport edge. */
.pad-inner.workspace-content {
  max-width: none;
}

/* Korean titles must wrap at word boundaries, not mid-syllable-block (e.g.
   "프로토타이핑" / prototyping breaking into "프로토타이" + "핑"); break-word
   still rescues unbroken English tokens. */
.jc-title,
.pos-title,
.crow .nm,
.st-title {
  word-break: keep-all;
  overflow-wrap: break-word;
}
/* A long JD title gets its own line; the meta row wraps below it instead of
   squeezing the title into an awkward two-character-wide column. */
.jc-head {
  flex-wrap: wrap;
}
.jc-title {
  flex: 1 1 100%;
}
.jc-meta {
  flex-wrap: wrap;
  row-gap: 4px;
}

/* Tablet: master list becomes a card grid above the detail pane. */
@media (max-width: 1100px) {
  .dash-md {
    flex-direction: column;
  }
  .dash-positions {
    position: static;
    width: auto;
    max-height: none;
  }
  .dash-positions .pos-grp {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: 4px;
  }
  .dash-positions .pos-grp .pos-group {
    grid-column: 1 / -1;
  }
}

/* Phone: tighter padding, wrapping stage strip, lean candidate rows
   (rank/name/score/role — the comparison essentials). */
@media (max-width: 760px) {
  .pad {
    padding: 16px 14px;
  }
  /* Wrapped connectors dangle at line starts — drop them and let the
     cards tile 2-up instead. */
  .stages {
    flex-wrap: wrap;
    gap: 6px;
  }
  .stg-sep {
    display: none;
  }
  .stg {
    flex: 1 1 45%;
  }
  .crow {
    grid-template-columns: 22px minmax(0, 1.6fr) 96px minmax(0, 1fr);
  }
  /* Overview cards stack; the conversion card gives up its fixed width. */
  .ov-grid {
    flex-direction: column;
  }
  .ov-card.ov-conv {
    width: auto;
  }
  .ov-controls {
    flex-wrap: wrap;
  }
  .crow > :nth-child(n + 5) {
    display: none;
  }
}

/* ===== avatar photos (mirrored LinkedIn profile images) ===== */
/* Fills any avatar circle (.av / .d-av / .cc-av) in place of the initial. */
.av-img {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
  display: block;
}

/* --- Project (folder) picker in the sidebar --- */
.proj-picker {
  position: relative;
  margin-bottom: 4px;
}
/* The active project's sessions/shortlist. Flush-left with the picker (no
   indent, no connector rail) — the rows carry their own hover pills, and the
   picker directly above already frames them as the project's contents. */
.proj-children {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: 2px;
}
.proj-sec-items {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
/* Session rows indent one step behind a thin rail so they read as the runs
   under "+ new sourcing"; fixed rows around them stay flush left. */
.sess-rail {
  margin-left: 7px;
  padding-left: 8px;
  border-left: 1px solid var(--border);
}
/* "+ New sourcing" matches the session row box exactly (same vertical padding,
   13px) so the runs list reads as one rhythm. */
.proj-children .newtask {
  margin: 0;
  width: 100%;
  padding: 5px 10px 5px 11px;
  font-size: 13px;
}
.proj-select {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 6px 10px;
  border: 1px solid var(--border-2);
  background: var(--elev);
  border-radius: 8px;
  color: var(--text);
  cursor: pointer;
  font-size: 13px;
  font-family: inherit;
  text-align: left;
}
.proj-select:hover {
  background: var(--hover);
}
.proj-select .proj-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
}
.proj-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  background: var(--elev);
  border: 1px solid var(--border-2);
  border-radius: 13px;
  box-shadow: var(--shadow-lg);
  padding: 6px;
  z-index: 200;
  animation: popUp 0.14s ease;
}
/* Row styles are shared with .proj-optlist — the ProjectOptionList component
   renders the same rows inside other popovers (talent-pool filter editor). */
.proj-menu .mi,
.proj-optlist .mi {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  background: transparent;
  border-radius: 9px;
  color: var(--text);
  cursor: pointer;
  font-size: 13px;
  font-family: inherit;
  text-align: left;
}
.proj-menu .mi:hover,
.proj-optlist .mi:hover {
  background: var(--hover);
}
.proj-menu .mi.on,
.proj-optlist .mi.on {
  background: var(--hover);
  font-weight: 600;
}
.proj-menu .mi .proj-count,
.proj-optlist .mi .proj-count {
  margin-left: auto;
  color: var(--muted);
  font-size: 12px;
}
.proj-menu .mi-new {
  border-top: 1px solid var(--border);
  margin-top: 4px;
  color: var(--text2);
}
.proj-menu .mi .proj-opt-name,
.proj-optlist .mi .proj-opt-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.proj-menu .mi .proj-opt-name ~ .proj-count,
.proj-optlist .mi .proj-opt-name ~ .proj-count {
  margin-left: 0;
}
.proj-menu .mi.on .ico[data-ico="check"],
.proj-optlist .mi.on .ico[data-ico="check"] {
  color: var(--accent-mark);
}
.proj-optlist-empty {
  padding: 12px 10px;
  color: var(--text2);
  font-size: 12.5px;
}
.proj-search {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 9px;
  margin-bottom: 4px;
  border-bottom: 1px solid var(--border);
  color: var(--muted);
}
.proj-search-input {
  flex: 1;
  border: 0;
  background: transparent;
  color: var(--text);
  font-size: 13px;
  font-family: inherit;
  outline: none;
}
.proj-list {
  max-height: 260px;
  overflow-y: auto;
}
.proj-menu .proj-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

/* --- Projects index: card grid --- */
.proj-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 12px;
  margin-top: 16px;
}
.proj-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 16px;
  border: 1px solid var(--border);
  border-radius: 13px;
  background: var(--elev);
  color: var(--text);
  cursor: pointer;
  text-align: left;
  font-family: inherit;
}
.proj-card:hover {
  background: var(--hover);
  border-color: var(--border-2);
}
.proj-card-top {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 15px;
  font-weight: 600;
}
.proj-card-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.proj-card-meta {
  display: flex;
  gap: 7px;
  color: var(--muted);
  font-size: 12px;
}

/* --- Project home / index: header (title + optional action) --- */
.proj-head {
  display: flex;
  align-items: center;
  /* h1 removed — the "New project" button sits on the right on its own. */
  justify-content: flex-end;
  gap: 8px;
}

/* New-project modal: name field + actions. */
.np-input {
  width: 100%;
  box-sizing: border-box;
  padding: 11px 13px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  color: var(--text);
  font-size: 14px;
}
.np-input:focus {
  outline: none;
  border-color: var(--text);
}
.np-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 16px;
}

/* Shared list toolbar (Projects / Talent Pool): search on the left, primary
   action on the right — one line, same style across list pages. */
.list-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
}
.list-search {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  max-width: 420px;
  /* Same compact height as the app's action buttons — the 38px toolbar row
     read visibly taller than everything around it. */
  height: 32px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  color: var(--muted);
}
.list-search-input {
  flex: 1;
  min-width: 0;
  border: none;
  background: none;
  outline: none;
  color: var(--text);
  font-size: 14px;
}
.list-search-input::placeholder {
  color: var(--muted);
}
/* Import button stays pinned right; search + filter cluster on the left. */
.talent-import-btn {
  margin-left: auto;
}
/* The Actions menu stays pinned right; search + filter cluster left. */
.talent-actions {
  margin-left: auto;
}

/* --- Talent Pool Actions menu ------------------------------------------
   An "Actions" button opens Import / Export; Export hovers open into a
   CSV / Excel submenu. Achromatic popover, same shell as the filter menu. */
.actions-menu {
  position: relative;
}
.actions-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.actions-btn .ico {
  opacity: 0.75;
}
/* Right-aligned popover — the button sits at the toolbar's right edge. */
.actions-pop {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 200;
  min-width: 190px;
  background: var(--elev);
  border: 1px solid var(--border-2);
  border-radius: 12px;
  box-shadow: var(--shadow-lg);
  padding: 6px;
  animation: popUp 0.14s ease;
}
.actions-item {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--text);
  font-size: 13px;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  white-space: nowrap;
}
.actions-item:hover:not(:disabled) {
  background: var(--hover);
}
.actions-item:disabled {
  color: var(--muted);
  cursor: default;
}
.actions-item .ico {
  color: var(--text2);
}
/* Hairline between the Import and Export groups. */
.actions-sep {
  height: 1px;
  margin: 6px 4px;
  background: var(--border);
}
/* Small caps-y section header for the export formats. */
.actions-group-label {
  padding: 2px 10px 4px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.03em;
  color: var(--text2);
}

/* --- Talent Pool filter bar (Juicebox-style) --------------------------------
   A "Filter" button opens a field menu; each field opens a value editor;
   applied filters render as removable chips. All client-side over the
   fetched pool. */
.cfilter {
  position: relative;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}
/* Match the search box height (32px) so the toolbar row lines up. */
.cfilter-btn {
  height: 32px;
}
/* Active filter chip — a quiet achromatic tint (the former lime edge bar
   read as stray color); the tint alone marks the applied state. */
.cfilter-chip {
  display: inline-flex;
  align-items: center;
  height: 32px;
  border: 1px solid var(--border-2);
  border-radius: 8px;
  background: var(--active);
  overflow: hidden;
}
.cfilter-chip-label {
  height: 100%;
  padding: 0 8px 0 10px;
  border: 0;
  background: none;
  color: var(--text);
  font-size: 12px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
  white-space: nowrap;
}
.cfilter-chip-x {
  height: 100%;
  padding: 0 7px 0 1px;
  border: 0;
  background: none;
  color: var(--text2);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
}
.cfilter-chip-x:hover {
  color: var(--text);
}
/* Field menu + value editor share the elevated popover shell. */
.cfilter-menu,
.cfilter-editor {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 200;
  min-width: 200px;
  background: var(--elev);
  border: 1px solid var(--border-2);
  border-radius: 12px;
  box-shadow: var(--shadow-lg);
  padding: 6px;
  animation: popUp 0.14s ease;
}
.cfilter-menu-item {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--text);
  font-size: 13px;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}
.cfilter-menu-item:hover {
  background: var(--hover);
}
.cfilter-menu-item .ico {
  color: var(--text2);
}
.cfilter-editor {
  width: 260px;
  padding: 10px;
}
.cfilter-editor-head {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.03em;
  color: var(--text2);
  padding: 2px 2px 8px;
}
.cfilter-input {
  width: 100%;
  height: 34px;
  padding: 0 10px;
  border: 1px solid var(--border-2);
  border-radius: 8px;
  background: var(--bg);
  color: var(--text);
  font-size: 13px;
  outline: none;
}
.cfilter-input:focus {
  border-color: var(--text2);
}
.cfilter-opts {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 240px;
  overflow-y: auto;
  margin-top: 6px;
}
.cfilter-opt {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--text);
  font-size: 13px;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}
.cfilter-opt:hover {
  background: var(--hover);
}
.cfilter-opt.on {
  background: var(--active);
}
.cfilter-opt-name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cfilter-opt .ico {
  color: var(--accent-mark);
}
.cfilter-empty {
  padding: 12px 10px;
  color: var(--text2);
  font-size: 12.5px;
}
/* Skill tags inside the editor. */
.cfilter-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}
.cfilter-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 4px 3px 9px;
  border-radius: 7px;
  background: var(--active);
  border: 1px solid var(--border-2);
  font-size: 12px;
  color: var(--text);
}
.cfilter-tag-x {
  display: inline-flex;
  align-items: center;
  border: 0;
  background: none;
  color: var(--text2);
  cursor: pointer;
  padding: 0;
}
.cfilter-tag-x:hover {
  color: var(--text);
}
.cfilter-apply {
  width: 100%;
  justify-content: center;
  margin-top: 10px;
}

/* --- Projects index: table CRUD --- */
/* Projects reads as a compact list, not a full-bleed workspace. */
.pad-inner.proj-page {
  max-width: 860px;
}
.proj-search-bar {
  max-width: 360px;
  margin: 12px 0 18px;
  padding: 8px 11px;
  border: 1px solid var(--border-2);
  border-radius: 10px;
  background: var(--elev);
}
/* Base list-table look (.admin-table). The admin-console extraction moved
   the original block into apps/admin, but the Projects list (and ui/Table)
   still render with this class — the base styles must live here too. */
.admin-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.admin-table th {
  text-align: left;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
}
.admin-table td {
  padding: 12px 14px;
  color: var(--text);
  border-top: 1px solid var(--border);
  vertical-align: middle;
}
.admin-table td .sub {
  margin-top: 2px;
}
.admin-table tr:first-child td {
  border-top: 0;
}
.admin-table .sub {
  color: var(--text2);
  font-size: 12px;
}
.admin-table td.right,
.admin-table th.right {
  text-align: right;
}
.proj-table .proj-row {
  cursor: pointer;
}
.proj-table .proj-row:hover td {
  background: var(--hover);
}
/* The ⋯ button reuses .sess-more (sidebar), which is absolute + hover-shown via
   .sess:hover. In the table the row is .proj-row, so reset to a static cell
   button and reveal it on row hover (or while its menu is open). */
.proj-table .sess-more {
  position: static;
  transform: none;
}
.proj-table .proj-row:hover .sess-more,
.proj-table .sess-more.open,
.proj-table .sess-more:focus-visible {
  opacity: 1;
}
/* Nothing in the table wraps: headers/stats/dates stay one line, and a long
   project name truncates instead of squeezing the other columns. */
.proj-table th,
.proj-table td {
  white-space: nowrap;
}
.proj-table td:first-child {
  width: 30%;
  max-width: 0;
}
.proj-cell-name {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
}
.proj-cell-name .ico {
  flex: none;
}
.proj-cell-label {
  overflow: hidden;
  text-overflow: ellipsis;
}
.proj-stat {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--text2);
}
/* Fixed-width count box: the icon's x-position stays identical across rows
   whether the count is 1 or 2 digits (right-aligned digits, tabular figures). */
.proj-stat-n {
  min-width: 2ch;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.proj-date {
  color: var(--muted);
}
/* Inline rename matches the .proj-cell-name box exactly (same font size/weight/
   line-height, no border or vertical padding) so the table row height never
   changes between display and edit. Focus ring is inset, not additive. */
.proj-rename-cell {
  /* A real input box with comfortable padding — natural over text glued to the
     edge; the row may grow slightly while editing, which is fine. */
  width: 100%;
  max-width: 320px;
  box-sizing: border-box;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.2;
  font-family: inherit;
  color: var(--text);
  background: var(--elev);
  border: 1px solid var(--border-2);
  border-radius: 7px;
  padding: 6px 10px;
  margin: 0;
  outline: none;
}
.proj-rename-cell:focus {
  border-color: var(--text2);
}

/* --- Project home: session list --- */
.proj-sessions {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.proj-sess {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 13px;
  border: 1px solid var(--border);
  border-radius: 11px;
  color: var(--text);
  text-decoration: none;
  font-size: 14px;
}
.proj-sess:hover {
  background: var(--hover);
}
.proj-sess .label {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.proj-sess .proj-sess-n {
  color: var(--muted);
  font-size: 12px;
}

/* ── Integrations page ─────────────────────────────────────────────────── */
.intg-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 14px 0 2px;
  padding: 10px 12px;
  border-radius: 8px;
  border: 1px solid var(--border-2);
  font-size: 12.5px;
  color: var(--text);
  background: var(--panel);
}
.intg-banner.ok {
  border-color: var(--accent-mark);
}
.intg-banner.err {
  border-color: var(--border-2);
  color: var(--text2);
}
.intg-banner-x {
  background: none;
  border: none;
  color: var(--muted);
  cursor: pointer;
  display: inline-flex;
  padding: 2px;
}
.intg-section {
  margin-top: 28px;
}
.intg-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}
.intg-title {
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text);
  margin-bottom: 2px;
}
.intg-desc {
  font-size: 12.5px;
  color: var(--text2);
  margin-top: 3px;
}
.intg-tabs {
  display: inline-flex;
  gap: 2px;
  margin: 14px 0 10px;
  padding: 3px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 9px;
}
.intg-tab {
  border: none;
  background: none;
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text2);
  padding: 5px 12px;
  border-radius: 6px;
  cursor: pointer;
}
.intg-tab.active {
  background: var(--panel-2);
  color: var(--text);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}
.intg-empty {
  padding: 28px 16px;
  text-align: center;
  color: var(--muted);
  font-size: 12.5px;
  border: 1px dashed var(--border);
  border-radius: 10px;
}
.intg-tablewrap {
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
}
.intg-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12.5px;
}
.intg-table th {
  text-align: left;
  font-weight: 600;
  color: var(--muted);
  padding: 9px 12px;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
  white-space: nowrap;
}
.intg-table td {
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
  color: var(--text);
  vertical-align: middle;
}
.intg-table tr:last-child td {
  border-bottom: none;
}
.intg-provider {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 600;
}
.email-brand-mark {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
}
.email-brand-mark svg {
  display: block;
  width: 100%;
  height: 100%;
}
.intg-email {
  color: var(--text2);
}
.intg-owner {
  color: var(--muted);
}
.intg-pill {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  border: 1px solid var(--border-2);
  color: var(--text2);
}
.intg-pill.connected {
  border-color: var(--accent-mark);
  color: var(--text);
}
.intg-pill.error,
.intg-pill.revoked {
  color: var(--muted);
}
.intg-select {
  font-family: inherit;
  font-size: 12px;
  padding: 4px 8px;
  border-radius: 6px;
  border: 1px solid var(--border-2);
  background: var(--panel-2);
  color: var(--text);
  cursor: pointer;
}
.intg-vislabel {
  font-size: 12px;
  color: var(--text2);
}
.intg-actions {
  text-align: right;
}
.intg-x {
  background: none;
  border: none;
  color: var(--muted);
  cursor: pointer;
  padding: 4px;
  display: inline-flex;
  border-radius: 6px;
}
.intg-x:hover {
  color: var(--text);
  background: var(--hover);
}
.intg-add {
  position: relative;
  margin-top: 12px;
  display: inline-block;
}
.intg-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  min-width: 190px;
  background: var(--panel-2);
  border: 1px solid var(--border-2);
  border-radius: 10px;
  padding: 4px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
  z-index: 20;
}
.intg-mi {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  border: none;
  background: none;
  font-family: inherit;
  font-size: 12.5px;
  color: var(--text);
  padding: 8px 10px;
  border-radius: 7px;
  cursor: pointer;
  text-align: left;
}
.intg-mi:hover:not([disabled]) {
  background: var(--hover);
}
.intg-mi[disabled] {
  color: var(--muted);
  cursor: default;
}
.intg-mi[disabled] .email-brand-mark {
  opacity: 0.48;
  filter: saturate(0.65);
}
.intg-mi-note {
  margin-left: auto;
  font-size: 10.5px;
  color: var(--muted);
}
.intg-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-top: 12px;
  padding: 16px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--panel);
}
.intg-card-soon {
  opacity: 0.75;
}
.intg-card-body {
  display: flex;
  align-items: center;
  gap: 12px;
}
.intg-card-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
}
.intg-soon-badge {
  font-size: 11px;
  font-weight: 600;
  color: var(--text2);
  border: 1px solid var(--border-2);
  border-radius: 999px;
  padding: 3px 10px;
  white-space: nowrap;
}

/* Quick Find — lives as a magnifier icon button in the sidebar's top row
   (.side-top-actions), beside the collapse toggle; ⌘K stays in its title. */
.cmdk-foot kbd {
  margin-left: auto;
  font-family: inherit;
  font-size: 11px;
  color: var(--muted);
  border: 1px solid var(--border-2);
  border-radius: 5px;
  padding: 1px 5px;
  background: var(--panel);
}
.cmdk {
  position: relative;
  width: min(640px, calc(100vw - 32px));
  max-width: 640px;
  height: min(520px, calc(100dvh - 32px));
  max-height: calc(100dvh - 32px);
  background: var(--bg);
  border: 1px solid var(--border-2);
  border-radius: 8px;
  box-shadow: var(--shadow-lg);
  color: inherit;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  margin: 0;
  padding: 0;
  animation: popUp 0.15s ease;
}
.modal-scrim:has(.cmdk) {
  padding: 16px;
}
.cmdk-search {
  flex: none;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  color: var(--text2);
}
.cmdk-input {
  flex: 1;
  border: 0;
  outline: none;
  background: transparent;
  color: var(--text);
  font-size: 14px;
}
.cmdk-list {
  overflow-y: auto;
  padding: 6px;
  flex: 1;
  min-height: 0;
}
.cmdk-heading {
  font-size: 11px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0;
  padding: 8px 10px 4px;
}
.cmdk-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  border: 0;
  background: transparent;
  color: var(--text2);
  font-size: 13.5px;
  padding: 8px 10px;
  border-radius: 8px;
  cursor: pointer;
  text-align: left;
}
.cmdk-item.active,
.cmdk-item:hover {
  background: var(--hover);
  color: var(--text);
}
.cmdk-title {
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cmdk-sub {
  color: var(--muted);
  font-size: 12px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  flex: 1;
}
.cmdk-item .cmdk-pill {
  margin-left: auto;
  font-size: 11px;
  color: var(--muted);
  border: 1px solid var(--border-2);
  border-radius: 999px;
  padding: 1px 8px;
  white-space: nowrap;
}
.cmdk-sub + .cmdk-pill {
  margin-left: 0;
}
.cmdk-empty {
  min-height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 28px 12px;
  text-align: center;
  color: var(--muted);
  font-size: 13px;
}
.cmdk-foot {
  flex: none;
  display: flex;
  gap: 14px;
  padding: 8px 14px;
  border-top: 1px solid var(--border);
  color: var(--muted);
  font-size: 12px;
}
.cmdk-foot kbd {
  margin-left: 0;
  margin-right: 4px;
}

/* ===== selection bar (floating) ===== */
/* Checking rows raises the action instead of parking a disabled button on the
   page. Same bar on /outreach and in the session rosters. */
.selbar {
  position: fixed;
  left: 50%;
  bottom: 18px;
  transform: translateX(-50%);
  z-index: 50;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 10px 8px 18px;
  border: 1px solid var(--border-2);
  border-radius: 999px;
  background: var(--bg);
  box-shadow: var(--shadow-lg);
  animation: selbar-in 140ms ease-out;
}
/* Fixed elements otherwise center against the browser viewport. The sidebar
   is part of that viewport but not of the recruiter's working canvas. */
.app:not(.collapsed) .selbar {
  left: calc(50% + var(--sidebar-w, 252px) / 2);
}
.selbar .n {
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.selbar .btn {
  border-radius: 999px;
}
@keyframes selbar-in {
  from {
    opacity: 0;
    transform: translate(-50%, 8px);
  }
  to {
    opacity: 1;
    transform: translate(-50%, 0);
  }
}
@media (prefers-reduced-motion: reduce) {
  .selbar {
    animation: none;
  }
}

/* ===== messages sent history ===== */
/* What actually went out, beneath the drafts in the aside's Messages tab.
   Deliberately quieter than the draft cards: this is a record, not an action
   surface — hairline rows instead of bordered cards, meta line in muted ink,
   body clamped to three lines. */
.omh-section {
  margin-top: 0;
}
/* The draft and the sent record are two sections of one tab, so they need air
   between them — but only between them, never above the first. */
.omh-section + .omh-section {
  margin-top: 22px;
}
/* One card shape for every box in this tab: the draft, the empty state, and
   the sent record. They are different contents of the same panel, and reading
   as three unrelated components was the complaint. Layout differences (the
   empty state centers itself) are declared by the specific class below. */
.omh-card {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 16px;
}
/* These name the two halves of the tab (the draft, the record), so they are
   section headings and not captions — at caption size and --muted they read as
   labels stuck to the card above them. */
.omh-head {
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
  margin-bottom: 10px;
}
/* With history present the compose button rides the header row — the record
   leads, the action stays reachable without floating over whitespace. */
.omh-head-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 8px;
}
.omh-head-row .omh-head {
  margin-bottom: 0;
}
/* Before the first send the whole tab is one card: what this space is for,
   how the person can be reached, and the compose CTA anchored inside it. */
.omh-empty-card {
  padding: 22px 16px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.omh-empty-title {
  margin: 0;
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
}
.omh-empty-hint {
  margin: 5px 0 0;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--muted);
}
.omh-empty-reach {
  margin: 3px 0 0;
  font-size: 12px;
  color: var(--muted);
}
.omh-empty-cta {
  margin-top: 14px;
}
.omh-list {
  display: flex;
  flex-direction: column;
}
.omh-row {
  padding: 9px 0;
  border-bottom: 1px solid var(--border);
}
.omh-row:last-child {
  border-bottom: none;
}
.omh-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--muted);
}
.omh-date {
  font-variant-numeric: tabular-nums;
}
.omh-channel {
  border: 1px solid var(--border-2);
  border-radius: 999px;
  padding: 1px 7px;
  font-size: 11px;
}
.omh-to {
  color: var(--text2);
  word-break: break-all;
}
.omh-flag {
  border: 1px solid var(--credit-low-border);
  background: var(--credit-low-bg);
  color: var(--credit-low);
  border-radius: 999px;
  padding: 1px 7px;
  font-size: 11px;
}
/* Taking back a mis-recorded touch: an ✕ at the end of the meta line, in the
   meta line's own tone, firming up only under the cursor. A correction should
   be findable without competing with the record it is attached to. */
.omh-retract {
  /* Sits with the meta chips it belongs to, directly above the message text.
     Pushed to the row's far edge (margin-left:auto) it read as an unrelated
     control floating in the panel's corner, unattached to the record it
     removes. */
  display: inline-flex;
  align-items: center;
  color: var(--muted);
  opacity: 0.6;
  transition:
    opacity 0.15s ease,
    color 0.15s ease;
}
.omh-row:hover .omh-retract,
.omh-retract:focus-visible {
  opacity: 1;
}
.omh-retract:hover:not(:disabled) {
  color: var(--text);
}
.omh-retract:disabled {
  opacity: 0.4;
}
.omh-subject {
  margin-top: 5px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
}
.omh-body {
  margin: 4px 0 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text2);
  /* The FULL sent text — this tab is the record, never a clipped preview. */
  white-space: pre-wrap;
  word-break: break-word;
}

/* ===== outreach preview (the pipeline's own first draft) ===== */
/* Stands where the empty card would: a real message, so it reads as one —
   bordered like a card but left-aligned prose, not a centered pitch. */
.omh-preview-head {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 8px;
}
.omh-preview-tag {
  font-size: 11px;
  font-weight: 700;
  color: var(--accent-fg);
  background: var(--accent);
  border-radius: 999px;
  padding: 1px 7px;
}
.omh-preview-channel {
  font-size: 11px;
  color: var(--muted);
  border: 1px solid var(--border-2);
  border-radius: 999px;
  padding: 1px 7px;
}
.omh-preview-body {
  margin: 0;
  font-size: 13px;
  line-height: 1.6;
  color: var(--text);
  white-space: pre-wrap;
  word-break: break-word;
}
.omh-preview-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 14px;
}
.omh-preview-spinner {
  display: inline-block;
  width: 10px;
  height: 10px;
  margin-right: 6px;
  vertical-align: -1px;
  border: 1.5px solid var(--border-2);
  border-top-color: var(--muted);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}

/* The settings fieldset is the rail's only scrolling region. The generate
   action below it is a separate fixed footer, so scrolled fields can never
   show through the action surface. */
.ocmp-railset {
  border: 0;
  padding: 18px;
  margin: 0;
  min-inline-size: auto;
  min-height: 0;
  flex: 1;
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.ocmp-railset:disabled {
  opacity: 0.6;
}
/* Full-width, opaque rail footer. Its own border spans edge to edge because
   it is not nested inside the padded scroll region. */
.ocmp-generate-field {
  position: relative;
  z-index: 1;
  flex: none;
  width: 100%;
  border-top: 1px solid var(--border);
  background: var(--panel);
  padding: 18px;
  gap: 9px;
}
.ocmp-generate-field > .action-tooltip-trigger {
  display: flex;
  width: 100%;
}

/* ===== legal documents (/terms, /privacy, /refund) ===== */
.legal-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}
.legal-doc {
  max-width: 680px;
  margin: 0 auto;
  padding: 48px 32px 96px;
  color: var(--text2);
  font-size: 14px;
  line-height: 1.75;
}
.legal-doc h1 {
  color: var(--text);
  font-size: 24px;
  font-weight: 700;
  margin: 0 0 6px;
}
.legal-doc h2 {
  color: var(--text);
  font-size: 15px;
  font-weight: 600;
  margin: 28px 0 6px;
}
.legal-doc p {
  margin: 0 0 12px;
}
.legal-effective {
  color: var(--muted);
  font-size: 12.5px;
  margin-bottom: 24px;
}
.legal-intro {
  margin-bottom: 8px;
}
/* Refund terms table. Kept as a real table (not flattened prose) so the
   reviewed wording per purchase type survives verbatim; scrolls inside its
   own box on narrow screens rather than widening the page. */
.legal-tablewrap {
  overflow-x: auto;
  margin: 10px 0 14px;
}
.legal-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  line-height: 1.6;
}
.legal-table th,
.legal-table td {
  border: 1px solid var(--border);
  padding: 8px 10px;
  text-align: left;
  vertical-align: top;
}
.legal-table th {
  color: var(--text);
  font-weight: 600;
  background: var(--panel);
  white-space: nowrap;
}
/* The purchase-type column is a short label ("크레딧 팩"); letting it wrap
   mid-phrase reads as two rows. The condition/outcome cells still wrap. */
.legal-table td:first-child {
  white-space: nowrap;
}
/* The reset strips list markers globally, so restore them here — these are
   enumerated legal restrictions and have to read as a list, not as lines. */
.legal-list {
  list-style: disc;
  margin: 0 0 12px;
  padding-left: 20px;
}
.legal-list-num {
  list-style: decimal;
}
.legal-list li {
  margin-bottom: 4px;
}
/* Numbered sub-clause heading inside a section (4.1, 2.1 …). */
.legal-subtitle {
  color: var(--text);
  font-size: 13.5px;
  font-weight: 600;
  margin: 18px 0 6px;
}
/* The Google Limited Use statement must appear verbatim for OAuth review —
   set apart so it reads as quoted policy text rather than our prose. */
.legal-quote {
  margin: 0 0 12px;
  padding: 10px 14px;
  border-left: 2px solid var(--border);
  background: var(--panel);
  color: var(--text);
}
/* Cross-reference between legal documents (약관 → 환불정책). Underlined
   rather than key-colored: these pages carry no accent. */
.legal-link {
  color: var(--text);
  text-decoration: underline;
}
