/* Brand overrides on top of Pico classless.
 *
 * Colours taken from tvoyapolka.ru: yellow #FCD400 on navy #003865.
 * Typography is a system stack rather than the site's Roboto — this is an internal work
 * tool opened many times a day, and a webfont would mean either a CDN request (forbidden
 * at runtime) or 4 vendored woff2 files for no legibility gain.
 *
 * Design intent: dense and boring. Tables over cards, no animation, tight vertical
 * rhythm so a 40-row candidate list fits on one screen.
 */

:root {
  --brand-yellow: #fcd400;
  --brand-navy: #003865;
  --brand-navy-dim: #0a4b80;

  --pico-font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
    Arial, sans-serif;
  --pico-font-size: 93.75%;         /* 15px base; the default 16px wastes row height */
  --pico-line-height: 1.45;
  --pico-form-element-spacing-vertical: 0.4rem;
  --pico-form-element-spacing-horizontal: 0.6rem;
  --pico-spacing: 0.9rem;
  --pico-border-radius: 3px;
  --pico-primary: var(--brand-navy);
  --pico-primary-background: var(--brand-navy);
  --pico-primary-hover-background: var(--brand-navy-dim);
  --pico-primary-focus: rgba(0, 56, 101, 0.25);
  --pico-primary-inverse: #fff;

  /* Semantic tokens. Every themed colour in this file goes through one of these, so a
   * component rule never needs its own dark variant — see the palette below. */
  --accent: var(--brand-navy);
  --color-danger: #8a1c1c;
  --color-success: #14622f;
  --badge-ink: var(--brand-navy);
}

/* --- Dark palette ----------------------------------------------------------
 *
 * Written once, applied by two selectors:
 *
 *   1. the OS preference, unless the user has explicitly chosen light;
 *   2. an explicit choice of dark, whatever the OS says.
 *
 * The second was missing until the theme switch was added, so choosing dark on a light
 * machine changed nothing. It could not be fixed in one place either, because the dark
 * colours were spread across seven media queries next to the components that used them.
 * They now set tokens instead, and there is exactly one place to add a colour to.
 */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --pico-primary: var(--brand-yellow);
    --pico-primary-background: var(--brand-navy-dim);
    --pico-primary-hover-background: var(--brand-navy);
    --pico-primary-inverse: #fff;
    --accent: var(--brand-yellow);
    --color-danger: #ff9d9d;
    --color-success: #7fd6a0;
    --badge-ink: #1a1a1a;
  }
}

:root[data-theme="dark"] {
  --pico-primary: var(--brand-yellow);
  --pico-primary-background: var(--brand-navy-dim);
  --pico-primary-hover-background: var(--brand-navy);
  --pico-primary-inverse: #fff;
  --accent: var(--brand-yellow);
  --color-danger: #ff9d9d;
  --color-success: #7fd6a0;
  --badge-ink: #1a1a1a;
}

/* --- Layout --------------------------------------------------------------- */

body > header,
body > main,
body > footer {
  max-width: 1400px;              /* the candidate list is wide; don't cage it at 1024 */
  padding-block: var(--pico-spacing);
}

body > header {
  border-bottom: 3px solid var(--brand-yellow);
  margin-bottom: var(--pico-spacing);
}

.site-nav {
  display: flex;
  align-items: baseline;
  gap: 1.25rem;
  flex-wrap: wrap;
}

.site-nav .brand {
  font-weight: 700;
  color: var(--accent);
  text-decoration: none;
  white-space: nowrap;
}

.site-nav a { text-decoration: none; }
.site-nav .spacer { margin-left: auto; }

/* --- Tables --------------------------------------------------------------- */

table { font-size: 0.95em; }

th, td {
  padding: 0.35rem 0.5rem;
  vertical-align: top;
}

thead th {
  position: sticky;
  top: 0;
  background: var(--pico-background-color);
  border-bottom: 2px solid var(--brand-navy);
  white-space: nowrap;
}

tbody tr:hover { background: var(--pico-code-background-color); }

.numeric { text-align: right; font-variant-numeric: tabular-nums; }
.nowrap  { white-space: nowrap; }
.muted   { color: var(--pico-muted-color); }

/* --- Stage badges ---------------------------------------------------------
 * Terminal stages are muted, active stages carry weight, rejections read as rejections.
 * Colour is never the only signal: the label is always spelled out next to it. */

.stage {
  display: inline-block;
  padding: 0.1rem 0.45rem;
  border-radius: 3px;
  font-size: 0.85em;
  white-space: nowrap;
  border: 1px solid currentColor;
}
.stage--active   { color: var(--accent);        background: rgba(252, 212, 0, 0.22); }
.stage--rejected { color: var(--color-danger);  background: rgba(138, 28, 28, 0.08); }
.stage--hired    { color: var(--color-success); background: rgba(20, 98, 47, 0.10); }
.stage--neutral  { color: var(--pico-muted-color); }

/* --- Forms ---------------------------------------------------------------- */

/* Read-only fields are rendered, not hidden, when the permission matrix grants read but
 * not write — the partner needs to see the HR comment he cannot edit. */
.readonly-value {
  padding: 0.4rem 0;
  border-bottom: 1px dotted var(--pico-muted-border-color);
  min-height: 1.6em;
}

fieldset > legend {
  font-weight: 600;
  color: var(--brand-navy);
}

.field-error { color: #8a1c1c; font-size: 0.9em; }

/* --- Timeline (pipeline history from stage_transitions) ------------------- */

.timeline { list-style: none; padding-left: 0; border-left: 2px solid var(--brand-yellow); }
.timeline li { padding: 0.3rem 0 0.3rem 0.9rem; position: relative; }
.timeline li::before {
  content: "";
  position: absolute;
  left: -5px;
  top: 0.75rem;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--brand-navy);
}

/* --- Utility -------------------------------------------------------------- */

.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1rem; }
.stack > * + * { margin-top: 0.6rem; }
.hidden { display: none !important; }

/* HTMX swaps a fragment in place; a brief dim tells the user the click registered
 * without a spinner or a transition. */
.htmx-request { opacity: 0.6; }

/* Honeypot on the public form: hidden from people, present for bots. Deliberately not
 * display:none, which some bots skip. */
.hp-field {
  position: absolute !important;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* --- Flash messages ------------------------------------------------------- */

.flash {
  padding: 0.5rem 0.75rem;
  border-radius: var(--pico-border-radius);
  border-left: 4px solid;
}
.flash--ok    { border-color: #14622f; background: rgba(20, 98, 47, 0.08); }
.flash--error { border-color: #8a1c1c; background: rgba(138, 28, 28, 0.08); }

/* --- Login ---------------------------------------------------------------- */

.login-form { max-width: 22rem; }

/* --- Admin ---------------------------------------------------------------- */

/* One-time magic link. Wide and monospace because it exists to be selected and
 * copied, and a truncated token is a support call. */
.magic-link input {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.85em;
  width: 100%;
}

/* --- Store assignment picker (admin/user_edit) ---------------------------
 *
 * A grid rather than a table, because the six multi-store cities collapse into
 * <details> blocks and a <details> cannot live inside a <tbody>. The shared column
 * template keeps plain rows and nested rows aligned on the same two checkbox columns.
 *
 * Native <details> means no JavaScript and full keyboard operation. Its contents stay
 * in the DOM when closed, so checkboxes in a collapsed city are still submitted. */

.store-picker {
  border: 1px solid var(--pico-muted-border-color);
  border-radius: var(--pico-border-radius);
  overflow: hidden;
}

.sp-head,
.sp-row {
  display: grid;
  grid-template-columns: 1fr 7rem 7rem;
  align-items: center;
  gap: 0.5rem;
  padding: 0.28rem 0.6rem;
}

.sp-head {
  font-weight: 600;
  border-bottom: 2px solid var(--brand-navy);
  background: var(--pico-code-background-color);
}

.sp-col { text-align: center; }
.sp-col input[type="checkbox"] { margin: 0; }

.sp-row + .sp-row,
.sp-group + .sp-row,
.sp-row + .sp-group { border-top: 1px solid var(--pico-muted-border-color); }

.sp-row:hover { background: var(--pico-code-background-color); }

.sp-name { min-width: 0; }

/* Nested rows sit under their city's summary; the indent is what marks them as
 * belonging to it, so the boundary of a group is visible rather than implied. */
.sp-row--nested .sp-name { padding-left: 1.4rem; }

.sp-group { border-top: 1px solid var(--pico-muted-border-color); }
.sp-group > summary {
  padding: 0.35rem 0.6rem;
  cursor: pointer;
  font-weight: 600;
  background: var(--pico-code-background-color);
  list-style-position: inside;
}
.sp-group > summary:hover { background: var(--pico-muted-border-color); }
.sp-group[open] > summary { border-bottom: 1px solid var(--pico-muted-border-color); }

/* Count of stores already assigned inside a city. Shown on the summary so a collapsed
 * group can never hide the fact that something in it is ticked. */
.sp-badge {
  display: inline-block;
  margin-left: 0.4rem;
  padding: 0 0.4rem;
  border-radius: 3px;
  font-size: 0.8em;
  font-weight: 400;
  color: var(--badge-ink);
  background: var(--brand-yellow);
}

table input[type="text"] { margin-bottom: 0; }

/* --- Candidate list ------------------------------------------------------- */

.list-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.list-head h1 { margin-bottom: 0; }

/* Filters wrap onto one or two lines and stay put; this is a bar a recruiter uses
 * dozens of times a day, not a form to fill in. */
.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
  margin-block: 0.75rem;
}
/* Pico sets width:100% on inputs with a higher-specificity selector than `.filters > *`,
 * so each control is named explicitly. Without this every date field and the button
 * take a full row and the bar becomes six stacked lines. */
.filters > *,
.filters input,
.filters select,
.filters button {
  margin-bottom: 0;
  width: auto;
}
.filters input[type="search"] { min-width: 18rem; flex: 1 1 18rem; }
.filters input[type="date"] { width: 10rem; }
.filters select { max-width: 14rem; }
.filters .inline { display: flex; align-items: center; gap: 0.35rem; white-space: nowrap; }
.filters .inline input { margin: 0; }

.pager { display: flex; gap: 1rem; align-items: baseline; }

/* --- Candidate card ------------------------------------------------------- */

.card-head { display: flex; justify-content: space-between; align-items: flex-start; }

/* The action panel is what the card is opened for, so it gets its own column and does
 * not sit below several screens of анкета. */
.card-grid {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(20rem, 1fr);
  gap: 1.25rem;
  align-items: start;
}

@media (max-width: 900px) {
  .card-grid { grid-template-columns: 1fr; }
}

.card-side { position: sticky; top: 0.5rem; }

.card-grid article,
.card-grid details.section {
  border: 1px solid var(--pico-muted-border-color);
  border-radius: var(--pico-border-radius);
  padding: 0.6rem 0.8rem;
  margin-bottom: 0;
}

.card-grid h2 { font-size: 1.05rem; margin-bottom: 0.4rem; display: inline; }
details.section > summary { cursor: pointer; }

/* Key/value pairs, dense. Two columns on wide screens, stacked when narrow. */
.kv { display: grid; grid-template-columns: minmax(9rem, 14rem) 1fr; gap: 0.15rem 0.75rem; margin: 0; }
.kv dt { color: var(--pico-muted-color); font-size: 0.9em; }
.kv dd { margin: 0; }

@media (max-width: 560px) {
  .kv { grid-template-columns: 1fr; }
  .kv dd { margin-bottom: 0.4rem; }
}

.copy { padding: 0 0.4rem; font-size: 0.75em; margin-left: 0.4rem; }

/* --- Action panel --------------------------------------------------------- */

.actions { background: var(--pico-code-background-color); }
.actions form { margin-bottom: 0; }
.actions label { font-size: 0.9em; }
.actions button { margin-bottom: 0; }

details.action { border-top: 1px solid var(--pico-muted-border-color); padding-top: 0.4rem; }
details.action > summary { cursor: pointer; padding: 0.25rem 0; font-weight: 600; }
details.action--admin > summary { color: var(--pico-muted-color); font-weight: 400; }

.req { color: var(--color-danger); }

/* A forced stage must never read as an ordinary step of the process. */
.timeline--forced::before { background: var(--color-danger) !important; }

/* --- Manual entry --------------------------------------------------------- */

.anketa fieldset { border: 1px solid var(--pico-muted-border-color); padding: 0.6rem 0.8rem; }
.anketa label { font-size: 0.9em; }
.work-block { border-top: 1px dashed var(--pico-muted-border-color); padding-top: 0.5rem; }
.work-block:first-child { border-top: none; padding-top: 0; }

/* --- Public анкета -------------------------------------------------------- */

/* The candidate-facing page. Wider line length and larger touch targets than the
 * internal tool: this is filled in once, often on a phone or an in-store tablet, by
 * someone who has never seen it before. */

body.public > header,
body.public > main,
body.public > footer { max-width: 52rem; }

body.public > header { border-bottom: 3px solid var(--brand-yellow); }

.public-brand {
  font-weight: 700;
  font-size: 1.1rem;
  color: var(--accent);
  padding-block: 0.5rem;
}

body.public .anketa label { font-size: 1rem; }

body.public input,
body.public select,
body.public textarea { min-height: 2.4rem; }

body.public fieldset { margin-bottom: 1.25rem; }

/* Token URLs exist to be selected and copied whole; a truncated one is a dead link. */
.token-url {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.8em;
  width: 100%;
  margin-bottom: 0;
}

/* --- Anketa review -------------------------------------------------------- */

/* Fields on the left, the text they came from on the right. A reviewer resolving a
 * doubtful value should not have to reopen the PDF to see what the parser saw. */
.review-grid {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(18rem, 2fr);
  gap: 1.25rem;
  align-items: start;
}

@media (max-width: 1000px) {
  .review-grid { grid-template-columns: 1fr; }
}

.review-source {
  position: sticky;
  top: 0.5rem;
  max-height: 85vh;
  overflow: auto;
  border: 1px solid var(--pico-muted-border-color);
  border-radius: var(--pico-border-radius);
  padding: 0.5rem 0.75rem;
}

.review-source pre {
  white-space: pre-wrap;
  word-break: break-word;
  font-size: 0.8em;
  background: none;
  padding: 0;
}

/* Only the doubtful fields are marked. Flagging everything would be the same as
 * flagging nothing, and the argument for this screen is that a reviewer checks three
 * fields instead of thirty. */
label.flagged {
  border-left: 3px solid var(--brand-yellow);
  padding-left: 0.5rem;
}
label.flagged input,
label.flagged select { border-color: var(--brand-yellow); }

.flag-why {
  display: block;
  font-size: 0.8em;
  color: var(--pico-muted-color);
  font-weight: 400;
}

.review-actions { position: sticky; bottom: 0; padding-block: 0.5rem; }
.review-actions kbd { font-size: 0.8em; opacity: 0.75; }

.discard-form { margin-top: 1rem; }

.flash--warn { border-color: var(--brand-yellow); background: rgba(252, 212, 0, 0.12); }

/* --- Outreach ------------------------------------------------------------- */

/* Collapsed by default. The recruiter opens the card to move a candidate along; the
 * message text is there when wanted, not in the way when not. */
details.outreach-item {
  border-top: 1px solid var(--pico-muted-border-color);
  padding-top: 0.35rem;
}
details.outreach-item > summary { cursor: pointer; padding: 0.25rem 0; font-weight: 600; }

.outreach-subject { margin: 0.3rem 0; font-size: 0.9em; }

/* The finished text, exactly as it will be sent. Rendered server-side so the recruiter
 * reads the real message rather than a template full of placeholders. */
.outreach-body {
  white-space: pre-wrap;
  word-break: break-word;
  font-size: 0.85em;
  max-height: 14rem;
  overflow: auto;
  margin-bottom: 0.5rem;
}

.outreach-actions { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.outreach-actions [role="button"],
.outreach-actions button { margin-bottom: 0; padding: 0.25rem 0.6rem; font-size: 0.85em; }

.outreach-history { font-size: 0.85em; padding-left: 1rem; margin-bottom: 0.3rem; }
.outreach h3 { font-size: 0.95rem; margin: 0.6rem 0 0.3rem; }

/* --- Admin: message templates --------------------------------------------- */

.template-editor textarea { font-family: inherit; font-size: 0.9em; }
.placeholder-help { font-size: 0.85em; }
.placeholder-help code {
  cursor: pointer;
  user-select: all;
}

/* --- Dashboard queues ----------------------------------------------------- */

.queue {
  border: 1px solid var(--pico-muted-border-color);
  border-radius: var(--pico-border-radius);
  padding: 0.6rem 0.8rem;
  margin-bottom: 1rem;
}

.queue h2 { font-size: 1.05rem; margin-bottom: 0.4rem; }
.queue table { margin-bottom: 0; }

.queue .count {
  display: inline-block;
  min-width: 1.4em;
  padding: 0 0.35rem;
  border-radius: 3px;
  font-size: 0.8em;
  text-align: center;
  background: var(--pico-code-background-color);
}

/* Overdue is the only thing on this page that should pull the eye. If every queue were
 * coloured, none of them would be. It marks the row, not a separate block: an item
 * being late is a property of that item, not a different kind of work. */
.queue--overdue { border-left: 4px solid #8a1c1c; }
.count--urgent { background: rgba(138, 28, 28, 0.18) !important; }
tr.row--urgent > td:first-child { box-shadow: inset 3px 0 0 #8a1c1c; }
.queue--interns { border-left: 4px solid var(--brand-yellow); }
.queue--interns .count { background: rgba(252, 212, 0, 0.22); }

/* --- Intern check-in ------------------------------------------------------ */

.intern-check form { margin-bottom: 0.4rem; }
.intern-check label { font-size: 0.9em; }
.intern-check button { margin-bottom: 0; }
.intern-history { font-size: 0.85em; padding-left: 1rem; margin-bottom: 0; }

/* --- Reminder delivery log ------------------------------------------------ */

/* Silent non-delivery is the failure this system is least able to notice on its own,
 * so a failed row has to be visible at a glance rather than found by reading. */
tr.delivery--failed td { background: rgba(138, 28, 28, 0.10); }

/* --- Reports -------------------------------------------------------------- */

.report {
  border: 1px solid var(--pico-muted-border-color);
  border-radius: var(--pico-border-radius);
  padding: 0.6rem 0.8rem;
  margin-bottom: 1rem;
}

.report h2 { font-size: 1.05rem; margin-bottom: 0.4rem; }
.report h3 { font-size: 0.95rem; margin: 0.9rem 0 0.3rem; }
.report table { margin-bottom: 0; }

.report-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.export-links { font-size: 0.85em; white-space: nowrap; }

/* A row of figures. The median is the one that should be read first — at a handful of
 * internships per store the mean is dominated by a single early leaver, so it is shown
 * beside the median rather than instead of it, and smaller. */
.stat-row { display: flex; flex-wrap: wrap; gap: 1.5rem; align-items: flex-end; margin: 0.5rem 0; }
.stat-value { font-size: 1.4rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.stat-label { font-size: 0.8em; color: var(--pico-muted-color); }

.stat--lead .stat-value {
  font-size: 2.2rem;
  color: var(--accent);
}

/* --- Store and partner cards ------------------------------------------------
 *
 * Two-column on a desktop, one on a phone. A partner checking a store from the shop
 * floor is the case that matters, so the breakpoint is generous and nothing here
 * depends on hover.
 */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
  gap: 1rem;
  margin-bottom: 1rem;
}

.cards > article { margin-bottom: 0; }
.cards h2 { font-size: 1.05rem; margin-bottom: 0.5rem; }
.cards table { margin-bottom: 0; }

/* A list of names or shops, not a bulleted list of prose. */
ul.plain { list-style: none; padding-left: 0; margin-bottom: 0; }
ul.plain li { padding: 0.35rem 0; border-bottom: 1px solid var(--pico-muted-border-color); }
ul.plain li:last-child { border-bottom: none; }

/* A closed store or a deactivated user: still listed, visibly not current. Opacity
 * rather than colour, so it survives both themes and reads as "inactive" without
 * needing the legend. */
.row--muted td { opacity: 0.55; }

.urgent { color: var(--color-danger); }

.city-block { margin-bottom: 1rem; }
.city-block h2 { font-size: 1rem; margin-bottom: 0.4rem; }
.city-block table { margin-bottom: 0; }

/* The block a recruiter reads out on the phone. Term/definition rather than a table:
 * these are labelled facts about one thing, not rows to compare. */
.store-details { margin-bottom: 1rem; }
.store-details .report-head { margin-bottom: 0.4rem; }
.store-details h2 { font-size: 1.05rem; margin-bottom: 0; }

.detail-list { margin: 0; }
.detail-list dt {
  font-size: 0.8em;
  color: var(--pico-muted-color);
  margin-top: 0.6rem;
}
.detail-list dt:first-child { margin-top: 0; }
.detail-list dd { margin: 0 0 0 0; }

/* Two inputs side by side on a desktop, stacked on a phone. Name and role belong
 * together; splitting them across full-width rows makes the form look longer than it is. */
.field-row { display: flex; flex-wrap: wrap; gap: 0 1rem; }
.field-row > label { flex: 1 1 14rem; }

/* --- User guides ------------------------------------------------------------
 *
 * Prose, not a dashboard. Measure is capped: these are read start to finish, and a
 * 1400px line of Russian text is genuinely hard to follow back to the next line.
 */
.guide { max-width: 46rem; }
.guide h2 { font-size: 1.25rem; margin-top: 2rem; }
.guide h3 { font-size: 1.05rem; margin-top: 1.4rem; }
.guide h2:first-child, .guide h3:first-child { margin-top: 0; }
.guide li { margin-bottom: 0.3rem; }
.guide table { font-size: 0.9em; }
.guide code { white-space: nowrap; }
.guide pre code { white-space: pre; }

/* A pull-quote for the warnings — "do not share this link", "the key goes in
 * wp-config, not in the plugin file". These are the sentences that cost someone an
 * afternoon if skimmed past. */
.guide blockquote {
  border-left: 3px solid var(--brand-yellow);
  padding-left: 0.9rem;
  margin-left: 0;
  color: inherit;
}

/* justify-content is explicit: Pico styles bare <nav> as space-between, which
 * throws three tabs to the far corners of a 1400px screen. */
.guide-tabs {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  gap: 1rem;
  margin-bottom: 1.2rem;
}
.guide-tabs a { font-size: 0.9em; }
.guide-tabs a.current { font-weight: 600; text-decoration: none; border-bottom: 2px solid var(--brand-yellow); }

/* The theme switch. A nav item, not a button: Pico styles <button> as a filled primary
 * control, which would make it the loudest thing on every page. */
.theme-toggle {
  background: none;
  border: none;
  padding: 0 0.2rem;
  margin: 0;
  width: auto;
  font-size: 1rem;
  line-height: 1;
  color: inherit;
  cursor: pointer;
  opacity: 0.75;
}

.theme-toggle:hover,
.theme-toggle:focus-visible { opacity: 1; }
