/* Talsuite UI — implements docs/ui-reference.md on top of Bootstrap 5.3
   ─────────────────────────────────────────────────────────────────────────────
   Every colour is a token. Light is the default; dark redefines the same tokens,
   once for people whose system asks for it and once for an explicit choice. The
   accent is one token per Vendor, and its hover, tint and gradient shades derive
   from it, so a new accent is two values rather than a new palette.            */

/* The two typefaces, since 29 Sep 2026 (PLAN.md, The candidate form in the 29 Sep design, and Inter
   everywhere), served from this site rather than a font CDN. Variable fonts, so every weight the scale uses
   — 650 headings included, which a static family rounds — is one file per script, and a browser fetches a
   script only when a page contains it: Latin always, Latin Extended for an accented name or a rupee sign.
   JetBrains Mono is upright only; nothing here sets code in italics. The licences sit beside the files. */
@font-face {
  font-family: "Inter"; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url("../lib/fonts/inter/inter-latin-wght-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter"; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url("../lib/fonts/inter/inter-latin-ext-wght-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
    U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Inter"; font-style: italic; font-weight: 100 900; font-display: swap;
  src: url("../lib/fonts/inter/inter-latin-wght-italic.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter"; font-style: italic; font-weight: 100 900; font-display: swap;
  src: url("../lib/fonts/inter/inter-latin-ext-wght-italic.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
    U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "JetBrains Mono"; font-style: normal; font-weight: 100 800; font-display: swap;
  src: url("../lib/fonts/jetbrains-mono/jetbrains-mono-latin-wght-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "JetBrains Mono"; font-style: normal; font-weight: 100 800; font-display: swap;
  src: url("../lib/fonts/jetbrains-mono/jetbrains-mono-latin-ext-wght-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
    U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  color-scheme: light;

  /* Surfaces and ink */
  --ts-bg: #f6f8fc;
  --ts-card: #ffffff;
  --ts-surface-2: #f1f5f9;
  --ts-text: #0f172a;
  --ts-text-2: #334155;
  --ts-muted: #64748b;
  --ts-border: #e2e8f0;

  /* Accent. A Vendor picks one of the [data-ts-accent] sets below; this is the default.

     Held as components rather than as a hex, and the hex derives from them. Bootstrap writes every link
     as rgba(var(--bs-link-color-rgb), ...) and will not read a colour, so an accent that exists only as
     #1f5eff cannot reach a link — which is the bug that left every link in the app Bootstrap blue while
     the buttons beside them were the Vendor's own. Components go both ways; a hex goes one. */
  --ts-accent-light-rgb: 31, 94, 255;
  --ts-accent-dark-rgb: 107, 147, 255;
  --ts-accent-light: rgb(var(--ts-accent-light-rgb));
  --ts-accent-dark: rgb(var(--ts-accent-dark-rgb));
  --ts-primary: var(--ts-accent-light);
  --ts-primary-rgb: var(--ts-accent-light-rgb);
  --ts-primary-dark: color-mix(in srgb, var(--ts-primary) 85%, #000);
  --ts-primary-light: color-mix(in srgb, var(--ts-primary) 75%, #fff);
  --ts-primary-soft: color-mix(in srgb, var(--ts-primary) 12%, var(--ts-card));
  --ts-primary-ink: color-mix(in srgb, var(--ts-primary) 82%, #000);
  --ts-on-primary: #ffffff;
  --ts-focus: color-mix(in srgb, var(--ts-primary) 25%, transparent);

  /* Status. Each pairs an ink with a tint mixed into the card, so both follow the theme. */
  --ts-ok: #16a34a;
  --ts-warn: #ea580c;
  --ts-danger: #dc2626;
  --ts-info: #7c3aed;
  --ts-neutral: #475569;
  --ts-ok-soft: #dcfce7;
  --ts-warn-soft: #ffedd5;
  --ts-danger-soft: #fee2e2;
  --ts-info-soft: #ede9fe;
  --ts-neutral-soft: #f1f5f9;

  /* Avatar wheel */
  --ts-c0: #7c3aed; --ts-c1: #f97316; --ts-c2: #0ea5e9;
  --ts-c3: #ec4899; --ts-c4: #22c55e; --ts-c5: #6366f1;

  /* The banner and the auth backdrop are pictures rather than flat fills, so they
     get their own tokens: bright in light, deep in dark. */
  --ts-banner-from: var(--ts-primary-dark);
  --ts-banner-to: var(--ts-primary-light);
  --ts-banner-ink: #ffffff;
  --ts-banner-shadow: 0 12px 30px color-mix(in srgb, var(--ts-primary) 25%, transparent);

  /* Card geometry, moved to the design the user drew on 24 Sep 2026. A tighter corner and a much
     flatter shadow: 14px and a 24px lift made every card read as a floating tile, and a screen that is
     nine cards deep — which the candidate's page is — turned into nine tiles with gaps between them
     rather than one page. The second shadow is 12px and barely there, which is what holds a card to the
     canvas instead of above it. */
  --ts-radius: 10px;
  --ts-radius-sm: 8px;
  --ts-shadow: 0 1px 2px rgba(22, 32, 43, 0.04), 0 1px 12px rgba(22, 32, 43, 0.04);
  --ts-sidebar-w: 232px;
  --ts-topbar-h: 60px;

  /* Type: Inter and JetBrains Mono since 29 Sep 2026, from the @font-face blocks above. Until then these
     were the system stacks shared with RecruitMetrics, and those stay behind them: they are what a page
     shows for the moment before the files arrive, and for good if they never do. */
  --ts-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --ts-mono: "JetBrains Mono", "Cascadia Mono", ui-monospace, "SFMono-Regular", Consolas, "Liberation Mono", monospace;

  --bs-primary: var(--ts-primary);
  --bs-body-bg: var(--ts-bg);
  --bs-body-color: var(--ts-text);
  --bs-body-font-family: var(--ts-sans);
  /* 15px, from the same design. It was 14 to match RecruitMetrics, and the whole product read one notch
     smaller than the screen it is replacing. Everything pinned in px below moved with it. */
  --bs-body-font-size: 15px;
  --bs-body-line-height: 1.55;
  --bs-font-monospace: var(--ts-mono);
  --bs-border-color: var(--ts-border);

  /* Links, fixed 23 Sep 2026. These were set as hexes and did nothing for months: Bootstrap 5.3 writes
     `a { color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1)) }` and reads only the -rgb
     half, so every link in the app stayed #0d6efd whatever accent the Vendor picked. It showed worst on
     an accent far from blue — on the demo Vendor the buttons were rust and the links beside them blue,
     which is what made the two look like they came from different products.
     Both halves are set now: the hex for anything that reads a colour, the components for Bootstrap. */
  --bs-link-color: var(--ts-primary);
  --bs-link-color-rgb: var(--ts-primary-rgb);

  /* Hover is the accent faded rather than the accent darkened, and that is a real choice. Darkening
     needs a third number per accent — --bs-link-hover-color-rgb takes components too, and
     --ts-primary-dark is a color-mix, which cannot be decomposed — and the table below is meant to stay
     two values per accent. Fading works in both themes without a third: on a white card it recedes, on
     a dark one it recedes too, because it moves toward whatever is behind it.

     The hover pair still points at the accent so that nothing can fall back to Bootstrap's own darker
     blue, which is what `a:hover` would otherwise resolve to. */
  --bs-link-hover-color: var(--ts-primary-dark);
  --bs-link-hover-color-rgb: var(--ts-primary-rgb);
}

/* Curated accents. Two values each: the light-mode base and a lighter dark-mode base.
   Every other shade derives, and text on the accent is white in light, near-black in dark,
   so no combination can produce unreadable buttons.

   Components rather than hexes since 23 Sep 2026, for the reason at the top of the file: a link is
   rgba(components) and cannot be given a colour. The hexes still exist — :root derives them — so
   everything reading --ts-accent-light is untouched. These are the same sixteen colours as before:
   #1f5eff #6b93ff, #4f46e5 #8b85f0, #7c3aed #a78bfa, #0d9488 #2dd4bf, #15803d #4ade80, #b45309 #fbbf24,
   #e11d48 #fb7185, #475569 #94a3b8. */
[data-ts-accent="blue"]   { --ts-accent-light-rgb: 31, 94, 255;   --ts-accent-dark-rgb: 107, 147, 255; }
[data-ts-accent="indigo"] { --ts-accent-light-rgb: 79, 70, 229;   --ts-accent-dark-rgb: 139, 133, 240; }
[data-ts-accent="violet"] { --ts-accent-light-rgb: 124, 58, 237;  --ts-accent-dark-rgb: 167, 139, 250; }
[data-ts-accent="teal"]   { --ts-accent-light-rgb: 13, 148, 136;  --ts-accent-dark-rgb: 45, 212, 191; }
[data-ts-accent="green"]  { --ts-accent-light-rgb: 21, 128, 61;   --ts-accent-dark-rgb: 74, 222, 128; }
[data-ts-accent="amber"]  { --ts-accent-light-rgb: 180, 83, 9;    --ts-accent-dark-rgb: 251, 191, 36; }
[data-ts-accent="rose"]   { --ts-accent-light-rgb: 225, 29, 72;   --ts-accent-dark-rgb: 251, 113, 133; }
[data-ts-accent="slate"]  { --ts-accent-light-rgb: 71, 85, 105;   --ts-accent-dark-rgb: 148, 163, 184; }

/* Dark. Declared twice on purpose: once for "follow my system" and once for an explicit
   choice, because CSS cannot share a block between a media query and an attribute. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --ts-bg: #0b1220;
    --ts-card: #121a2b;
    --ts-surface-2: #1b2436;
    --ts-text: #e6ebf5;
    --ts-text-2: #b6c0d4;
    --ts-muted: #8b97ad;
    --ts-border: #253048;

    --ts-primary: var(--ts-accent-dark);
    --ts-primary-rgb: var(--ts-accent-dark-rgb);
    --ts-primary-dark: color-mix(in srgb, var(--ts-primary) 85%, #fff);
    --ts-primary-light: color-mix(in srgb, var(--ts-primary) 70%, #000);
    --ts-primary-soft: color-mix(in srgb, var(--ts-primary) 14%, var(--ts-card));
    --ts-primary-ink: var(--ts-primary);
    --ts-on-primary: #0b1220;

    --ts-ok: #4ade80;
    --ts-warn: #fb923c;
    --ts-danger: #f87171;
    --ts-info: #a78bfa;
    --ts-neutral: #94a3b8;
    --ts-ok-soft: color-mix(in srgb, var(--ts-ok) 16%, var(--ts-card));
    --ts-warn-soft: color-mix(in srgb, var(--ts-warn) 16%, var(--ts-card));
    --ts-danger-soft: color-mix(in srgb, var(--ts-danger) 16%, var(--ts-card));
    --ts-info-soft: color-mix(in srgb, var(--ts-info) 16%, var(--ts-card));
    --ts-neutral-soft: color-mix(in srgb, var(--ts-neutral) 16%, var(--ts-card));

    --ts-banner-from: color-mix(in srgb, var(--ts-primary) 28%, #060b16);
    --ts-banner-to: color-mix(in srgb, var(--ts-primary) 46%, #060b16);
    --ts-banner-ink: #f8fafc;
    --ts-banner-shadow: 0 12px 30px rgba(0, 0, 0, .45);
    --ts-shadow: 0 1px 2px rgba(0, 0, 0, .35), 0 1px 12px rgba(0, 0, 0, .3);

    --bs-secondary-bg: var(--ts-surface-2);
    --bs-tertiary-bg: var(--ts-surface-2);
    --bs-secondary-color: var(--ts-muted);
    --bs-emphasis-color: var(--ts-text);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --ts-bg: #0b1220;
  --ts-card: #121a2b;
  --ts-surface-2: #1b2436;
  --ts-text: #e6ebf5;
  --ts-text-2: #b6c0d4;
  --ts-muted: #8b97ad;
  --ts-border: #253048;

  --ts-primary: var(--ts-accent-dark);
  --ts-primary-rgb: var(--ts-accent-dark-rgb);
  --ts-primary-dark: color-mix(in srgb, var(--ts-primary) 85%, #fff);
  --ts-primary-light: color-mix(in srgb, var(--ts-primary) 70%, #000);
  --ts-primary-soft: color-mix(in srgb, var(--ts-primary) 14%, var(--ts-card));
  --ts-primary-ink: var(--ts-primary);
  --ts-on-primary: #0b1220;

  --ts-ok: #4ade80;
  --ts-warn: #fb923c;
  --ts-danger: #f87171;
  --ts-info: #a78bfa;
  --ts-neutral: #94a3b8;
  --ts-ok-soft: color-mix(in srgb, var(--ts-ok) 16%, var(--ts-card));
  --ts-warn-soft: color-mix(in srgb, var(--ts-warn) 16%, var(--ts-card));
  --ts-danger-soft: color-mix(in srgb, var(--ts-danger) 16%, var(--ts-card));
  --ts-info-soft: color-mix(in srgb, var(--ts-info) 16%, var(--ts-card));
  --ts-neutral-soft: color-mix(in srgb, var(--ts-neutral) 16%, var(--ts-card));

  --ts-banner-from: color-mix(in srgb, var(--ts-primary) 28%, #060b16);
  --ts-banner-to: color-mix(in srgb, var(--ts-primary) 46%, #060b16);
  --ts-banner-ink: #f8fafc;
  --ts-banner-shadow: 0 12px 30px rgba(0, 0, 0, .45);
  --ts-shadow: 0 1px 2px rgba(0, 0, 0, .35), 0 1px 12px rgba(0, 0, 0, .3);

  --bs-secondary-bg: var(--ts-surface-2);
  --bs-tertiary-bg: var(--ts-surface-2);
  --bs-secondary-color: var(--ts-muted);
  --bs-emphasis-color: var(--ts-text);
}

html, body { height: 100%; }
body {
  font-family: var(--ts-sans);
  font-size: 14px;
  line-height: 1.55;
  background: var(--ts-bg);
  color: var(--ts-text);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
a { text-decoration: none; }

/* The hover, now that a link is finally the accent and no longer changes colour on hover by itself.
   Underline is off above, so colour is the only affordance a link has left.

   It sets a custom property rather than a colour on purpose: --bs-link-opacity is read only by things
   using Bootstrap's link formula — bare anchors, .link-* and .btn-link — so this cannot reach the
   sidebar, the brand, the row links or anything else in this file that sets its own colour. A plain
   `a:hover { color: … }` would have reached all of them, because most set colour at one class of
   specificity and a hover beats that. */
a:hover { --bs-link-opacity: .75; }
.text-muted { color: var(--ts-muted) !important; }

/* Type scale. Bootstrap sizes its components in rem off a 16px root, so the ones this app
   uses are pinned in px here and everything lands on one scale.

   Rescaled 24 Sep 2026 to the design the user drew. The body went up a point and the headings came
   down: a 21px h1 over 14px body is a five-step gap that made every page shout its own title, and the
   design it is now matched to runs 20/15.5 over 15. Headings are 650 rather than 600 throughout, which
   is what lets them shrink without stopping being headings. */
h1, .h1 { font-size: 20px; font-weight: 650; letter-spacing: -.01em; line-height: 1.25; }
h2, .h2 { font-size: 15.5px; font-weight: 650; letter-spacing: -.005em; line-height: 1.3; }
h3, .h3, h4, .h4, h5, .h5, h6, .h6 { font-size: 14px; font-weight: 650; }
small, .small { font-size: 12.5px; }
code, kbd, samp, pre, .font-monospace { font-family: var(--ts-mono); }
.ts-num { font-variant-numeric: tabular-nums; }

.btn { font-size: 13px; font-weight: 600; }
.btn-primary, .btn-danger, .btn-outline-primary, .btn-outline-danger { font-weight: 600; }
.form-control, .form-select { font-size: 13.5px; }
.form-control-sm, .form-select-sm { font-size: 12.5px; }
.form-text { font-size: 12px; color: var(--ts-muted); }
.table { font-size: 13.5px; }
.alert, .dropdown-menu, .input-group-text { font-size: 13.5px; }
.badge { font-family: var(--ts-mono); font-size: 10.5px; font-weight: 600; letter-spacing: .05em; }

/* Shell: one header across the top carrying the brand, the page name and the account menu, and
   under it the sidebar beside the page. The brand sits in the header rather than above the nav, so
   the header reads as the product's own bar rather than a strip left over above the content. */
.ts-shell { display: flex; flex-direction: column; min-height: 100vh; }
.ts-topbar {
  position: sticky; top: 0; z-index: 1040;
  display: flex; align-items: center; gap: 16px;
  height: var(--ts-topbar-h); padding-right: 24px;
  background: var(--ts-card); border-bottom: 1px solid var(--ts-border);
}
/* The header's left cell, exactly as wide as the menu below it: the brand, then the collapse
   control on the same line, against the border the two columns share. */
.ts-brand-cell {
  flex: 0 0 var(--ts-sidebar-w); width: var(--ts-sidebar-w); align-self: stretch;
  display: flex; align-items: center; gap: 4px; padding-right: 10px;
  border-right: 1px solid var(--ts-border);
}
.ts-brand {
  flex: 1; min-width: 0; align-self: stretch;
  display: flex; align-items: center; gap: 10px; padding: 0 0 0 20px;
  font-weight: 600; font-size: 14px; letter-spacing: -.015em; color: var(--ts-text); text-decoration: none;
}
/* Bare, because it sits on the brand's line and a filled button there would read as the brand's own. */
.ts-nav-collapse {
  flex: 0 0 auto; align-items: center; justify-content: center;
  width: 28px; height: 28px; padding: 0;
  background: none; border: 0; border-radius: 8px; color: var(--ts-muted);
}
.ts-nav-collapse:hover { background: var(--ts-surface-2); color: var(--ts-text); }
.ts-brand:hover { color: var(--ts-text); }
.ts-brand .ts-star { width: 26px; height: 26px; flex: 0 0 26px; color: var(--ts-primary); }
.ts-brand > div { min-width: 0; line-height: 1.2; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ts-brand small { display: block; font-size: 11px; font-weight: 400; color: var(--ts-muted); }
/* The page's own name. The only h1 on the page, so the headings below it start at h2. */
.ts-topbar-title { margin: 0; font-size: 15px; font-weight: 600; letter-spacing: -.01em; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ts-topbar-end { display: flex; align-items: center; gap: 10px; margin-left: auto; }

.ts-body { display: flex; flex: 1; min-height: 0; }
.ts-sidebar {
  width: var(--ts-sidebar-w);
  flex: 0 0 var(--ts-sidebar-w);
  background: var(--ts-card);
  border-right: 1px solid var(--ts-border);
  display: flex; flex-direction: column;
  position: sticky; top: var(--ts-topbar-h); height: calc(100vh - var(--ts-topbar-h));
}
.ts-nav { list-style: none; margin: 0; padding: 12px; flex: 1; overflow-y: auto; }
.ts-nav-section { font-family: var(--ts-mono); font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: .1em; color: var(--ts-muted); padding: 14px 12px 6px; }
.ts-nav a {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px; border-radius: 999px; color: var(--ts-text-2); font-size: 13.5px; font-weight: 500;
}
.ts-nav a:hover { background: var(--ts-surface-2); color: var(--ts-text); }
/* Selected page: a soft tint rather than a solid fill, so the sidebar stays quiet. */
.ts-nav a.active { background: var(--ts-primary-soft); color: var(--ts-primary-ink); font-weight: 600; }
.ts-nav a .lucide { width: 18px; height: 18px; flex: 0 0 18px; }
.ts-nav .badge { margin-left: auto; }
.ts-nav .ts-dot { margin-left: auto; width: 8px; height: 8px; border-radius: 50%; background: var(--ts-danger); }
.ts-main { flex: 1; min-width: 0; padding: 20px 28px 40px; }

/* The Vendor's logo, wherever it is drawn: on a white plate in dark mode, as the user chose on 7 Oct 2026, and
   as it always was in light. A logo is drawn for a white page, and ImageProcessor keeps its transparency, so dark
   lettering on a clear ground vanished on a dark header and left only the coloured parts behind.
   The plate is the image's own padding, and every place that sizes a logo adds that padding to its size, so the
   logo is as big in both themes and the plate takes room of its own rather than covering the name beside it. The
   corners round only where there is a plate, so a logo in light mode is not trimmed at its corners either. */
:root { --ts-logo-plate: transparent; --ts-logo-pad: 0px; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --ts-logo-plate: #fff; --ts-logo-pad: 4px; }
}
:root[data-theme="dark"] { --ts-logo-plate: #fff; --ts-logo-pad: 4px; }
.ts-vendor-logo {
  padding: var(--ts-logo-pad) calc(var(--ts-logo-pad) * 1.5);
  background: var(--ts-logo-plate); border-radius: calc(var(--ts-logo-pad) * 1.5);
  object-fit: contain;
}
/* At the head of the Super Admin's page for one Vendor, the largest the logo is drawn anywhere but its preview. */
.ts-vendor-page-logo { height: calc(48px + 2 * var(--ts-logo-pad)); max-width: calc(192px + 3 * var(--ts-logo-pad)); }

/* The tenant's logo, sized here rather than on the element, so the collapsed menu below can make it
   smaller — an inline style cannot be overridden by a stylesheet. */
.ts-brand img { height: calc(26px + 2 * var(--ts-logo-pad)); max-width: calc(110px + 3 * var(--ts-logo-pad)); object-fit: contain; }

/* The menu narrowed to its icons.
   Both the sidebar and the brand block above it are sized from --ts-sidebar-w, so redefining that one
   variable moves the column and the header's left cell together and they cannot drift apart.
   Only from the breakpoint up: below it the sidebar is a slide-out, and a rail would be a third state
   nobody asked for. */
@media (min-width: 993px) {
  :root.ts-nav-collapsed { --ts-sidebar-w: 68px; }
  /* The logo stays and its name goes: 68px holds the mark and the control that brings the menu back,
     so both keep their own padding down to nothing and the control loses a few pixels of its box. */
  .ts-nav-collapsed .ts-brand-cell { justify-content: center; gap: 2px; padding: 0 4px; }
  .ts-nav-collapsed .ts-brand { flex: 0 0 auto; padding: 0; }
  .ts-nav-collapsed .ts-brand > div { display: none; }
  /* The logo keeps its own shape here, a sliver 26px wide, so a dark plate is a sliver too rather than a white
     square with a line across it, and its sides are as thin as its top to leave the control its room. */
  .ts-nav-collapsed .ts-brand img { height: auto; max-width: calc(26px + 2 * var(--ts-logo-pad)); padding: var(--ts-logo-pad); }
  .ts-nav-collapsed .ts-nav-collapse { width: 24px; }
  .ts-nav-collapsed .ts-nav { padding: 12px 10px; }
  .ts-nav-collapsed .ts-nav a { justify-content: center; padding: 10px 0; }
  /* The label stays in the document rather than being removed: it is the link's accessible name and
     the tooltip's text, and a rail of unnamed icons is not navigable without them. */
  .ts-nav-collapsed .ts-nav-label {
    position: absolute; width: 1px; height: 1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap;
  }
  /* A section heading with no room for its word becomes the rule it was already acting as. */
  .ts-nav-collapsed .ts-nav-section { font-size: 0; padding: 12px 6px 6px; }
  .ts-nav-collapsed .ts-nav-section::after { content: ""; display: block; height: 1px; background: var(--ts-border); }
}

.ts-user {
  display: flex; align-items: center; gap: 9px;
  padding: 4px 10px 4px 4px; border: 1px solid transparent; border-radius: 999px;
  background: none; color: var(--ts-text); cursor: pointer; max-width: 220px;
}
.ts-user:hover, .ts-user[aria-expanded="true"] { background: var(--ts-surface-2); border-color: var(--ts-border); }
.ts-user-who { min-width: 0; text-align: left; line-height: 1.25; }
.ts-user-name { display: block; font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ts-user-role { display: block; font-size: 11px; color: var(--ts-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ts-user-caret { width: 14px; height: 14px; flex: 0 0 14px; color: var(--ts-muted); }
.ts-user-menu { min-width: 236px; padding: 6px; }
.ts-user-head { padding: 8px 12px 6px; font-size: 12.5px; }
.ts-user-menu .dropdown-item { display: flex; align-items: center; gap: 10px; border-radius: var(--ts-radius-sm); padding: 9px 12px; }
.ts-user-menu .dropdown-item svg { width: 15px; height: 15px; flex: 0 0 15px; color: var(--ts-muted); }
.ts-user-menu .dropdown-divider { margin: 4px 0; }
/* The appearance item carries both wordings and shows one, so the row itself is the layout. */
.ts-user-menu .ts-item { display: flex; align-items: center; gap: 10px; }
/* Signing out is the one thing here you cannot undo with the back button. */
.ts-user-menu .dropdown-item.ts-danger, .ts-user-menu .dropdown-item.ts-danger svg { color: var(--ts-danger); }
.ts-user-menu .dropdown-item.ts-danger:hover, .ts-user-menu .dropdown-item.ts-danger:focus { background: var(--ts-danger-soft); color: var(--ts-danger); }

/* Appearance switch: three states, because "follow my system" is a real answer. */
.ts-theme { display: inline-flex; gap: 2px; padding: 2px; border: 1px solid var(--ts-border); border-radius: 999px; background: var(--ts-surface-2); }
.ts-theme button {
  display: inline-grid; place-items: center; width: 26px; height: 24px;
  border: 0; border-radius: 999px; background: none; color: var(--ts-muted); cursor: pointer; padding: 0;
}
.ts-theme button:hover { color: var(--ts-text); }
.ts-theme button[aria-pressed="true"] { background: var(--ts-card); color: var(--ts-primary-ink); box-shadow: 0 1px 2px rgba(0, 0, 0, .12); }
.ts-theme .lucide { width: 14px; height: 14px; }

/* Header banner */
.ts-banner {
  background: linear-gradient(120deg, var(--ts-banner-from), var(--ts-banner-to));
  color: var(--ts-banner-ink); border-radius: var(--ts-radius); padding: 22px 26px 18px;
  box-shadow: var(--ts-banner-shadow);
}
.ts-banner .ts-greeting { font-size: 21px; font-weight: 600; letter-spacing: -.01em; line-height: 1.25; margin: 0; }
.ts-banner .ts-sub { font-size: 12.5px; opacity: .85; margin: 4px 0 0; }
.ts-banner .form-control { border: 0; border-radius: 999px; padding: 10px 18px; background: rgba(255, 255, 255, .95); color: #0f172a; }
.ts-banner .ts-avatar { width: 44px; height: 44px; border: 2px solid rgba(255, 255, 255, .7); }
.ts-banner .ts-chip { background: rgba(255, 255, 255, .18); border-radius: 999px; padding: 6px 12px; font-size: 12.5px; }
.ts-quick { display: flex; gap: 18px; flex-wrap: wrap; margin-top: 18px; }
.ts-quick a { display: flex; flex-direction: column; align-items: center; gap: 6px; color: var(--ts-banner-ink); font-size: 12.5px; opacity: .95; }
.ts-quick a span.ic { width: 44px; height: 44px; border-radius: 50%; background: rgba(255, 255, 255, .18); display: grid; place-items: center; transition: background .15s; }
.ts-quick a:hover span.ic { background: rgba(255, 255, 255, .32); }
.ts-quick .lucide { width: 20px; height: 20px; }

/* Cards */
.ts-card {
  background: var(--ts-card); border: 1px solid var(--ts-border); border-radius: var(--ts-radius);
  box-shadow: var(--ts-shadow); padding: 18px 20px;
}
.ts-card-title { font-size: 15.5px; font-weight: 650; letter-spacing: -.005em; line-height: 1.3; margin: 0 0 12px; display: flex; align-items: center; gap: 8px; }
.ts-card-title .lucide { width: 17px; height: 17px; color: var(--ts-muted); }
.ts-kpi { display: flex; flex-direction: column; gap: 6px; min-height: 96px; }
.ts-kpi .ts-kpi-label { color: var(--ts-muted); font-family: var(--ts-mono); font-size: 10.5px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; display: flex; align-items: center; gap: 6px; }
.ts-kpi .ts-kpi-value { font-size: 26px; font-weight: 650; letter-spacing: -.02em; line-height: 1.15; font-variant-numeric: tabular-nums; }
.ts-kpi .ts-kpi-delta { font-size: 12px; color: var(--ts-ok); }
.ts-kpi .ts-kpi-delta.neg { color: var(--ts-danger); }
.ts-list { list-style: none; margin: 0; padding: 0; }
.ts-list li { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-top: 1px solid var(--ts-border); }
.ts-list li:first-child { border-top: 0; padding-top: 0; }
.ts-list .ts-list-main { flex: 1; min-width: 0; }
.ts-list .ts-list-main strong { display: block; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ts-list .ts-list-main small { color: var(--ts-muted); }
.ts-card-more { display: block; margin-top: 12px; font-size: 12.5px; font-weight: 600; color: var(--ts-primary); }

/* Avatars and tiles */
.ts-avatar {
  width: 36px; height: 36px; border-radius: 50%; display: inline-grid; place-items: center;
  font-weight: 700; font-size: 11.5px; color: #fff; flex: 0 0 auto;
}
.ts-avatar.c0 { background: var(--ts-c0); } .ts-avatar.c1 { background: var(--ts-c1); } .ts-avatar.c2 { background: var(--ts-c2); }
.ts-avatar.c3 { background: var(--ts-c3); } .ts-avatar.c4 { background: var(--ts-c4); } .ts-avatar.c5 { background: var(--ts-c5); }
.ts-avatar-photo { object-fit: cover; background: var(--ts-surface-2); }
/* No picture yet, on a form that is offering to take one. Not a coloured initial: initials say "this is
   who it is", and here the point is the empty slot. */
.ts-avatar.grey { background: var(--ts-surface-2); color: var(--ts-neutral); }

/* A picture you change by clicking the picture. The pencil sits on the corner rather than beside the frame
   so the control is one object: at a glance it reads as "this is the photo", not "this is a file field". */
.ts-photo { position: relative; flex: 0 0 auto; container-type: size; }
.ts-photo-shot,
.ts-photo-empty {
  width: 100%; height: 100%; border-radius: 14px; display: grid; place-items: center;
  border: 1px solid var(--ts-border); background: var(--ts-surface-2); object-fit: cover;
}
.ts-photo-empty { color: var(--ts-muted); }
.ts-photo-empty i, .ts-photo-empty svg { width: 38%; height: 38%; stroke-width: 1.5; }
/* Sized off the frame, not off the page: the control is 96px on a form and the same markup could be
   smaller anywhere else that reuses it. Containment only covers size, layout and style, so the two buttons
   hanging off the corners still paint. */
.ts-photo-initials { font-size: 26cqw; font-weight: 700; letter-spacing: .5px; }

/* Off-screen rather than hidden: a display:none input cannot take focus, and the pencil is a <label for>,
   which is the whole reason this reaches the file dialog from the keyboard. */
.ts-photo-file { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.ts-photo-file:focus-visible + .ts-photo-edit { outline: 2px solid var(--ts-primary); outline-offset: 2px; }

.ts-photo-btn {
  position: absolute; width: 28px; height: 28px; border-radius: 50%; border: 2px solid var(--ts-card);
  display: grid; place-items: center; cursor: pointer; padding: 0; line-height: 0;
  box-shadow: 0 1px 3px rgb(0 0 0 / 18%);
}
/* lucide swaps the <i> for an <svg> once it runs, so both are named: the rule has to hold either way. */
.ts-photo-btn i, .ts-photo-btn svg { width: 15px; height: 15px; }
.ts-photo-edit { top: -8px; right: -8px; background: var(--ts-primary); color: #fff; }
.ts-photo-edit:hover { filter: brightness(1.08); }
.ts-photo-clear { bottom: -8px; right: -8px; background: var(--ts-card); color: var(--ts-muted); }
.ts-photo-clear:hover { color: var(--ts-danger); }

/* A comma-separated box, worn as chips. The outer element takes Bootstrap's .form-control so it lines up
   with every other field on the form and picks up the focus ring for free. */
.ts-tokens-wrap { position: relative; }
.ts-tokens {
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center; cursor: text;
  min-height: 38px; height: auto; padding: 5px 8px;
}
.ts-tokens:focus-within { border-color: var(--ts-primary); box-shadow: 0 0 0 3px var(--ts-focus); }

.ts-token {
  display: inline-flex; align-items: center; gap: 5px; max-width: 100%;
  background: var(--ts-primary-soft); color: var(--ts-primary-ink);
  border: 1px solid color-mix(in srgb, var(--ts-primary) 22%, transparent);
  border-radius: 999px; padding: 2px 6px 2px 10px; font-size: 12.5px; font-weight: 600;
}
.ts-token-x {
  border: 0; background: none; color: inherit; opacity: .6; cursor: pointer;
  font-size: 15px; line-height: 1; padding: 0 2px;
}
.ts-token-x:hover { opacity: 1; color: var(--ts-danger); }

/* No border of its own: it is a hole in the chip row, not a field inside a field. */
.ts-token-input {
  flex: 1 1 90px; min-width: 90px; border: 0; outline: 0; background: none;
  padding: 2px 0; font-size: inherit; color: inherit;
}

.ts-token-menu {
  position: absolute; z-index: 20; left: 0; right: 0; top: calc(100% + 4px);
  background: var(--ts-card); border: 1px solid var(--ts-border); border-radius: 10px;
  box-shadow: 0 8px 24px rgb(15 23 42 / 12%); padding: 4px; max-height: 310px; overflow-y: auto;
}
.ts-token-option {
  display: block; width: 100%; text-align: left; border: 0; background: none; cursor: pointer;
  padding: 6px 10px; border-radius: 7px; font-size: 13.5px; color: var(--ts-text-2);
}
.ts-token-option:hover,
.ts-token-option.is-on { background: var(--ts-primary-soft); color: var(--ts-primary-ink); }
/* The one at the top of a person's own page, where it is the subject rather than a row marker. */
.ts-avatar-lg { width: 52px; height: 52px; font-size: 17px; }

/* The email signature as it will print, so what you type is what they get. */
.ts-signature-preview {
  border: 1px solid var(--ts-border); border-radius: var(--ts-radius-sm); padding: 12px 14px;
  background: var(--ts-surface-2); font-size: 13px; line-height: 1.55; color: var(--ts-text);
  overflow-wrap: anywhere;
}

.ts-tile { width: 36px; height: 36px; border-radius: 10px; display: inline-grid; place-items: center; background: var(--ts-primary); color: var(--ts-on-primary); }


/* The reveal button on a password box. Sits inside the field, so the field keeps its width in a grid. */
.ts-reveal { position: relative; display: block; }
.ts-reveal > .form-control { padding-right: 40px; }
.ts-reveal-btn {
  position: absolute; top: 0; right: 0; bottom: 0; width: 38px;
  display: grid; place-items: center; padding: 0;
  border: 0; background: none; color: var(--ts-muted); cursor: pointer; border-radius: 0 var(--ts-radius-sm) var(--ts-radius-sm) 0;
}
.ts-reveal-btn:hover, .ts-reveal-btn[aria-pressed="true"] { color: var(--ts-text); }
.ts-reveal-btn svg { width: 16px; height: 16px; }
.ts-reveal-btn:focus-visible { outline: 2px solid var(--ts-primary); outline-offset: -2px; }


/* Settings categories down the side; the chosen one's detail fills the rest of the row. */
.ts-settings-nav { padding: 8px; display: flex; flex-direction: column; gap: 2px; }
.ts-settings-nav a {
  display: flex; gap: 10px; align-items: flex-start; padding: 10px 12px;
  border-radius: var(--ts-radius-sm); color: var(--ts-text); text-decoration: none;
}
.ts-settings-nav a:hover { background: var(--ts-surface-2); }
.ts-settings-nav a.active { background: color-mix(in srgb, var(--ts-primary) 12%, transparent); color: var(--ts-primary-ink); }
.ts-settings-nav a.active .ts-settings-nav-blurb { color: var(--ts-primary-ink); opacity: .75; }
.ts-settings-nav svg { width: 16px; height: 16px; flex: 0 0 auto; margin-top: 2px; }
.ts-settings-nav-title { display: block; font-weight: 600; font-size: 13.5px; }
.ts-settings-nav-blurb { display: block; font-size: 11.5px; color: var(--ts-muted); line-height: 1.4; }

/* The way back out of a page that has no sidebar entry of its own, at the top left where reading starts. */
.ts-back {
  display: inline-flex; align-items: center; gap: 6px; margin-bottom: 6px;
  font-size: 12.5px; font-weight: 600; color: var(--ts-muted); text-decoration: none;
}
.ts-back:hover { color: var(--ts-primary); }
.ts-back svg { width: 14px; height: 14px; }

/* Pills */
.ts-pill { display: inline-block; padding: 3px 10px; border-radius: 999px; font-family: var(--ts-mono); font-size: 10.5px; font-weight: 600; letter-spacing: .05em; text-transform: uppercase; }
.ts-pill.green { background: var(--ts-ok-soft); color: var(--ts-ok); }
.ts-pill.orange { background: var(--ts-warn-soft); color: var(--ts-warn); }
.ts-pill.blue { background: var(--ts-primary-soft); color: var(--ts-primary-ink); }
.ts-pill.grey { background: var(--ts-neutral-soft); color: var(--ts-neutral); }
.ts-pill.red { background: var(--ts-danger-soft); color: var(--ts-danger); }
.ts-pill.violet { background: var(--ts-info-soft); color: var(--ts-info); }

/* Page header + tables + forms */
.ts-page-sub { color: var(--ts-muted); font-size: 13.5px; margin: 2px 0 0; }

.table { --bs-table-bg: transparent; --bs-table-color: var(--ts-text); --bs-table-border-color: var(--ts-border); }
.table > :not(caption) > * > * { padding: .7rem .75rem; }
.table thead th { font-family: var(--ts-mono); font-size: 10.5px; text-transform: uppercase; letter-spacing: .08em; color: var(--ts-muted); font-weight: 600; border-bottom-width: 1px; }
.ts-card .table { margin-bottom: 0; }
.btn { border-radius: 999px; padding: .5rem 1.1rem; }
.btn-sm { padding: .3rem .8rem; font-size: 12.5px; }

/* An icon in a button is a mark beside the word, not a second word. Lucide draws at 24px unless it is
   told otherwise, which is half again the height of the line it sits on; every button in the app was
   carrying an inline size to say so, and this is that said once. */
.btn .lucide { width: 16px; height: 16px; }
.btn-sm .lucide { width: 14px; height: 14px; }
.btn-primary { --bs-btn-bg: var(--ts-primary); --bs-btn-border-color: var(--ts-primary); --bs-btn-color: var(--ts-on-primary); --bs-btn-hover-bg: var(--ts-primary-dark); --bs-btn-hover-border-color: var(--ts-primary-dark); --bs-btn-hover-color: var(--ts-on-primary); --bs-btn-active-bg: var(--ts-primary-dark); --bs-btn-active-color: var(--ts-on-primary); --bs-btn-disabled-bg: var(--ts-primary); --bs-btn-disabled-border-color: var(--ts-primary); --bs-btn-disabled-color: var(--ts-on-primary); }
.btn-outline-primary { --bs-btn-color: var(--ts-primary-ink); --bs-btn-border-color: var(--ts-primary); --bs-btn-hover-bg: var(--ts-primary); --bs-btn-hover-border-color: var(--ts-primary); --bs-btn-hover-color: var(--ts-on-primary); --bs-btn-active-bg: var(--ts-primary); --bs-btn-active-color: var(--ts-on-primary); }
.btn-light { --bs-btn-bg: var(--ts-card); --bs-btn-border-color: var(--ts-border); --bs-btn-color: var(--ts-text); --bs-btn-hover-bg: var(--ts-surface-2); --bs-btn-hover-border-color: var(--ts-border); --bs-btn-hover-color: var(--ts-text); --bs-btn-active-bg: var(--ts-surface-2); --bs-btn-active-color: var(--ts-text); }
.btn-link { --bs-btn-color: var(--ts-primary); --bs-btn-hover-color: var(--ts-primary-dark); }
.btn-outline-danger { --bs-btn-color: var(--ts-danger); --bs-btn-border-color: var(--ts-danger); --bs-btn-hover-bg: var(--ts-danger); --bs-btn-hover-border-color: var(--ts-danger); }
.btn-outline-dark { --bs-btn-color: var(--ts-text); --bs-btn-border-color: var(--ts-border); --bs-btn-hover-bg: var(--ts-text); --bs-btn-hover-color: var(--ts-card); }
.form-control, .form-select {
  border-radius: var(--ts-radius-sm); border-color: var(--ts-border); padding: .55rem .8rem;
  background-color: var(--ts-bg); color: var(--ts-text);
}
/* The caret is a background image over the last 28px of the box. The padding above is for a text input
   and overwrote the 2.25rem Bootstrap reserves for that image, so the last few letters of a long option
   were drawn underneath the arrow — and a select left to size itself put the arrow over them every time. */
.form-select { padding-right: 2.25rem; }
.form-control:focus, .form-select:focus { background-color: var(--ts-bg); color: var(--ts-text); border-color: var(--ts-primary); box-shadow: 0 0 0 .2rem var(--ts-focus); }
.form-control::placeholder { color: var(--ts-muted); }
.form-check-input:checked { background-color: var(--ts-primary); border-color: var(--ts-primary); }
.form-check-input:focus { border-color: var(--ts-primary); box-shadow: 0 0 0 .2rem var(--ts-focus); }
.form-label { font-weight: 600; font-size: 12.5px; }
.alert { border-radius: var(--ts-radius-sm); }
.alert-success { --bs-alert-bg: var(--ts-ok-soft); --bs-alert-color: var(--ts-ok); --bs-alert-border-color: transparent; }
.alert-danger { --bs-alert-bg: var(--ts-danger-soft); --bs-alert-color: var(--ts-danger); --bs-alert-border-color: transparent; }
.alert-warning { --bs-alert-bg: var(--ts-warn-soft); --bs-alert-color: var(--ts-warn); --bs-alert-border-color: transparent; }
.alert-info { --bs-alert-bg: var(--ts-primary-soft); --bs-alert-color: var(--ts-primary-ink); --bs-alert-border-color: transparent; }
.text-danger { color: var(--ts-danger) !important; }
.text-success { color: var(--ts-ok) !important; }

/* Hierarchy tree */
.ts-tree ul { list-style: none; padding-left: 26px; margin: 0; border-left: 1px dashed var(--ts-border); }
.ts-tree > ul { padding-left: 0; border-left: 0; }
/* The chevron and the card share a line; the team below them takes a line of its own. Without this the
   li is a block, the card is as wide as its contents and the chevron gets pushed onto its own row. */
.ts-tree li { display: flex; flex-wrap: wrap; align-items: center; margin: 6px 0; }
.ts-tree li > ul { flex: 0 0 100%; }
.ts-tree .ts-node {
  display: inline-flex; align-items: center; gap: 10px; background: var(--ts-card); border: 1px solid var(--ts-border);
  border-radius: 999px; padding: 6px 12px 6px 6px; box-shadow: 0 1px 2px rgba(15, 23, 42, .04);
}
.ts-tree .ts-node .ts-avatar { width: 30px; height: 30px; font-size: 10.5px; }
.ts-tree .ts-node small { color: var(--ts-muted); }

/* Bootstrap draws the caret as a background image and reserves padding for it, but a select left to size
   itself measures the text alone — so every name ran under the arrow, and no two boxes were the same
   width. One width, wide enough for a full name. */
.ts-node-manager { width: 350px; max-width: 100%; text-overflow: ellipsis; }
/* An address wraps as one thing or not at all; split over two lines it is no longer readable as one. */
.ts-node-email { white-space: nowrap; }
/* Bootstraps [hidden] and its display utilities are both !important and equally specific, so the one
   written later wins — and the utilities are written later. A form carrying d-inline-flex therefore
   ignored its own hidden attribute. This is after both, so hidden means hidden. */
[hidden] { display: none !important; }

.ts-tree-tools { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; color: var(--ts-muted); font-size: 12.5px; }
.ts-tree-tools .btn-link { font-size: 12.5px; text-decoration: none; color: var(--ts-muted); }
.ts-tree-tools .btn-link:hover { color: var(--ts-primary); text-decoration: underline; }

/* The chevron sits in the gutter, level with the card it opens. */
.ts-node-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; margin-right: 2px; padding: 0;
  border: 0; border-radius: 6px; background: transparent; color: var(--ts-muted);
  vertical-align: middle;
}
.ts-node-toggle:hover { background: var(--ts-neutral-soft); color: var(--ts-primary); }
.ts-node-toggle.is-empty, .ts-node-toggle.is-empty:hover { background: transparent; pointer-events: none; }
.ts-node-toggle .lucide { width: 15px; height: 15px; transition: transform .12s ease; }
.ts-node-toggle[aria-expanded="false"] .lucide { transform: rotate(-90deg); }

.ts-node-reveal { margin-left: 4px; padding: 3px 7px; line-height: 1; color: var(--ts-muted); }
.ts-node-reveal:hover { color: var(--ts-primary); }
.ts-node-reveal .lucide { width: 13px; height: 13px; }

/* Dragging. The card being carried fades, and so does everybody under it, because they come too. */
.ts-tree [data-ts-person][draggable="true"] { cursor: grab; }
.ts-tree .ts-node.is-dragging { opacity: .45; cursor: grabbing; }
.ts-tree li.is-dragging-branch > ul { opacity: .45; }
.ts-tree .ts-node.is-drop-target { border-color: var(--ts-primary); box-shadow: 0 0 0 3px var(--ts-primary-soft); }
.ts-tree .ts-node.is-moving { opacity: .6; }

.ts-tree-top {
  display: flex; align-items: center; gap: 8px; margin-bottom: 14px; padding: 10px 14px;
  border: 1px dashed var(--ts-border); border-radius: 10px;
  color: var(--ts-muted); font-size: 12.5px;
}
.ts-tree-top svg { width: 15px; height: 15px; }
.ts-tree-top.is-over { border-color: var(--ts-primary); border-style: solid; color: var(--ts-primary); background: var(--ts-primary-soft); }

/* Auth pages */
.ts-auth { min-height: 100vh; display: grid; place-items: center; align-content: center; gap: 16px; background: linear-gradient(135deg, var(--ts-banner-from), var(--ts-banner-to)); padding: 24px; }
/* The switch sits on the gradient, which is coloured in both themes, so it dresses in white either way. */
.ts-auth .ts-theme { background: rgba(255, 255, 255, .14); border-color: rgba(255, 255, 255, .3); }
.ts-auth .ts-theme button { color: rgba(255, 255, 255, .78); }
.ts-auth .ts-theme button:hover { color: #fff; }
.ts-auth .ts-theme button[aria-pressed="true"] { background: rgba(255, 255, 255, .94); color: var(--ts-primary-dark); }
.ts-auth .ts-card { width: 100%; max-width: 420px; padding: 32px; }
/* The sign-in card borrows the brand, but none of the header's column sizing goes with it. */
.ts-auth .ts-brand { flex: 0 1 auto; width: auto; align-self: auto; padding: 0 0 18px; border-right: 0; }
.ts-auth .ts-brand img { height: calc(40px + 2 * var(--ts-logo-pad)); max-width: calc(200px + 3 * var(--ts-logo-pad)); }
.ts-auth-title { font-size: 19px; font-weight: 650; letter-spacing: -.015em; line-height: 1.25; }

@media (max-width: 992px) {
  :root { --ts-topbar-h: 52px; }
  /* The nav slides out from under the header rather than over it, so the brand and the account
     menu stay reachable while it is open. */
  .ts-sidebar { position: fixed; top: var(--ts-topbar-h); z-index: 1030; transform: translateX(-100%); transition: transform .2s; }
  .ts-sidebar.open { transform: none; }
  .ts-main { padding: 16px; }
  .ts-topbar { padding-right: 12px; }
  /* No column to be as wide as: the cell shrinks to the brand, and the brand keeps its own padding. */
  .ts-brand-cell { flex: 0 0 auto; width: auto; padding-right: 0; border-right: 0; }
  .ts-brand { padding: 0 12px 0 16px; }
  .ts-brand small { display: none; }
}

/* Narrow enough that the name would push the menu off the edge: the avatar says who it is, and
   the page name is in the tab title anyway. */
@media (max-width: 576px) {
  .ts-user-who { display: none; }
  .ts-topbar-title { display: none; }
}

/* Forms and states */
.validation-summary-valid { display: none; }
.ts-seatbar { height: 8px; border-radius: 999px; background: var(--ts-border); overflow: hidden; }
.ts-seatbar > span { display: block; height: 100%; background: var(--ts-primary); border-radius: 999px; }
.ts-seatbar > span.warn { background: var(--ts-warn); }
.ts-seatbar > span.full { background: var(--ts-danger); }
/* A Vendor's use of its plan, a bar a line (Phase 7 step 2, 15 Oct 2026). */
.ts-plan-usage { display: grid; gap: 12px; }
/* Every wording of a Vendor's consent notice, newest first (Phase 7 step 3, 15 Oct 2026). */
.ts-consent-history { list-style: none; margin: 0; padding: 0; }
.ts-consent-history > li { padding: 10px 0; border-bottom: 1px solid var(--ts-border); }
.ts-consent-history > li:first-child { padding-top: 0; }
.ts-consent-history > li:last-child { border-bottom: 0; padding-bottom: 0; }
.ts-consent-history details, .ts-consent-given { margin-top: 4px; }
.ts-consent-history summary, .ts-consent-given summary { cursor: pointer; color: var(--ts-muted); }
/* Who a retention period would erase first (Phase 7 step 4). */
.ts-retention-due { border-top: 1px solid var(--ts-border); padding-top: 12px; }
.ts-retention-first { list-style: none; margin: 0; padding: 0; columns: 2 220px; column-gap: 24px; }
.ts-retention-first > li { padding: 2px 0; break-inside: avoid; }
.ts-empty { text-align: center; color: var(--ts-muted); padding: 32px 16px; }
.ts-empty .lucide { width: 36px; height: 36px; color: var(--ts-border); margin-bottom: 8px; }
.ts-tabs { display: flex; gap: 6px; flex-wrap: wrap; }
.ts-tabs a { padding: 6px 14px; border-radius: 999px; font-weight: 600; font-size: 12.5px; color: var(--ts-muted); background: transparent; }
.ts-tabs a.active { background: var(--ts-card); color: var(--ts-primary-ink); border: 1px solid var(--ts-border); }
.ts-perm-group { border: 1px solid var(--ts-border); border-radius: var(--ts-radius-sm); padding: 12px 14px; height: 100%; }
.ts-perm-group h6 { font-family: var(--ts-mono); font-size: 10.5px; font-weight: 600; text-transform: uppercase; letter-spacing: .1em; color: var(--ts-muted); margin-bottom: 8px; }
.ts-code { font-family: var(--ts-mono); font-size: 12.5px; background: var(--ts-surface-2); border-radius: 6px; padding: 2px 6px; }
/* Editing an email body is editing code, so it reads like code. */
.ts-code-area { font-family: var(--ts-mono); font-size: 12.5px; line-height: 1.6; }
.ts-json { font-family: var(--ts-mono); font-size: 12.5px; white-space: pre-wrap; word-break: break-word; max-width: 520px; color: var(--ts-muted); margin: 0; }

/* A framed area for previewing an upload against the page background. */
.ts-preview { background: var(--ts-bg); border: 1px dashed var(--ts-border); border-radius: var(--ts-radius-sm); padding: 12px; text-align: center; }
/* The banner preview is the crop itself, at the shape it will be published in, so what is shown here is
   what a stranger sees rather than an idea of it. */
.ts-preview-banner { padding: 0; overflow: hidden; }
.ts-preview-banner img { display: block; width: 100%; aspect-ratio: 4 / 1; object-fit: cover; }
.ts-banner-empty { aspect-ratio: 4 / 1; display: flex; align-items: center; justify-content: center; color: var(--ts-muted); font-size: 13px; }

/* Accent picker. Each label carries its own data-ts-accent, so the swatch paints itself
   from that accent's tokens and shows the shade the current theme would actually use.

   From the components, never from --ts-accent-light or --ts-accent-dark. Those are worked out once, on
   the root, from the root's own components, and what a label inherits is that finished colour: a label
   redefining its components changes nothing derived above it. Reading the hexes here painted all eight
   swatches the workspace's own accent from 23 Sep 2026, when the accents became components, until
   28 Sep. */
.ts-swatches { display: flex; flex-wrap: wrap; gap: 10px; }
.ts-swatch input { position: absolute; opacity: 0; width: 0; height: 0; }
.ts-swatch span {
  display: grid; place-items: center; width: 34px; height: 34px; border-radius: 50%;
  background: rgb(var(--ts-accent-light-rgb)); color: #fff; cursor: pointer;
  border: 2px solid transparent; box-shadow: 0 0 0 1px var(--ts-border);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .ts-swatch span { background: rgb(var(--ts-accent-dark-rgb)); color: #0b1220; }
}
:root[data-theme="dark"] .ts-swatch span { background: rgb(var(--ts-accent-dark-rgb)); color: #0b1220; }
.ts-swatch span .lucide { width: 15px; height: 15px; opacity: 0; }
.ts-swatch input:checked + span { border-color: var(--ts-card); box-shadow: 0 0 0 2px var(--ts-text); }
.ts-swatch input:checked + span .lucide { opacity: 1; }
.ts-swatch input:focus-visible + span { box-shadow: 0 0 0 3px var(--ts-focus); }
/* "Follow the workspace" is the absence of a colour, so the swatch has none of its own. */
.ts-swatch-follow span, :root[data-theme="dark"] .ts-swatch-follow span { background: var(--ts-surface-2); color: var(--ts-muted); border-style: dashed; border-color: var(--ts-muted); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .ts-swatch-follow span { background: var(--ts-surface-2); color: var(--ts-muted); }
}
.ts-swatch-follow input:checked + span { border-style: solid; }

/* Searchable dropdowns. The native select is still there and still posts; it is moved out of sight and
   this is drawn over it. Every colour comes from the same tokens as the rest, so both themes follow. */
.ts-combo { position: relative; }
.ts-combo-native {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: 0;
  opacity: 0; pointer-events: none; overflow: hidden;
}
.ts-combo-button {
  display: flex; align-items: center; width: 100%; text-align: left;
  cursor: pointer; white-space: nowrap; overflow: hidden;
}
.ts-combo-value { overflow: hidden; text-overflow: ellipsis; }
.ts-combo-value.is-placeholder { color: var(--ts-muted); }
.ts-combo-panel {
  position: absolute; z-index: 1060; left: 0; right: 0; top: calc(100% + 4px);
  background: var(--ts-card); border: 1px solid var(--ts-border);
  border-radius: var(--ts-radius-sm); box-shadow: 0 12px 28px rgba(15, 23, 42, .14);
  padding: 6px; min-width: 220px;
}
.ts-combo.is-above .ts-combo-panel { top: auto; bottom: calc(100% + 4px); }
.ts-combo-search { margin-bottom: 6px; }
.ts-combo-list { list-style: none; margin: 0; padding: 0; max-height: 240px; overflow-y: auto; }
.ts-combo-group {
  padding: 6px 10px 2px; font-size: 11px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ts-muted);
}
.ts-combo-option {
  padding: 7px 10px; border-radius: 6px; cursor: pointer; font-size: 13.5px; color: var(--ts-text);
}
.ts-combo-option.is-active { background: var(--ts-surface-2); }
.ts-combo-option.is-selected { background: var(--ts-primary-soft); color: var(--ts-primary-ink); font-weight: 600; }
.ts-combo-option.is-disabled { color: var(--ts-muted); cursor: not-allowed; }
.ts-combo-empty { padding: 10px; font-size: 13px; color: var(--ts-muted); }

/* An uploaded mark and the empty square standing in for one, the same size so the row does not jump
   when a file is picked. */
.ts-logo-preview, .ts-logo-empty {
  width: 64px; height: 64px; flex: none;
  border: 1px solid var(--ts-border); border-radius: 8px; background: var(--ts-bg);
}
.ts-logo-preview { object-fit: contain; padding: 4px; }
.ts-logo-empty {
  display: flex; align-items: center; justify-content: center;
  border-style: dashed; color: var(--ts-muted);
}
.ts-logo-empty i { width: 22px; height: 22px; }

/* An employer's mark in a list: round, and never cropped, because a wordmark cut to a circle is
   unreadable. The initials stand in until there is a logo to show. */
.ts-logo-chip, .ts-logo-chip-empty {
  width: 32px; height: 32px; flex: none; border-radius: 50%;
}
.ts-logo-chip {
  object-fit: contain; padding: 3px;
  background: #fff; border: 1px solid var(--ts-border);
}
.ts-logo-chip-empty { font-size: 11px; }

/* The pool's toolbar. Three columns rather than a flex row, so the job box lands in the middle of the
   page whatever is beside it: the button on the right changes width with the viewer's permissions and
   with whether a job is picked, and a centre that drifts when a button appears is not a centre. */
.ts-pool-toolbar {
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 12px;
}
.ts-pool-toolbar > .ts-pool-mid { grid-column: 2; display: flex; align-items: center; gap: 8px; }
.ts-pool-toolbar > .ts-pool-end { grid-column: 3; display: flex; justify-content: flex-end; }
/* Both, because the box somebody actually sees is ts-select.js's combo with scripting on and the
   native select without it, and a control this screen is worked from should not change width as the
   job it names gets longer or shorter. */
.ts-job-box, .ts-pool-mid .ts-combo { min-width: 300px; max-width: 420px; }

/* Below this the three columns cannot hold a 280px box and a button, so the row becomes two stacked
   ones — still centred, because that is what it is at every other width. */
@media (max-width: 767.98px) {
  .ts-pool-toolbar { grid-template-columns: 1fr; }
  .ts-pool-toolbar > .ts-pool-mid,
  .ts-pool-toolbar > .ts-pool-end { grid-column: 1; flex-wrap: wrap; justify-content: center; }
  .ts-pool-mid > form { flex: 1 1 100%; }
  .ts-job-box, .ts-pool-mid .ts-combo { min-width: 0; max-width: none; width: 100%; }
}

/* Square and wordless, beside the box they act on — the shape the legacy's own toolbar uses. In the
   Vendor's accent rather than its fixed green and purple, so a workspace that picks teal is not handed
   somebody else's palette. Sized to the form control next to them, not to their icon. */
.ts-icon-btn {
  display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
  width: 38px; height: 38px; padding: 0;
  border: 1px solid var(--ts-primary); border-radius: 10px;
  background: var(--ts-primary); color: var(--ts-on-primary);
}
.ts-icon-btn:hover, .ts-icon-btn:focus {
  background: var(--ts-primary-dark); border-color: var(--ts-primary-dark); color: var(--ts-on-primary);
}
.ts-icon-btn:focus-visible { outline: 3px solid var(--ts-focus); outline-offset: 1px; }

/* The count of filters in force, on the button that opens the drawer holding them. */
.ts-filter-count {
  display: inline-grid; place-items: center; min-width: 18px; height: 18px; padding: 0 5px;
  margin-left: 4px; border-radius: 9px; background: var(--ts-primary); color: #fff;
  font-size: 11px; font-weight: 700; line-height: 1;
}

/* On a square button there is no label to sit beside, so the count sits on the corner — and in the
   danger colour, because accent on accent would be a badge nobody can see. */
.ts-icon-btn .ts-filter-count {
  position: absolute; top: -7px; right: -7px; margin: 0;
  min-width: 20px; height: 20px; border-radius: 10px;
  background: var(--ts-danger); border: 2px solid var(--ts-bg);
}
.ts-filter-note { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 6px; font-size: 12px; }
.ts-filter-note a { font-weight: 600; }
/* Not .ts-pill: that uppercases, and a search term has to come back looking the way it was typed. */
.ts-filter-chip {
  padding: 2px 9px; border-radius: 999px; background: var(--ts-surface-2);
  border: 1px solid var(--ts-border); color: var(--ts-text); font-size: 12px;
}

/* A row you can click anywhere on. The hover is what says so before the pointer changes. */
tr.ts-row-link { cursor: pointer; }
tr.ts-row-link:hover > td { background: var(--ts-surface-2); }

/* The filter drawer wears the app's surface, not Bootstrap's, so it reads as part of the page. */
.offcanvas { background: var(--ts-card); color: var(--ts-text); border-left: 1px solid var(--ts-border); }
.offcanvas-header { border-bottom: 1px solid var(--ts-border); }

/* A second line under a cell's main value: quieter and tighter than the value it hangs off. */
.ts-row-sub { font-size: 11.5px; color: var(--ts-muted); margin-top: 2px; }

/* The Candidates list, restyled 22 Sep 2026 from a design the user drew.
   Scoped to this one table rather than to .table, because every other list in the app is a different
   shape and a global change here would restyle eleven screens nobody asked about.

   The whole move is contrast. Every cell used to be text-muted small, so a row was seven equal greys
   and the eye had nothing to run down a column on. Now each cell has one value in ink with anything
   else muted beneath it, and the header is a band rather than a line of text floating above the rows. */
.ts-pool-table thead th {
    background: var(--ts-surface-2);
    border-top: 1px solid var(--ts-border);
    padding-top: .6rem;
    padding-bottom: .6rem;
}
.ts-pool-table > :not(caption) > * > * { padding: 14px; }
.ts-pool-table tbody td { font-size: 13px; color: var(--ts-text); }

/* The scale, taken off the design itself rather than eyeballed: 13px in a cell, 13.5 for the two lines
   that carry it, 12 for a second line, 11 for the head and the pill. Every one of these is a shared
   class, so each is scoped to this table — the design covers this list, not the other eleven.

   The head keeps the house .08em. The design tracks its head at .04em, but it sets the words in
   sentence case and ours are capitals, and caps at .04em set solid. Matching the number there would
   have missed the point of it. */
.ts-pool-table thead th { font-size: 11px; font-weight: 700; }
.ts-pool-table .ts-row-sub { font-size: 12px; }
.ts-pool-table .ts-pill { font-size: 11px; font-weight: 700; letter-spacing: .02em; }
.ts-pool-table .ts-cell-owner { font-weight: 500; }

/* Hover through Bootstrap's own variable rather than a background on the row: .table paints each cell
   with an inset shadow, so a background set on the tr is covered by the cells sitting on top of it. */
.ts-pool-table { --bs-table-hover-bg: var(--ts-surface-2); --bs-table-hover-color: var(--ts-text); }

/* The name is the one thing on the row that is a link, so it is the one thing wearing the accent.

   650 rather than 600, which is the design's own number and is not the hair's breadth it looks. Segoe
   UI ships Semibold and Bold and nothing between, and CSS matches a weight above 500 by looking upward
   first — so 600 lands on Semibold and 650 lands on Bold. That one step is the weight difference
   between the two screens. */
.ts-cell-name { font-size: 13.5px; font-weight: 650; line-height: 1.35; }

/* A cell's leading value where it is words rather than a number with an icon. */
.ts-cell-strong { font-size: 13.5px; font-weight: 600; color: var(--ts-text); line-height: 1.35; }

/* Green, and only on the second figure: an expected CTC is the one number on this row that is a hope
   rather than a fact, and the colour is what says so without a label. */
.ts-cell-up { color: var(--ts-ok); }
.ts-cell-up .lucide { opacity: .85; }

/* The owner wears the same blue as the candidate's name: the two people on the row read as people and
   the rest of it as facts about them. Deliberately whatever an anchor resolves to rather than a blue of
   its own, so the pair cannot drift apart later.

   It has to be the -rgb variable, not --bs-link-color. Bootstrap 5.3 writes anchors as
   rgba(var(--bs-link-color-rgb), var(--bs-link-opacity)), and this app sets only the hex half to the
   Vendor accent — so --bs-link-color reads #b45309 on a Vendor whose links are visibly #0d6efd, and
   using it here would have made the owner the one rust word on the row. See the note in PLAN.md.

   The icon stays muted: it is a label for the name, not part of it. */
.ts-cell-owner { color: rgb(var(--bs-link-color-rgb)); }
.ts-cell-owner .lucide { color: var(--ts-muted); }

/* Picking rows to hand over. 22 Sep 2026.

   The column is narrow and the box inside it is small, so the label is the target: 14px of padding
   round a 13px box turns a fiddly tick into an ordinary click. It is also why the label is there at
   all — label is on the row-click exclusion list, so the padding does not open the record. */
.ts-tick-col { width: 1%; padding-right: 0 !important; }
.ts-tick { display: block; margin: 0; padding: 2px 6px 2px 2px; cursor: pointer; }
.ts-tick-col .form-check-input { margin: 0; cursor: pointer; }

/* A ticked row is marked, because on fifty rows the boxes are a column of specks and somebody scrolling
   back up needs to see what they picked without reading down the left edge. The accent's own tint, via
   the link colour, so it belongs to the Vendor rather than being a blue of its own — and the same
   -rgb variable for the same reason as above. */
.ts-pool-table tbody tr.ts-row-picked > td { background: rgba(var(--bs-link-color-rgb), .07); }

/* The bar over the table, shown only once something is ticked. Sticky, so that on a long page the thing
   acting on the selection stays where the selection is being made rather than scrolling off the top.

   Under the topbar, not at zero: the topbar is itself sticky at top:0 with z-index 1040, so a bar pinned
   to the viewport top parks underneath it and is invisible for the whole of the scroll — which is exactly
   the page where it is needed, since a one-screen list needs no sticky anything. */
.ts-bulk-bar {
  position: sticky; top: var(--ts-topbar-h); z-index: 3;
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-bottom: 10px; padding: 10px 12px;
  border: 1px solid var(--ts-border); border-radius: 10px;
  background: var(--ts-surface-2);
}
.ts-bulk-count { font-size: 13px; font-weight: 600; color: var(--ts-text); white-space: nowrap; }
.ts-bulk-who { width: auto; min-width: 190px; }
/* Left of Clear rather than butted against the primary button: the two are both submits and the second
   moves a great deal more than the first, so it reads as its own sentence. */
.ts-bulk-all { font-size: 13px; }
.ts-bulk-all .btn-link { font-size: 13px; vertical-align: baseline; }

/* Search in the open, beside the job it is searching inside. The button is square like the two next to
   it, and joined to the box so the pair reads as one control. */
.ts-pool-search { display: flex; align-items: center; min-width: 0; }
/* Wide enough to hold its own placeholder. At 220px "Search a name, email or mobile" was cut off after
   "mob", which is the one place a box may not economise: the placeholder is the only thing that says
   the box takes an email and a number at all. */
.ts-pool-search .form-control {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
    border-right: 0;
    width: 260px;
    min-width: 0;
}
.ts-pool-search .ts-icon-btn { border-top-left-radius: 0; border-bottom-left-radius: 0; }

/* The search box is the one thing here that can afford to shrink: the job box is what the screen is
   worked from, and the two buttons are already at their smallest. */
@media (max-width: 991.98px) {
    .ts-pool-search .form-control { width: 170px; }
}

/* Stacked, where ts-pool-mid gives every form a row of its own: the box then takes the row rather than
   sitting at 150px with empty space beside it. */
@media (max-width: 767.98px) {
    .ts-pool-search { width: 100%; }
    .ts-pool-search .form-control { width: auto; flex: 1 1 auto; }
}

/* A person on a list row. The picture needs air around it: at 8px, and worse at 5px, a 36px circle sits
   on top of the name and the two fight. 12px lets the name start cleanly and still reads as one unit,
   because the gap to the next column is wider again. */
/* A floor, because since 21 Sep 2026 this cell carries the job above the name and "Frontend Engineer
   (45)" needs more room than a name ever did. The table scrolls rather than crushing it. */
.ts-person { display: flex; align-items: center; gap: 12px; min-width: 210px; }
/* Above the name rather than under it, so the margin ts-row-sub puts on top belongs underneath. */
.ts-row-job { margin-top: 0; margin-bottom: 2px; }

/* An icon that labels the number beside it. Sized to the text rather than to the icon set's own 24px,
   and muted, because it is there to be recognised at a glance and not read. */
.ts-cell-icon { display: inline-flex; align-items: center; gap: 4px; }
.ts-cell-icon .lucide { width: 13px; height: 13px; opacity: .6; flex: 0 0 auto; }

/* A sub-line is a line of its own. Putting ts-cell-icon on one turned it inline-flex and it climbed back
   up beside the line above — so on a sub-line the flex is block-level and the stacking survives. */
.ts-row-sub.ts-cell-icon { display: flex; }

/* The code beside the title it names: quieter than the name, and mono, so a code reads as a code. */
.ts-title-code { font-family: var(--ts-mono); font-size: 11.5px; font-weight: 500; color: var(--ts-muted); }

/* An icon glued to the value it labels: the two wrap as one thing or not at all, and the icon is sized
   from the text beside it so it stays right whatever is showing it. */
.ts-fact { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.ts-fact svg { width: 1.05em; height: 1.05em; flex: 0 0 auto; color: var(--ts-muted); }

/* Experience and money on one line, the notice period under them. */
.ts-ask { font-size: 12.5px; }
.ts-ask > div { display: flex; flex-wrap: wrap; align-items: center; gap: 3px 14px; }
.ts-ask > div + div { margin-top: 3px; }

/* A heading inside a card, dividing one long form into the separate decisions it actually holds. */
.ts-section-title {
  margin: 22px 0 12px; padding-top: 14px; border-top: 1px solid var(--ts-border);
  font-size: 12px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--ts-muted);
}
.ts-card-title + .ts-section-title, .alert + .ts-section-title { margin-top: 4px; padding-top: 0; border-top: 0; }

/* A range is one decision: two boxes under one label, with the word between them carrying the meaning. */
.ts-range { display: flex; align-items: center; gap: 8px; }
.ts-range > span { flex: none; font-size: 12.5px; color: var(--ts-muted); }

/* The mark on a field the form will refuse to save without. */
.ts-req { margin-left: 2px; color: var(--ts-danger); font-weight: 700; }

/* The rich-text box: a toolbar sitting on top of an editable area that wears the form-control look. */
.ts-editor { border: 1px solid var(--ts-border); border-radius: var(--ts-radius-sm); background: var(--ts-card); overflow: hidden; }
.ts-editor-bar { display: flex; gap: 2px; padding: 6px 8px; border-bottom: 1px solid var(--ts-border); background: var(--ts-surface-2); }
.ts-editor-btn {
  display: inline-grid; place-items: center; width: 30px; height: 28px; padding: 0;
  border: 0; border-radius: 6px; background: transparent; color: var(--ts-text-2); cursor: pointer;
}
.ts-editor-btn:hover { background: var(--ts-card); color: var(--ts-text); }
.ts-editor-btn i { width: 15px; height: 15px; }
.ts-editor-box {
  /* A description is paragraphs and lists, not a sentence: it gets the room to be read back while writing. */
  min-height: 460px; max-height: 75vh; overflow-y: auto;
  border: 0; border-radius: 0; background: transparent; box-shadow: none;
}
.ts-editor-box:focus { box-shadow: none; outline: 0; }
.ts-editor:focus-within { border-color: var(--ts-primary); }
.ts-editor-box > :first-child { margin-top: 0; }
.ts-editor-box > :last-child { margin-bottom: 0; }
.ts-editor-box ul, .ts-editor-box ol { padding-left: 22px; }

/* A stored description, shown where it is read rather than edited. */
.ts-rich > :first-child { margin-top: 0; }
.ts-rich > :last-child { margin-bottom: 0; }
.ts-rich ul, .ts-rich ol { padding-left: 22px; }
.ts-rich h2, .ts-rich h3, .ts-rich h4 { font-size: 14px; font-weight: 700; margin: 16px 0 6px; }

/* A long form's sections, listed beside it. Anchors rather than steps: the rail is navigation, not a
   gate, so the whole form still saves in one go. */
.ts-form-layout { display: grid; grid-template-columns: 232px minmax(0, 1fr); gap: 20px; align-items: start; }
.ts-form-rail {
  position: sticky; top: calc(var(--ts-topbar-h) + 20px);
  display: flex; flex-direction: column; gap: 2px;
  background: var(--ts-card); border: 1px solid var(--ts-border); border-radius: var(--ts-radius); padding: 10px;
}
.ts-form-rail a {
  display: flex; align-items: center; gap: 9px;
  padding: 8px 12px; border-radius: 999px;
  color: var(--ts-text-2); font-size: 13.5px; font-weight: 500; line-height: 1.3;
}
/* Numbered, so a long form reads as a short list of steps rather than a wall to scroll. */
.ts-step-no {
  display: grid; place-items: center; flex: 0 0 22px; width: 22px; height: 22px;
  border-radius: 50%; background: var(--ts-surface-2); color: var(--ts-muted);
  font-family: var(--ts-mono); font-size: 11px; font-weight: 700;
}
.ts-form-rail a.is-active .ts-step-no { background: var(--ts-primary); color: #fff; }
.ts-form-rail a:hover { background: var(--ts-surface-2); color: var(--ts-text); }
.ts-form-rail a.is-active { background: var(--ts-primary-soft); color: var(--ts-primary-ink); font-weight: 600; }
/* A section holding a rejected field says so, so a refused save is not a hunt down the page. */
.ts-form-rail a.has-error::after {
  content: ''; margin-left: auto; width: 7px; height: 7px; border-radius: 50%; background: var(--ts-danger);
}
.ts-form-rail-actions { display: grid; gap: 8px; margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--ts-border); }
/* Clear of the sticky topbar, so a jump does not land the heading underneath it. */
.ts-form-main > .ts-card { scroll-margin-top: calc(var(--ts-topbar-h) + 16px); }

@media (max-width: 991.98px) {
  /* No room beside the form, and a phone is short enough to scroll: the list goes, the buttons stay
     and move to the end where they were before. */
  .ts-form-layout { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .ts-form-rail { position: static; order: 2; }
  .ts-form-main { order: 1; }
  .ts-form-rail a { display: none; }
  .ts-form-rail-actions { grid-auto-flow: column; justify-content: start; margin-top: 0; }
}

/* The two drafting buttons above the description, and whatever the last one had to say. */
.ts-ai-bar { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; }
.ts-ai-bar .btn { display: inline-flex; align-items: center; gap: 6px; }
.ts-ai-bar .btn i { width: 15px; height: 15px; color: var(--ts-primary); }
.ts-ai-bar.is-busy .btn i { animation: ts-pulse 1.1s ease-in-out infinite; }
.ts-ai-note { font-size: 12.5px; color: var(--ts-muted); }
.ts-ai-note.is-error { color: var(--ts-danger); }

/* Fill from CV, on the Add candidate form. A box the CV filled keeps a tint until somebody changes it: what a
   file said is not what anybody checked, and the tint is what makes a skimmed form visibly so. */
.ts-cv-fill-note { font-size: 12.5px; color: var(--ts-muted); }
.ts-cv-fill-note:empty { display: none; }
.ts-cv-fill-note.is-error { color: var(--ts-danger); }
.ts-cv-fill.is-busy .ts-cv-fill-note { animation: ts-pulse 1.1s ease-in-out infinite; }
.ts-from-cv .form-control, .ts-from-cv .form-select {
  background-color: rgba(var(--ts-primary-rgb), .07);
  border-color: rgba(var(--ts-primary-rgb), .55);
}
@keyframes ts-pulse { 50% { opacity: .35; } }
@media (prefers-reduced-motion: reduce) {
  .ts-ai-bar.is-busy .btn i, .ts-cv-fill.is-busy .ts-cv-fill-note { animation: none; }
}

/* The JD explainer: a recording of what the hiring manager said, and the words in it. */
.ts-record-status { font-size: 12.5px; color: var(--ts-muted); margin-top: 8px; min-height: 18px; }
.ts-record-status.is-warning { color: var(--ts-danger); }
.ts-record-status.is-good { color: var(--ts-ok); }
.ts-card.is-recording { box-shadow: 0 0 0 2px var(--ts-danger-soft); }
.ts-audio { display: block; width: 100%; margin: 10px 0 12px; }
/* Spoken words, so the line breaks the speaker made are the only ones there are. */
.ts-explainer-text { white-space: pre-wrap; font-size: 13.5px; line-height: 1.65; margin-top: 10px; }
/* Speaking a comment, 7 Oct 2026: the microphone sits in the box's bottom right corner, clear of its resize grip, and
   the text keeps clear of it. Recording turns it red with a stop square; writing it down shows a spinner. */
.ts-dictate { position: relative; }
.ts-dictate.has-mic > textarea { padding-right: 50px; }
.ts-dictate-mic { position: absolute; right: 14px; bottom: 6px; display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; padding: 0; border: 1px solid var(--ts-border); border-radius: 50%; background: var(--ts-card); color: var(--ts-muted); }
.ts-dictate-mic:hover:not(:disabled), .ts-dictate-mic:focus-visible { color: var(--ts-primary); border-color: var(--ts-primary); }
.ts-dictate-mic .lucide { width: 14px; height: 14px; }
.ts-dictate-mic .ts-dictate-stop, .ts-dictate-mic .ts-dictate-busy { display: none; }
.ts-dictate-mic .ts-dictate-busy { width: 13px; height: 13px; border-width: 2px; }
.ts-dictate.is-recording .ts-dictate-mic { background: var(--ts-danger); border-color: var(--ts-danger); color: #fff; }
.ts-dictate.is-recording .ts-dictate-mic .ts-dictate-idle, .ts-dictate.is-writing .ts-dictate-mic .ts-dictate-idle { display: none; }
.ts-dictate.is-recording .ts-dictate-mic .ts-dictate-stop { display: block; fill: currentColor; }
.ts-dictate.is-writing .ts-dictate-mic .ts-dictate-busy { display: inline-block; }
.ts-dictate.is-recording > textarea { box-shadow: 0 0 0 2px var(--ts-danger-soft); }
.ts-dictate-status { font-size: 12.5px; color: var(--ts-muted); margin-top: 6px; }
.ts-dictate-status:empty { display: none; }
.ts-dictate-status.is-warning { color: var(--ts-danger); }
.ts-dictate-status.is-good { color: var(--ts-ok); }

/* A CV, as the words that came out of the file. The line breaks are the candidate's own and are most of what
   gives a CV its shape, so they are kept. Bounded because a CV can be forty pages and the page below it —
   where they have been put forward — is the thing a recruiter came here to find. */
.ts-cv-text { white-space: pre-wrap; font-size: 13px; line-height: 1.6; max-height: 26rem; overflow-y: auto; margin: 0; }
/* A job working from an older CV than the person's latest, said above its words (25 Sep 2026). */
.ts-cv-note {
  display: flex; align-items: flex-start; gap: 8px; margin: -4px 0 12px; padding: 8px 12px;
  border-radius: var(--ts-radius-sm); background: var(--ts-surface-2); font-size: 12.5px; color: var(--ts-text-2);
}
.ts-cv-note .lucide { width: 15px; height: 15px; flex: none; margin-top: 2px; color: var(--ts-muted); }
/* The CV itself, as its pages (29 Sep 2026): the browser's own PDF viewer in a frame tall enough to read a page
   in, and behind it a line the pages cover when they arrive — a Word file's first opening takes seconds. */
.ts-cv-stage {
  position: relative; overflow: hidden;
  border: 1px solid var(--ts-border); border-radius: var(--ts-radius-sm); background: var(--ts-surface-2);
}
.ts-cv-frame { position: relative; z-index: 1; display: block; width: 100%; height: 78vh; min-height: 520px; border: 0; background: transparent; }
.ts-cv-wait {
  position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center;
  margin: 0; padding: 16px; text-align: center; font-size: 13px; color: var(--ts-muted);
}
.ts-cv-stage.is-loaded .ts-cv-wait { display: none; }
/* A phone that cannot show a PDF in a page: the frame goes, and the line saying so stands on its own. */
.ts-cv-stage.is-unable { border: 0; background: none; }
.ts-cv-stage.is-unable .ts-cv-note { margin: 0; }
/* A photographed CV is the picture it is. */
.ts-cv-picture { display: block; max-width: 100%; height: auto; margin: 0 auto; border: 1px solid var(--ts-border); border-radius: var(--ts-radius-sm); }
/* What the frame shows when the CV cannot be drawn in it: a page of its own, so it takes the card's colour. */
.ts-cv-refused { background: var(--ts-card); }

/* A share link, wide enough to read the whole token without scrolling it. */
.ts-share-url { font-family: var(--ts-mono); font-size: 12px; min-width: 300px; max-width: 420px; }

/* The public apply page: the one page in the product a stranger sees, so it carries none of the app chrome. */
.ts-apply-page { background: var(--ts-bg); min-height: 100vh; display: flex; flex-direction: column; }
.ts-apply-wrap { width: 100%; max-width: 1040px; margin: 0 auto; padding: 0 20px; }
.ts-apply-head { border-bottom: 1px solid var(--ts-border); background: var(--ts-card); padding: 16px 0; }
/* The gap under the header lives here, so a banner between the two sits flush against it. */
main.ts-apply-wrap { padding-top: 28px; }
.ts-apply-logo { height: calc(36px + 2 * var(--ts-logo-pad)); max-width: calc(160px + 3 * var(--ts-logo-pad)); object-fit: contain; }
.ts-apply-brand { font-weight: 650; font-size: 15px; letter-spacing: -.01em; }
.ts-apply-brand-sub { font-size: 12px; color: var(--ts-muted); }
.ts-apply-foot { padding-block: 28px; font-size: 12px; color: var(--ts-muted); }
/* The job beside its form, five parts to four as the 8 Oct design has them; one column under 920px, below. */
.ts-apply-grid { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); gap: 28px; align-items: start; }
.ts-apply-title { font-size: 24px; font-weight: 680; letter-spacing: -.02em; margin: 0 0 4px; }
.ts-apply-by { color: var(--ts-muted); margin-bottom: 20px; }
/* A card each rather than a row of labels: these are what somebody scans before reading a word of the
   description, and on a phone they are the whole of the page above the fold. */
.ts-apply-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 10px; margin: 0 0 20px; }
.ts-apply-fact { background: var(--ts-card); border: 1px solid var(--ts-border); border-radius: 12px; padding: 12px 14px; }
.ts-apply-facts dt { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--ts-muted); font-weight: 600; }
.ts-apply-facts dd { margin: 4px 0 0; font-weight: 600; font-size: 15px; }
.ts-apply-skills { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 18px; }

/* The block the title, the company and the skills sit in, so the job reads as one thing and the facts
   below it as another. */
.ts-apply-head-block { background: var(--ts-card); border: 1px solid var(--ts-border); border-radius: 14px; padding: 20px 22px; margin-bottom: 14px; }
.ts-apply-head-block .ts-apply-by { margin-bottom: 14px; }
.ts-apply-head-block .ts-apply-by:last-child { margin-bottom: 0; }

.ts-apply-h2 { font-size: 17px; font-weight: 660; letter-spacing: -.01em; margin: 0 0 12px; }
.ts-apply-jd { font-size: 14px; line-height: 1.7; color: var(--ts-text-2); }

/* The Vendor's own picture, full width above the page. Fixed aspect so the layout below it does not jump
   while it loads, and cropped rather than squashed. */
.ts-apply-banner { background: var(--ts-surface-2); border-bottom: 1px solid var(--ts-border); }
.ts-apply-banner img { display: block; width: 100%; aspect-ratio: 4 / 1; max-height: 260px; object-fit: cover; }
.ts-apply-note { max-width: 560px; margin: 40px auto; text-align: center; }
/* Off-screen rather than display:none: a machine that skips hidden inputs still finds this one. */
.ts-trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* The job page in the user's design of 8 Oct 2026 (HF_ATS_v3_Design/job-apply.html): its top bar, a banner, the job
   in cards with an icon to each fact, and the form beside it in boxes of its own. The look is the design's and the
   type is the app's, as asked: every size here is one the page or the app already had. The blue is the accent and the
   indigo the accent turned as the candidate form turns it, so each Vendor's page is in its own colour, which the
   frame has carried since the user asked for it the same day. The banner's two blurs are the accent turned as the
   design's cyan and pink are turned from its blue; the design's fixed pair turned muddy on rose and amber.
   Only under .is-job, which the apply pages alone set: the feedback and approval pages in this frame keep theirs. */
.ts-apply-page.is-job {
  --ts-apply-to: var(--ts-primary-dark);
  --ts-apply-field: color-mix(in srgb, var(--ts-surface-2) 50%, var(--ts-card));
  --ts-apply-ring: color-mix(in srgb, var(--ts-primary) 18%, transparent);
  --ts-apply-shadow: 0 1px 2px rgba(15, 23, 42, .04), 0 8px 24px -12px rgba(15, 23, 42, .12);
  /* The banner keeps the light accent in both themes, as the design keeps its banner: white words need it. */
  --ts-apply-hero-from: color-mix(in srgb, var(--ts-accent-light) 82%, #000);
  --ts-apply-hero-mid: color-mix(in srgb, var(--ts-accent-light) 72%, #000);
  --ts-apply-hero-to: var(--ts-accent-light);
  --ts-apply-blob-a: #22d3ee;
  --ts-apply-blob-b: #f472b6;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .ts-apply-page.is-job { --ts-apply-shadow: 0 1px 2px rgba(0, 0, 0, .3), 0 12px 32px -16px rgba(0, 0, 0, .6); }
}
:root[data-theme="dark"] .ts-apply-page.is-job { --ts-apply-shadow: 0 1px 2px rgba(0, 0, 0, .3), 0 12px 32px -16px rgba(0, 0, 0, .6); }
/* Where the browser can turn a colour: the gradients' second colour 14° on and a shade darker in light, 21° in dark,
   as .ts-cf has it; the banner's three are the design's #1d4ed8, #4f46e5 and #7c3aed, from the accent; and its blurs
   the design's #22d3ee (49° back, lighter, a little less vivid) and #f472b6 (90° on), from the accent too. */
@supports (color: oklch(from red l c h)) {
  .ts-apply-page.is-job {
    --ts-apply-to: oklch(from var(--ts-primary) calc(l - .035) c calc(h + 14));
    --ts-apply-hero-from: oklch(from var(--ts-accent-light) calc(l - .06) c h);
    --ts-apply-hero-mid: oklch(from var(--ts-accent-light) calc(l - .04) c calc(h + 13));
    --ts-apply-hero-to: oklch(from var(--ts-accent-light) l c calc(h + 29));
    --ts-apply-blob-a: oklch(from var(--ts-accent-light) .8 calc(c * .6) calc(h - 49));
    --ts-apply-blob-b: oklch(from var(--ts-accent-light) .72 calc(c * .7) calc(h + 90));
  }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .ts-apply-page.is-job { --ts-apply-to: oklch(from var(--ts-primary) l c calc(h + 21)); }
  }
  :root[data-theme="dark"] .ts-apply-page.is-job { --ts-apply-to: oklch(from var(--ts-primary) l c calc(h + 21)); }
}
@media (prefers-reduced-motion: no-preference) {
  html:has(.ts-apply-page.is-job) { scroll-behavior: smooth; }
}

/* The frame: wider, and the top bar stays at the top. */
.is-job .ts-apply-wrap { max-width: 1120px; }
.is-job .ts-apply-head { position: sticky; top: 0; z-index: 10; padding: 14px 0; }
.ts-apply-mark {
  flex: none; width: 36px; height: 36px; border-radius: 10px; display: grid; place-items: center;
  font-size: 15px; font-weight: 700; color: var(--ts-on-primary);
  /* The fallback for the pages outside .is-job that show the letters too: the video interview's (21 Oct 2026). */
  background: linear-gradient(135deg, var(--ts-primary), var(--ts-apply-to, var(--ts-primary-dark))); box-shadow: 0 6px 16px -6px var(--ts-primary);
}
.ts-apply-live {
  margin-left: auto; flex: none; display: inline-flex; align-items: center; gap: 6px; padding: 6px 10px; border-radius: 999px;
  font-size: 12px; font-weight: 600; color: var(--ts-ok); background: color-mix(in srgb, var(--ts-ok) 10%, transparent);
}
.ts-apply-dot { flex: none; width: 7px; height: 7px; border-radius: 50%; background: currentColor; box-shadow: 0 0 0 3px color-mix(in srgb, currentColor 22%, transparent); }
.is-job .ts-apply-main { background: radial-gradient(1200px 300px at 20% -50%, var(--ts-primary-soft), transparent); }
.is-job main.ts-apply-wrap { padding-top: 32px; padding-bottom: 48px; }
.is-job .ts-apply-foot { text-align: center; padding: 8px 20px 40px; }

/* The banner. The dots fade in from the left and the two blurs are light behind the words, not pictures. */
.ts-apply-hero {
  position: relative; overflow: hidden; color: #fff;
  background: linear-gradient(120deg, var(--ts-apply-hero-from) 0%, var(--ts-apply-hero-mid) 45%, var(--ts-apply-hero-to) 100%);
}
.ts-apply-hero::before {
  content: ""; position: absolute; inset: 0; opacity: .18; pointer-events: none;
  background-image: radial-gradient(rgba(255, 255, 255, .9) 1px, transparent 1.2px); background-size: 22px 22px;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 40%, #000); mask-image: linear-gradient(90deg, transparent, #000 40%, #000);
}
.ts-apply-blob { position: absolute; border-radius: 50%; filter: blur(40px); opacity: .55; pointer-events: none; }
.ts-apply-blob.is-a { width: 320px; height: 320px; background: var(--ts-apply-blob-a); right: -60px; top: -140px; }
.ts-apply-blob.is-b { width: 260px; height: 260px; background: var(--ts-apply-blob-b); right: 22%; bottom: -170px; opacity: .4; }
.ts-apply-hero-inner { position: relative; display: flex; align-items: center; gap: 32px; padding-top: 44px; padding-bottom: 48px; }
.ts-apply-hero-copy { flex: 1; min-width: 0; }
.ts-apply-badge {
  display: inline-flex; align-items: center; gap: 8px; max-width: 100%; padding: 6px 12px; border-radius: 999px;
  font-size: 12.5px; font-weight: 600; background: rgba(255, 255, 255, .14); border: 1px solid rgba(255, 255, 255, .25);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.ts-apply-badge .ts-apply-dot { color: #4ade80; }
.ts-apply-hero-title { font-size: 24px; font-weight: 680; letter-spacing: -.02em; line-height: 1.15; margin: 14px 0 10px; }
.ts-apply-hero-sub { max-width: 560px; margin: 0; color: rgba(255, 255, 255, .85); }
.ts-apply-hero-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 22px; }
.ts-apply-hero-actions .btn { height: 44px; padding: 0 18px; display: inline-flex; align-items: center; gap: 8px; }
.ts-apply-hero-actions .btn svg { width: 16px; height: 16px; }
.ts-apply-go {
  --bs-btn-bg: #fff; --bs-btn-border-color: #fff; --bs-btn-color: color-mix(in srgb, var(--ts-accent-light) 55%, #000);
  --bs-btn-hover-bg: #fff; --bs-btn-hover-border-color: #fff; --bs-btn-hover-color: color-mix(in srgb, var(--ts-accent-light) 55%, #000);
  --bs-btn-active-bg: #fff; --bs-btn-active-border-color: #fff; --bs-btn-active-color: color-mix(in srgb, var(--ts-accent-light) 55%, #000);
  box-shadow: 0 10px 24px -10px rgba(0, 0, 0, .4); transition: transform .15s;
}
.ts-apply-go:hover { transform: translateY(-1px); }
.ts-apply-share {
  --bs-btn-bg: rgba(255, 255, 255, .12); --bs-btn-border-color: rgba(255, 255, 255, .3); --bs-btn-color: #fff;
  --bs-btn-hover-bg: rgba(255, 255, 255, .2); --bs-btn-hover-border-color: rgba(255, 255, 255, .3); --bs-btn-hover-color: #fff;
  --bs-btn-active-bg: rgba(255, 255, 255, .24); --bs-btn-active-border-color: rgba(255, 255, 255, .3); --bs-btn-active-color: #fff;
}
.ts-apply-go:focus-visible, .ts-apply-share:focus-visible { outline: 2px solid #fff; outline-offset: 2px; box-shadow: none; }
/* The label under the figure on screen, and before it for a screen reader, which is the order a list says them in. */
.ts-apply-stats { flex: none; display: grid; grid-auto-flow: column; gap: 14px; margin: 0; }
.ts-apply-stat {
  display: flex; flex-direction: column-reverse; justify-content: center; min-width: 110px; padding: 16px 18px; border-radius: 14px;
  text-align: center; background: rgba(255, 255, 255, .12); border: 1px solid rgba(255, 255, 255, .22);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
.ts-apply-stat dd { margin: 0; font-size: 17px; font-weight: 700; white-space: nowrap; }
.ts-apply-stat dt { font-size: 12px; font-weight: 400; color: rgba(255, 255, 255, .8); }

/* The job's cards. */
.ts-apply-card { background: var(--ts-card); border: 1px solid var(--ts-border); border-radius: 16px; box-shadow: var(--ts-apply-shadow); }
.ts-apply-jobcard { position: relative; overflow: hidden; padding: 28px; }
.ts-apply-jobcard::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 4px; background: linear-gradient(90deg, var(--ts-primary), var(--ts-apply-to)); }
.ts-apply-eyebrow { font-size: 12px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--ts-primary); }
.ts-apply-jobcard .ts-apply-title { margin: 6px 0 4px; }
.ts-apply-company { margin: 0; color: var(--ts-muted); font-weight: 500; }
.ts-apply-skills .ts-pill { border-radius: 8px; padding: 5px 10px; border: 1px solid color-mix(in srgb, currentColor 18%, transparent); }
.ts-apply-about { padding: 28px; margin-top: 16px; }

/* The facts with an icon each, drawn by the stylesheet so the list stays a list of a label and its value. */
.ts-apply-facts.has-icons { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin: 16px 0 0; }
.has-icons .ts-apply-fact { position: relative; min-height: 68px; padding: 16px 16px 16px 64px; border-radius: 16px; box-shadow: var(--ts-apply-shadow); }
.has-icons .ts-apply-fact::before { content: ""; position: absolute; left: 16px; top: 16px; width: 36px; height: 36px; border-radius: 10px; background: var(--ts-primary-soft); }
.has-icons .ts-apply-fact::after {
  content: ""; position: absolute; left: 25px; top: 25px; width: 18px; height: 18px; background: var(--ts-primary);
  -webkit-mask: var(--ts-apply-icon) center / contain no-repeat; mask: var(--ts-apply-icon) center / contain no-repeat;
}
.has-icons .ts-apply-fact dd { margin-top: 2px; overflow-wrap: break-word; }
/* The cities are a list, and one of them alone can be longer than a third of the row holds: Visakhapatnam broke
   in two there. Two columns for them, which fills the second row too when all five facts are there. */
.has-icons .ts-apply-fact[data-icon="map-pin"] { grid-column: span 2; }
.ts-apply-fact[data-icon="map-pin"] { --ts-apply-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 10c0 6-8 12-8 12S4 16 4 10a8 8 0 1 1 16 0Z'/%3E%3Ccircle cx='12' cy='10' r='3'/%3E%3C/svg%3E"); }
.ts-apply-fact[data-icon="briefcase"] { --ts-apply-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2' y='7' width='20' height='14' rx='2'/%3E%3Cpath d='M16 7V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v2'/%3E%3C/svg%3E"); }
.ts-apply-fact[data-icon="indian-rupee"] { --ts-apply-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 3h12M6 8h12M6 13l8.5 8M6 13h3a5 5 0 0 0 0-10'/%3E%3C/svg%3E"); }
.ts-apply-fact[data-icon="dollar-sign"] { --ts-apply-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6'/%3E%3C/svg%3E"); }
.ts-apply-fact[data-icon="pound-sterling"] { --ts-apply-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 7c0-5.333-8-5.333-8 0M10 7v14M6 21h12M6 13h10'/%3E%3C/svg%3E"); }
.ts-apply-fact[data-icon="euro"] { --ts-apply-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 10h12M4 14h9M19 6a7.7 7.7 0 0 0-5.2-2A7.9 7.9 0 0 0 6 12c0 4.4 3.5 8 7.8 8 2 0 3.8-.8 5.2-2'/%3E%3C/svg%3E"); }
.ts-apply-fact[data-icon="banknote"] { --ts-apply-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2' y='6' width='20' height='12' rx='2'/%3E%3Ccircle cx='12' cy='12' r='2'/%3E%3Cpath d='M6 12h.01M18 12h.01'/%3E%3C/svg%3E"); }
.ts-apply-fact[data-icon="clock"] { --ts-apply-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7v5l3 2'/%3E%3C/svg%3E"); }
.ts-apply-fact[data-icon="file-text"] { --ts-apply-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z'/%3E%3Cpath d='M14 2v6h6M9 13h6M9 17h6'/%3E%3C/svg%3E"); }

/* The form, below the top bar wherever the banner's Apply now lands it. It stays in view beside the job only where
   the window is tall enough to show all of it: a form that sticks taller than the window keeps Send out of reach
   until the job beside it ends. At 1280 it measured 961px, and 1,047px refused with its messages, below the 84px it
   stands under. The body's 100% height would stop the top bar sticking after one screen. */
.ts-apply-page.is-job { height: auto; }
.ts-apply-form { scroll-margin-top: 84px; }
.ts-apply-form .ts-apply-card { padding: 28px; }
@media (min-width: 921px) and (min-height: 1160px) {
  .ts-apply-form { position: sticky; top: 84px; }
}
.ts-apply-form .ts-card-title { margin-bottom: 4px; }
.ts-apply-lead { margin: 0 0 22px; font-size: 13px; color: var(--ts-muted); }
.ts-apply-req { color: var(--ts-danger); margin-left: 2px; }
.ts-apply-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.ts-apply-fields .is-full { grid-column: 1 / -1; }
.ts-apply-fields .form-label { margin-bottom: 6px; color: var(--ts-text-2); }
.ts-apply-fields .form-control {
  height: 44px; padding: 0 14px; border-radius: 10px; background: var(--ts-apply-field); border-color: var(--ts-border);
  transition: border-color .15s, background-color .15s, box-shadow .15s;
}
.ts-apply-fields .form-control:hover { border-color: color-mix(in srgb, var(--ts-primary) 35%, var(--ts-border)); }
.ts-apply-fields .form-control:focus { background: var(--ts-card); border-color: var(--ts-primary); box-shadow: 0 0 0 4px var(--ts-apply-ring); }
.ts-apply-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
/* Across the row, the years under the left column and the months under the right. */
.ts-apply-fields .is-full > .ts-apply-pair { gap: 16px; }
.ts-apply-affix { position: relative; }
.ts-apply-affix .form-control { padding-right: 52px; }
.ts-apply-affix > span { position: absolute; right: 12px; top: 50%; transform: translateY(-50%); font-size: 12.5px; color: var(--ts-muted); pointer-events: none; }
/* The CV: the box is the control, and the ring shows for the keyboard only. */
.ts-apply-drop {
  position: relative; display: flex; align-items: center; gap: 14px; margin: 0; padding: 16px; cursor: pointer;
  border: 1.5px dashed color-mix(in srgb, var(--ts-primary) 35%, var(--ts-border)); border-radius: 12px;
  background: var(--ts-apply-field); transition: border-color .15s, background-color .15s, box-shadow .15s;
}
.ts-apply-drop:hover, .ts-apply-drop.is-over { border-color: var(--ts-primary); background: var(--ts-primary-soft); }
.ts-apply-drop:has(:focus-visible) { border-color: var(--ts-primary); box-shadow: 0 0 0 4px var(--ts-apply-ring); }
.ts-apply-drop-file { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.ts-apply-drop-ico { flex: none; width: 42px; height: 42px; border-radius: 10px; display: grid; place-items: center; background: var(--ts-primary-soft); color: var(--ts-primary); }
.ts-apply-drop-ico svg { width: 18px; height: 18px; }
.ts-apply-drop-text { min-width: 0; }
.ts-apply-drop-text b { display: block; font-weight: 600; color: var(--ts-text); overflow-wrap: anywhere; }
.ts-apply-drop.has-file .ts-apply-drop-text b { color: var(--ts-primary); }
.ts-apply-drop.is-refused .ts-apply-drop-text b { color: var(--ts-danger); }
.ts-apply-drop-text em { font-style: normal; font-size: 12px; color: var(--ts-muted); }
.ts-apply-consent { display: flex; align-items: flex-start; gap: 10px; margin-top: 4px; }
.ts-apply-consent .form-check-input { flex: none; width: 17px; height: 17px; margin: 3px 0 0; }
.ts-apply-consent .form-check-label { color: var(--ts-muted); line-height: 1.55; }
/* Send, in the gradient, in the app's own pill. */
.ts-apply-send { width: 100%; height: 50px; margin-top: 20px; display: flex; align-items: center; justify-content: center; gap: 8px; }
.ts-apply-send svg { width: 18px; height: 18px; }
.ts-apply-send.btn-primary, .ts-apply-send.btn-primary:hover, .ts-apply-send.btn-primary:active,
.ts-apply-send.btn-primary:focus-visible, .ts-apply-send.btn-primary:disabled {
  border: 0; color: var(--ts-on-primary);
  background: linear-gradient(135deg, var(--ts-primary), var(--ts-apply-to));
  box-shadow: 0 10px 24px -10px var(--ts-primary);
}
.ts-apply-send.btn-primary { transition: transform .12s, box-shadow .12s, opacity .12s; }
.ts-apply-send.btn-primary:hover { transform: translateY(-1px); box-shadow: 0 14px 28px -10px var(--ts-primary); }
.ts-apply-send.btn-primary:focus-visible { box-shadow: 0 0 0 4px var(--ts-apply-ring), 0 10px 24px -10px var(--ts-primary); }
.ts-apply-send.btn-primary:disabled { opacity: .5; transform: none; box-shadow: none; }
.ts-apply-secure { display: flex; align-items: center; justify-content: center; gap: 6px; margin: 12px 0 0; font-size: 12px; color: var(--ts-muted); }
.ts-apply-secure svg { width: 13px; height: 13px; flex: none; }
@media (prefers-reduced-motion: reduce) {
  .ts-apply-go:hover, .ts-apply-send.btn-primary:hover { transform: none; }
}

@media (max-width: 920px) {
  .ts-apply-stats { display: none; }
  .ts-apply-grid { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 560px) {
  .ts-apply-live { display: none; }
  .ts-apply-hero-inner { padding: 30px 16px 34px; }
  .is-job main.ts-apply-wrap { padding: 20px 16px 32px; }
  .ts-apply-jobcard, .ts-apply-about, .ts-apply-form .ts-apply-card { padding: 20px; }
  .ts-apply-facts.has-icons { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ts-apply-fields { grid-template-columns: minmax(0, 1fr); }
}

/* The careers page (Phase 7, 15 Oct 2026): the job page's frame, its banner, then a search and the jobs as cards, one
   column, each opening the job's page. Its way back from a job sits over the job's first card. */
.ts-careers-search { display: flex; gap: 10px; margin: 0 0 10px; }
.ts-careers-search .form-control { flex: 1 1 auto; min-width: 0; height: 44px; }
.ts-careers-search .form-select { flex: 0 1 220px; min-width: 0; height: 44px; }
.ts-careers-search .btn { flex: none; height: 44px; padding: 0 20px; }
.ts-careers-count { margin: 0 0 16px; font-size: 13px; color: var(--ts-muted); }
.ts-careers-count a { margin-left: 6px; }
.ts-careers-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 14px; }
.ts-careers-job { position: relative; padding: 22px 24px; }
.ts-careers-job-head { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.ts-careers-job-title { margin: 0; font-size: 18px; font-weight: 650; letter-spacing: -.01em; }
.ts-careers-job-title a { color: var(--ts-text); text-decoration: none; }
.ts-careers-job-title a:hover { color: var(--ts-primary); }
.ts-careers-facts { display: flex; flex-wrap: wrap; gap: 6px 22px; margin: 10px 0 0; }
.ts-careers-facts dt { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--ts-muted); font-weight: 600; }
.ts-careers-facts dd { margin: 2px 0 0; font-weight: 600; font-size: 14px; }
.ts-careers-skills { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
.ts-careers-open { display: inline-flex; align-items: center; gap: 6px; margin-top: 16px; font-weight: 600; font-size: 14px; color: var(--ts-primary); text-decoration: none; }
.ts-careers-open svg { width: 15px; height: 15px; }
.ts-careers-open:hover { text-decoration: underline; }
.ts-careers-pages { display: flex; align-items: center; justify-content: center; gap: 14px; margin-top: 22px; font-size: 13px; color: var(--ts-muted); }
.ts-careers-back { display: inline-flex; align-items: center; gap: 6px; margin: 0 0 12px; font-size: 13px; font-weight: 600; color: var(--ts-muted); text-decoration: none; }
.ts-careers-back svg { width: 14px; height: 14px; }
.ts-careers-back:hover { color: var(--ts-primary); }
@media (max-width: 560px) {
  .ts-careers-search { flex-wrap: wrap; }
  .ts-careers-search .form-control { flex-basis: 100%; }
  .ts-careers-search .form-select { flex: 1 1 0; }
  .ts-careers-job { padding: 18px; }
}

/* The page a feedback link opens, 28 Sep 2026: one column, since the form is the page, in the apply page's frame.
   Mostly opened on a phone from an email, so every score is a button a thumb can hit, and a row of eleven wraps
   on a narrow screen rather than shrinking below that. */
.ts-feedback { max-width: 720px; margin: 0 auto; }
.ts-feedback-hint { font-size: 13px; color: var(--ts-muted); }
.ts-feedback-question { margin: 0 0 18px; }
.ts-feedback-question legend { font-size: 14.5px; font-weight: 620; margin-bottom: 8px; }
.ts-scale, .ts-verdicts { display: flex; flex-wrap: wrap; gap: 6px; }
.ts-scale .btn { min-width: 40px; padding-inline: 0; }
.ts-verdicts .btn { min-width: 110px; }
/* Ask for a revision, 8 Oct 2026: the violet its pill has, rather than Bootstrap's cyan for info. */
.ts-verdicts .btn-outline-info { --bs-btn-color: var(--ts-info); --bs-btn-border-color: var(--ts-info); --bs-btn-hover-bg: var(--ts-info); --bs-btn-hover-border-color: var(--ts-info); --bs-btn-hover-color: #fff; --bs-btn-active-bg: var(--ts-info); --bs-btn-active-border-color: var(--ts-info); --bs-btn-active-color: #fff; }
.ts-feedback-answer { width: 100%; }
.ts-feedback-answer th { font-weight: 500; color: var(--ts-muted); padding: 6px 16px 6px 0; vertical-align: top; width: 40%; }
.ts-feedback-answer td { padding: 6px 0; }
.ts-feedback-remarks { white-space: pre-wrap; }

/* The page an approval link opens, 7 Oct 2026, as the user drew it: as wide as the frame, so its cards line up under
   the Vendor's name, with the offer in two columns and the answer on one line. On a phone it is one column again,
   labels at 40% as the feedback page has them. The labels are a fixed width where there are two columns, so the
   second column's and the note's start where the first's do. A value starts on its label's first line, as drawn, and
   each column keeps its own height: stretched to the other's, a table spreads its rows apart. */
.ts-approval-offer { display: grid; grid-template-columns: minmax(0, 1fr); column-gap: 40px; align-items: start; }
.ts-approval-offer td { vertical-align: top; }
.ts-approval-answer { display: grid; grid-template-columns: minmax(0, 1fr); gap: 6px 24px; margin: 0; }
.ts-approval-answer > div { display: grid; grid-template-columns: 40% minmax(0, 1fr); align-items: baseline; }
.ts-approval-answer dt { font-weight: 500; color: var(--ts-muted); padding-right: 16px; }
.ts-approval-answer dd { margin: 0; overflow-wrap: anywhere; }
@media (min-width: 860px) {
    .ts-approval-offer { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .ts-approval .ts-feedback-answer th { width: 168px; }
    .ts-approval-notes { grid-column: 1 / -1; }
    .ts-approval-answer { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .ts-approval-answer > div { grid-template-columns: 80px minmax(0, 1fr); }
    .ts-approval-answer > .ts-approval-long { grid-column: 1 / -1; }
}

/* An extension key: shown once, so it has to be readable and selectable in one go. */
.ts-key-fresh { border-color: var(--ts-primary); }
.ts-key-value { font-family: var(--ts-mono); font-size: 12.5px; }
.ts-key-hint { font-family: var(--ts-mono); font-size: 11.5px; }

/* A form that filled itself in from a job board says so, and says what it did not fill in. */
.ts-capture-note { border-color: var(--ts-primary); }
.ts-capture-note i { width: 14px; height: 14px; vertical-align: -2px; }

/* The candidate's page, laid out 23 Sep 2026 from a design the user drew.
   ─────────────────────────────────────────────────────────────────────────────
   Three pieces: a profile card that carries the identity and the one submission being worked, a split
   with the record on one side and the feed on the other, and the career below both. The mockup's own
   --accent: #2f6fed is deliberately not here — there are eight Vendor accents, and a page that hard-codes
   one is a page that belongs to a different product on seven of them. */
.ts-profile { padding-bottom: 0; }
.ts-profile-top { display: flex; align-items: flex-start; gap: 16px; flex-wrap: wrap; }
.ts-profile-id { flex: 1 1 22rem; min-width: 0; }
.ts-profile-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-left: auto; }

/* The number and the address as things to act on. Bigger than the muted line above them on purpose:
   ringing somebody is what this page is opened to do. */
.ts-contact-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 18px; margin-top: 8px; font-size: 13px; }
.ts-contact-row a, .ts-contact-row span { display: inline-flex; align-items: center; gap: 6px; }
.ts-contact-row .lucide { width: 14px; height: 14px; color: var(--ts-muted); }

/* The submission the page is being read about, and the controls that act on it. A tinted band rather than
   a card, so it reads as part of the heading: five sixths of submissions never move, so everything in here
   has to cost nothing to walk past. */
.ts-about {
  margin-top: 14px; padding: 10px 14px; border-radius: var(--ts-radius-sm);
  background: var(--ts-surface-2); border: 1px solid var(--ts-border);
}
.ts-about-line { display: flex; align-items: flex-start; gap: 8px; font-size: 13px; }
.ts-about-line .lucide { width: 15px; height: 15px; color: var(--ts-muted); flex: none; margin-top: 3px; }

/* The numbers a recruiter says out loud, as figures. Boxes that were four rows of a definition list; the
   list is gone. As wide as their figures, the way the legacy's sit, rather than stretched across the card. */
.ts-stat-row { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 16px; }
.ts-stat { background: var(--ts-surface-2); border-radius: var(--ts-radius-sm); padding: 10px 14px; }
.ts-stat-figure { font-size: 19px; font-weight: 650; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.ts-stat-label { color: var(--ts-muted); font-family: var(--ts-mono); font-size: 10px; font-weight: 600; letter-spacing: .07em; text-transform: uppercase; margin-top: 2px; }

/* The tabs sit on the card's bottom edge and the card has no padding left under them. */
.ts-profile-tabs { margin: 16px -20px 0; padding: 0 20px; border-top: 1px solid var(--ts-border); }
.ts-profile-tabs a { border-radius: 0; border-bottom: 2px solid transparent; padding: 10px 12px; }
.ts-profile-tabs a.active { background: transparent; border: 0; border-bottom: 2px solid var(--ts-primary); color: var(--ts-primary-ink); }

/* The record on one side, the story on the other. The feed used to be at the foot of the page, below
   everything, on the one question a recruiter opens a candidate to answer.

   40:60 at every width, the user's call on 25 Sep 2026. Until then the record was a fixed 400px and the
   feed took the rest, which made the split whatever the screen made it: 42:58 on a laptop, 25:75 on a
   wide monitor. */
.ts-split { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); gap: 16px; align-items: start; }
.ts-split-side { min-width: 0; }
.ts-split-main { min-width: 0; position: sticky; top: calc(var(--ts-topbar-h) + 16px); }

/* Its own scroll, so the facts beside it stay where they were put. The height is the viewport's, less the
   topbar and a margin, so the column ends where the window does rather than at a number picked by hand. */
.ts-activity { display: flex; flex-direction: column; max-height: calc(100vh - var(--ts-topbar-h) - 32px); }
.ts-feed { overflow-y: auto; min-height: 0; margin: 0 -20px -18px; padding: 0 20px; }
.ts-feed::-webkit-scrollbar { width: 6px; }
.ts-feed::-webkit-scrollbar-thumb { background: var(--ts-border); border-radius: 3px; }

/* A timeline, from the user's screenshot of the legacy's, 25 Sep 2026: a dotted line down the left through a
   dotted circle per entry, and the icon inside in its own colour. The line runs from the first circle's
   middle to the last one's, so it never hangs off either end; the circle sits over it on the card's colour. */
.ts-feed-item { position: relative; display: flex; gap: 12px; padding: 10px 0; }
.ts-feed-item::before {
  content: ""; position: absolute; left: 16px; top: 0; bottom: 0;
  border-left: 1px dashed var(--ts-dash);
}
.ts-feed-item:first-child::before { top: 27px; }
.ts-feed-item:last-child::before { bottom: auto; height: 27px; }
.ts-feed-item:first-child:last-child::before { display: none; }
.ts-feed-glyph {
  position: relative; z-index: 1; width: 34px; height: 34px; border-radius: 50%; flex: none;
  display: inline-grid; place-items: center;
  background: var(--ts-card); border: 1px dashed var(--ts-dash); color: var(--ts-dash-ink);
}
.ts-feed-glyph .lucide { width: 16px; height: 16px; }
.ts-feed-glyph.green { color: var(--ts-ok); }
.ts-feed-glyph.orange { color: var(--ts-warn); }
.ts-feed-glyph.red { color: var(--ts-danger); }
.ts-feed-glyph.blue { color: var(--ts-primary); }
.ts-feed-glyph.violet { color: var(--ts-info); }
.ts-feed-body { padding-top: 7px; }

.ts-feed-body { flex: 1; min-width: 0; }
.ts-feed-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.ts-feed-subject { font-size: 13.5px; font-weight: 650; }
.ts-feed-note { font-size: 12.5px; color: var(--ts-text-2); line-height: 1.55; margin-top: 4px; white-space: pre-wrap; }
/* Clamped until the button says otherwise. The button is added by script and only where something is
   actually hidden — see data-ts-clamp. */
.ts-feed-note.ts-clamped { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.ts-clamp-more { font-size: 12px; font-weight: 600; padding: 2px 0 0; }
.ts-feed-foot {
  margin-top: 6px; font-size: 11.5px; color: var(--ts-muted);
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
}
.ts-dot { width: 3px; height: 3px; border-radius: 50%; background: currentColor; opacity: .6; }

/* Put forward for, as a list. The row the header is about is marked, because a reader who scrolled has to
   be able to tell where the rung at the top came from. */
.ts-list li.ts-entry-shown { background: var(--ts-surface-2); border-radius: var(--ts-radius-sm); padding-left: 10px; padding-right: 10px; }
.ts-entry-links { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; flex-shrink: 0; font-size: 12px; }
/* The list's own rows are top-aligned here: an entry can carry a duplicate flag and a form under it. */
#entries .ts-list li { align-items: flex-start; }

@media (max-width: 1199.98px) {
    /* One column, and the feed gives up both its scroll and its sticky: a scrolling panel inside a
       scrolling page is a trap on a touch screen, and there is nothing beside it to stay level with. */
    .ts-split { grid-template-columns: 1fr; }
    .ts-split-main { position: static; }
    .ts-activity { max-height: none; }
    .ts-feed { overflow-y: visible; }
}

@media (max-width: 575.98px) {
    /* Two to a row on a phone, sharing it evenly rather than each as wide as its figure. */
    .ts-stat { flex: 1 1 40%; }
    .ts-profile-actions { margin-left: 0; }
    .ts-ai-match { width: 100%; margin-left: 0; }
}

/* The candidate page, corrected against the shipped screen on 24 Sep 2026.
   ─────────────────────────────────────────────────────────────────────────────
   The working context moved into the app's own bar, where CandidateCommunication/Index keeps it, and the
   page below stopped repeating it. What is left here is the design's own measurements: its panel heads,
   its 140px fact grid and its bordered stat boxes. */
.ts-topbar-context { display: flex; align-items: center; gap: 10px; min-width: 0; overflow: hidden; }
.ts-topbar-req { font-size: 13px; color: var(--ts-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ts-topbar-req a { font-weight: 600; }
.ts-assigned-chip {
  font-size: 12.5px; color: var(--ts-muted); background: var(--ts-card);
  border: 1px solid var(--ts-border); padding: 3px 10px; border-radius: 999px; white-space: nowrap;
}
.ts-assigned-chip b { color: var(--ts-text); font-weight: 600; }
/* Below lg the bar is brand, burger and title; three more things in it would push the title out. */
@media (max-width: 991.98px) { .ts-topbar-context { display: none; } }

/* The name in the card, under the one in the bar. The design has both and so does the screen it came
   from — the bar's is the record you are on, this one is the head of the card. */
.ts-profile-name { font-size: 20px; font-weight: 650; letter-spacing: -.01em; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* A duplicate flag belongs to one submission, and this page is one submission's. */
.ts-about-flag { font-size: 13px; }
.ts-about-flag .lucide { width: 14px; height: 14px; vertical-align: -2px; }

/* The action bar, agreed 24 Sep 2026: one coloured icon to a box, 44 by 40 with a 1px border, the legacy's
   own measurements in custom.css. The boxes stand apart since 25 Sep, at the user's word — they were joined
   into one strip. The colours are that file's palette — light-green-c for Comment, which is the legacy's own —
   and the three the legacy kept uncoloured in its "more" menu take colours the palette had spare. Lifted a
   step in dark mode, where the legacy never went.

   The dotted lines are the legacy's too, from its figures and its timeline: a border a shade darker than
   the app's own, so the dashes show at all, and the grey of an icon that carries no colour of its own. */
:root {
  --ts-act-whatsapp: #25d366;
  --ts-act-comment: #88c440;
  --ts-act-stage: #9c1ab1;
  --ts-act-assign: #1093f5;
  --ts-act-add: #ff9800;
  --ts-act-email: #3d4db7;
  --ts-act-lost: #f6402c;
  --ts-act-interview: #eb1460;
  --ts-act-offer: #009688;
  --ts-act-summary: #00838f;
  --ts-act-video: #6a3de8;
  --ts-dash: #cbd5e1;
  --ts-dash-ink: #94a3b8;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ts-act-comment: #a3d964; --ts-act-stage: #d17ee0; --ts-act-assign: #5cb6ff; --ts-act-add: #ffb74d;
    --ts-act-email: #8c9eff;
    --ts-act-lost: #ff7b6b;
    --ts-act-interview: #ff6f9e;
    --ts-act-offer: #4db6ac;
    --ts-act-summary: #4dd0e1;
    --ts-act-video: #b39dfb;
    --ts-dash: #3a4863; --ts-dash-ink: #8b97ad;
  }
}
:root[data-theme="dark"] {
  --ts-act-comment: #a3d964; --ts-act-stage: #d17ee0; --ts-act-assign: #5cb6ff; --ts-act-add: #ffb74d;
  --ts-act-email: #8c9eff;
  --ts-act-lost: #ff7b6b;
  --ts-act-interview: #ff6f9e;
  --ts-act-offer: #4db6ac;
  --ts-act-summary: #4dd0e1;
  --ts-act-video: #b39dfb;
  --ts-dash: #3a4863; --ts-dash-ink: #8b97ad;
}

.ts-actbar { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; }
.ts-act {
  width: 44px; height: 40px; padding: 0;
  display: inline-grid; place-items: center;
  border: 1px solid var(--ts-border); border-radius: var(--ts-radius-sm);
  background: var(--ts-card); color: var(--ts-muted);
}
.ts-act:hover { background: var(--ts-surface-2); }
.ts-act:focus-visible { outline: 2px solid var(--ts-primary); outline-offset: 2px; }
.ts-act .lucide { width: 20px; height: 20px; }
.ts-act-whatsapp { width: 21px; height: 21px; fill: var(--ts-act-whatsapp); }
.ts-act-comment { color: var(--ts-act-comment); }
.ts-act-stage { color: var(--ts-act-stage); }
.ts-act-assign { color: var(--ts-act-assign); }
.ts-act-add { color: var(--ts-act-add); }
/* Send Email, 25 Sep 2026: the legacy's indigo-c, and an email on the feed takes the same. */
.ts-act-email { color: var(--ts-act-email); }
.ts-feed-glyph.indigo { color: var(--ts-act-email); }
/* Mark as Lost, 25 Sep 2026: the legacy's red-c, the one colour its "more" menu had, and a loss on the feed takes it.
   Restore brings no colour of its own: it is an undo, and grey says so. */
.ts-act-lost { color: var(--ts-act-lost); }
.ts-feed-glyph.lost { color: var(--ts-act-lost); }
/* Schedule interview, 27 Sep 2026: the legacy's pink-c on its fa-calendar-alt, and a booking on the feed takes it. */
.ts-act-interview { color: var(--ts-act-interview); }
.ts-feed-glyph.pink { color: var(--ts-act-interview); }

/* The job's interviews, over the feed: one row each, the round and when on the left, where it stands on the
   right, and the forms that change it opening under the row they change. */
.ts-interviews { margin-bottom: 12px; border: 1px solid var(--ts-border); border-radius: var(--ts-radius-sm); }
.ts-interviews-head { display: flex; align-items: center; gap: 6px; padding: 8px 12px; font-size: 12.5px; font-weight: 600; border-bottom: 1px solid var(--ts-border); }
.ts-interviews-head .lucide { width: 15px; height: 15px; color: var(--ts-act-interview); }
.ts-interview { padding: 10px 12px; }
.ts-interview + .ts-interview { border-top: 1px dashed var(--ts-dash); }
.ts-interview-row { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 6px 12px; }
.ts-interview-when { font-size: 13px; font-weight: 600; }
.ts-interview-how { font-size: 12px; color: var(--ts-muted); overflow-wrap: anywhere; }
.ts-interview-note { font-size: 12px; margin-top: 4px; white-space: pre-line; overflow-wrap: anywhere; }
.ts-interview-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }
.ts-interview .ts-act-pane { margin-top: 8px; }
.ts-interview.is-over .ts-interview-when { color: var(--ts-muted); text-decoration: line-through; }
/* Feedback under its interview, 28 Sep 2026: a line a person, an answer opening to each question's score. */
.ts-interview-feedback { font-size: 12.5px; margin-top: 4px; }
.ts-interview-feedback summary { cursor: pointer; }
.ts-interview-feedback .ts-pill { margin-right: 4px; }
.ts-feedback-scores { margin: 4px 0 2px 18px; font-size: 12px; }
.ts-feedback-scores td { padding: 1px 12px 1px 0; }
.ts-feedback-scores td:first-child { color: var(--ts-muted); }
.ts-interview-feedback .ts-interview-note { margin: 2px 0 4px 18px; }
/* The employer's Interviews, 10 Oct 2026: the same rows, flush with the card they sit in. */
.ts-interview-list > .ts-interview { padding-inline: 0; }
.ts-interview-list > .ts-interview:first-child { padding-top: 0; }
.ts-interview-list > .ts-interview:last-child { padding-bottom: 0; }

/* The form that books one and changes one: two columns of short boxes, the panel and the note full width. */
.ts-interview-form { display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); gap: 8px 10px; }
.ts-interview-form .ts-wide { grid-column: 1 / -1; }
.ts-interview-form label { display: block; font-size: 12px; color: var(--ts-muted); margin-bottom: 2px; }

/* Make an offer, 30 Sep 2026: a teal the legacy's palette had spare, and an offer on the feed takes it. The button
   that wore it left the action bar for the Offers tab on 5 Oct 2026; the feed and the tab keep the colour. */
.ts-feed-glyph.teal { color: var(--ts-act-offer); }

/* The job's offers, under its interviews and drawn like them: one row a version, the figure and who made it on the
   left, where it stands with the candidate on the right, and the one that stands with its fields laid out. */
.ts-offers { margin-bottom: 12px; border: 1px solid var(--ts-border); border-radius: var(--ts-radius-sm); }
.ts-offers-head { display: flex; align-items: center; gap: 6px; padding: 8px 12px; font-size: 12.5px; font-weight: 600; border-bottom: 1px solid var(--ts-border); }
.ts-offers-head .lucide { width: 15px; height: 15px; color: var(--ts-act-offer); }
.ts-offer { padding: 10px 12px; }
.ts-offer + .ts-offer { border-top: 1px dashed var(--ts-dash); }
.ts-offer-row { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 6px 12px; }
.ts-offer-what { font-size: 13px; font-weight: 600; }
.ts-offer-how { font-size: 12px; color: var(--ts-muted); overflow-wrap: anywhere; }
.ts-offer-note { font-size: 12px; margin-top: 4px; white-space: pre-line; overflow-wrap: anywhere; }
.ts-offer .ts-act-pane { margin-top: 8px; }
.ts-offer-fields { display: grid; grid-template-columns: minmax(8rem, max-content) 1fr; gap: 2px 12px; font-size: 12.5px; margin: 6px 0 2px; }
.ts-offer-fields dt { font-weight: 400; color: var(--ts-muted); }
.ts-offer-fields dd { margin: 0; min-width: 0; overflow-wrap: anywhere; white-space: pre-line; }
.ts-offer-then { font-size: 12.5px; margin-top: 4px; }
.ts-offer-then summary { cursor: pointer; color: var(--ts-muted); }

/* Its approval, 1 Oct 2026: whom the last request asked and what they said, and the requests before it folded. */
.ts-offer-approval { margin-top: 6px; }
.ts-offer-rounds { list-style: none; padding: 0; margin: 4px 0 0; }
.ts-offer-rounds li + li { margin-top: 4px; }

/* The offer's smaller forms (its approval answered, a day raised to the candidate, their answer): the interview form's grid. */
.ts-offer-form { display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); gap: 8px 10px; }
.ts-offer-form .ts-wide { grid-column: 1 / -1; }
/* Raised to the candidate asks one day: kept the width of a date on the form rather than stretched across the pane. */
.ts-offer-form.ts-offer-one { grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr)); }
.ts-offer-form label { font-size: 12px; color: var(--ts-muted); margin-bottom: 2px; }
.ts-offer-form .form-check-label { font-size: 13px; color: inherit; }
.ts-offer-form .ts-act-hint { margin-top: 2px; }

/* The form that makes one and revises one, drawn as the user's design has it (revise-version-2.html, 7 Oct 2026): a
   card of sections, each one's heading and what it says to the left of its fields, the fields three or four to a row
   and what an amount reads as under its box. The type sizes are the app's own, as asked. The card is a container, so
   its rows follow the room inside the card rather than the window: at 1280 the sidebar leaves about 880px there, and
   four dropdowns beside the headings would cut every name short, so a row of four is three until there are 1,000px.
   Narrower still the headings go above their fields, then the fields two to a row, then one. */
.ts-offer-edit {
  background: var(--ts-card); border: 1px solid var(--ts-border); border-radius: 12px; padding: 8px clamp(16px, 4vw, 32px);
  container-type: inline-size;
}
.ts-offer-sec {
  display: grid; grid-template-columns: 240px minmax(0, 1fr); gap: 32px; padding: 28px 0;
  border-top: 1px solid var(--ts-border);
}
.ts-offer-edit > .ts-offer-sec:first-child { border-top: 0; }
.ts-offer-sec-title {
  font-size: 11.5px; line-height: 16px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ts-text);
}
.ts-offer-sec-about { margin: 8px 0 0; font-size: 12px; line-height: 18px; color: var(--ts-muted); }
.ts-offer-sec-body { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
/* A field is its label, its box and what an amount reads as, on three rows it shares with the fields beside it, and a
   fourth row is the space under them. So a label that wraps to two lines takes its neighbours' boxes down with its own
   and the boxes stay in line, each label sitting on its box. */
.ts-offer-grid {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); grid-auto-rows: auto auto auto 20px; column-gap: 16px;
  min-width: 0; margin-bottom: -20px;
}
.ts-offer-grid.ts-offer-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.ts-offer-grid > div { display: grid; grid-row: span 4; grid-template-rows: subgrid; min-width: 0; }
.ts-offer-grid > .ts-offer-span-2 { grid-column: span 2; }
.ts-offer-grid > .ts-offer-full { grid-column: 1 / -1; }
.ts-offer-grid > div > label { align-self: end; font-size: 12px; line-height: 16px; color: var(--ts-muted); margin-bottom: 6px; }
.ts-offer-grid > div > .ts-act-hint { margin-top: 6px; line-height: 16px; }
.ts-offer-grid > div > .ts-act-hint:empty { margin-top: 0; }
/* Its boxes 40px tall and white on the card, a dropdown with the design's caret. Not the search box in a long
   dropdown's list, nor the select a searchable one keeps out of sight. */
.ts-offer-grid > div > .form-control,
.ts-offer-grid > div > .form-select,
.ts-offer-grid > div > .input-group > .form-control,
.ts-offer-grid > div > .ts-combo > .ts-combo-button {
  height: 40px; padding: 0 12px; background-color: var(--ts-card); border-color: var(--ts-border); text-overflow: ellipsis;
}
.ts-offer-grid > div > textarea.form-control { height: auto; padding: 10px 12px; }
.ts-offer-grid > div > .form-select,
.ts-offer-grid > div > .ts-combo > .ts-combo-button {
  --bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3e%3cpath fill='none' stroke='%230f172a' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m6 9 6 6 6-6'/%3e%3c/svg%3e");
  padding-right: 36px; background-position: right 12px center; background-size: 16px 16px;
}
[data-bs-theme=dark] .ts-offer-grid > div > .form-select,
[data-bs-theme=dark] .ts-offer-grid > div > .ts-combo > .ts-combo-button {
  --bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3e%3cpath fill='none' stroke='%23e6ebf5' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m6 9 6 6 6-6'/%3e%3c/svg%3e");
}
.ts-offer-grid > div > .form-control:focus,
.ts-offer-grid > div > .form-select:focus,
.ts-offer-grid > div > .input-group > .form-control:focus,
.ts-offer-grid > div > .ts-combo > .ts-combo-button:focus {
  background-color: var(--ts-card); border-color: var(--ts-primary); box-shadow: none;
  outline: 2px solid var(--ts-primary); outline-offset: -1px;
}
.ts-offer-beside {
  align-self: flex-start; padding: 10px 14px; border-radius: 8px; background: var(--ts-primary-soft);
  font-size: 12px; line-height: 16px; color: var(--ts-text-2); text-wrap: balance;
}
.ts-offer-contract { margin: 0; padding: 0; border: 0; min-width: 0; }
@container (max-width: 1000px) {
  .ts-offer-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@container (max-width: 760px) {
  .ts-offer-sec { grid-template-columns: minmax(0, 1fr); gap: 16px; padding: 20px 0; }
}
@container (max-width: 560px) {
  .ts-offer-grid, .ts-offer-grid.ts-offer-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ts-offer-grid > .ts-offer-span-2 { grid-column: 1 / -1; }
}
@container (max-width: 380px) {
  .ts-offer-grid, .ts-offer-grid.ts-offer-3 { grid-template-columns: minmax(0, 1fr); }
}

/* The job's offers on a tab of their own, 5 Oct 2026. The newest reads in columns under the form's own headings, which
   the form shows too; Revise puts the form where the columns were, so nothing shows twice; one row of buttons under
   where its approval and letter stand; and the offers before it folded to a line each. */
.ts-offer-head {
  font-size: 11.5px; font-weight: 600; letter-spacing: .03em; text-transform: uppercase; color: var(--ts-muted);
  padding-bottom: 3px; margin-bottom: 2px; border-bottom: 1px solid var(--ts-border);
}
.ts-offer-main { padding: 0; }
.ts-offer-groups { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); gap: 14px 24px; margin: 12px 0 8px; }
.ts-offer-group { min-width: 0; }
.ts-offer-group .ts-offer-fields { display: block; margin: 0; }
.ts-offer-group .ts-offer-fields dt { margin-top: 6px; font-size: 12px; }
.ts-offer-group .ts-offer-fields dd { font-size: 13px; }
.ts-offer:has(> .ts-offer-revise.show) > .ts-offer-groups,
.ts-offer:has(> .ts-offer-revise.collapsing) > .ts-offer-groups { display: none; }
.ts-offer-revise .ts-act-pane { margin: 10px 0 4px; }
.ts-offer-buttons { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; margin-top: 10px; }
.ts-offer-main > .collapse > .ts-act-pane,
.ts-offer-another > .collapse > .ts-act-pane { margin-top: 8px; }
.ts-offer-earlier { margin-top: 16px; }
.ts-offer-old { padding: 6px 0; font-size: 13px; }
.ts-offer-old + .ts-offer-old { border-top: 1px dashed var(--ts-dash); }
.ts-offer-old > summary { cursor: pointer; }
.ts-offer-old > summary .ts-offer-what { color: var(--ts-muted); margin-right: 6px; }
.ts-offer-old[open] > summary { margin-bottom: 2px; }
.ts-offer-old .ts-offer-groups { margin-top: 6px; }

/* Where the offers were on the Overview, one line: the newest offer, where it stands, and the way to the tab. */
.ts-offer-line {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; margin-bottom: 12px; padding: 8px 12px;
  border: 1px solid var(--ts-border); border-radius: var(--ts-radius-sm); color: inherit; text-decoration: none; font-size: 13px;
}
.ts-offer-line:hover { border-color: var(--ts-act-offer); color: inherit; }
.ts-offer-line > .lucide { width: 15px; height: 15px; color: var(--ts-act-offer); }
.ts-offer-line-what { font-weight: 600; }
.ts-offer-line-go { margin-left: auto; display: inline-flex; align-items: center; gap: 2px; font-size: 12px; color: var(--ts-muted); }
.ts-offer-line-go .lucide { width: 14px; height: 14px; }

/* A lost job, said where the buttons it takes away were: dashed like the legacy's timeline, with its reason in
   ink and everything else muted, and Restore on the right where the eye leaves the row. */
.ts-lost-banner {
  display: flex; align-items: flex-start; gap: 10px; margin-bottom: 10px; padding: 10px 12px;
  border: 1px dashed var(--ts-dash); border-radius: var(--ts-radius-sm); background: var(--ts-surface-2);
}
.ts-lost-banner > .lucide { width: 18px; height: 18px; flex-shrink: 0; margin-top: 2px; color: var(--ts-act-lost); }
.ts-lost-note { font-size: 13px; margin-top: 2px; white-space: pre-line; overflow-wrap: anywhere; }
/* The day they joined and the guarantee it started, where the lost banner goes and in its frame, since 3 Oct 2026, in
   Change stage's colour since a move records it. Beside the rung in the bar too, where there is room for it. */
.ts-joined-banner {
  display: flex; align-items: center; gap: 10px; margin-bottom: 10px; padding: 10px 12px;
  border: 1px dashed var(--ts-dash); border-radius: var(--ts-radius-sm); background: var(--ts-surface-2);
}
.ts-joined-banner > .lucide { width: 18px; height: 18px; flex-shrink: 0; color: var(--ts-act-stage); }
.ts-topbar-joined { font-size: 13px; color: var(--ts-muted); white-space: nowrap; }
/* The summary for the employer, 9 Oct 2026: the tracker's Remarks, in the lost banner's frame, with its button in a cyan
   of its own. Its words keep the lines they were written in. */
.ts-act-summary { color: var(--ts-act-summary); }
/* Send video interview, 21 Oct 2026: a violet the bar had spare. */
.ts-act-video { color: var(--ts-act-video); }
.ts-summary-banner {
  display: flex; align-items: flex-start; gap: 10px; margin-bottom: 10px; padding: 10px 12px;
  border: 1px dashed var(--ts-dash); border-radius: var(--ts-radius-sm); background: var(--ts-surface-2);
}
.ts-summary-banner > .lucide { width: 18px; height: 18px; flex-shrink: 0; margin-top: 2px; color: var(--ts-act-summary); }
.ts-summary-text { font-size: 13px; margin-top: 2px; white-space: pre-line; overflow-wrap: anywhere; }
/* Send to employer, 9 Oct 2026: a narrow tick column, a small way to the person's page beside the name, and long address
   lists that wrap rather than widen the side card. */
.ts-tracker-tick { width: 2rem; }
.ts-tracker-open { margin-left: 4px; color: var(--ts-muted); }
.ts-tracker-open .lucide { width: 14px; height: 14px; vertical-align: -2px; }
.ts-tracker-to { overflow-wrap: anywhere; }
/* The open panel is marked on its button: its border and a wash of it in the button's own colour. */
.ts-act[aria-expanded="true"] { border-color: currentColor; background: color-mix(in srgb, currentColor 10%, var(--ts-card)); }

.ts-act-panes { margin-bottom: 12px; }
.ts-act-pane { background: var(--ts-surface-2); border-radius: var(--ts-radius-sm); padding: 12px; }
.ts-act-title { display: block; font-size: 12.5px; font-weight: 600; margin-bottom: 6px; }
.ts-act-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.ts-act-row .form-select { width: auto; min-width: 12rem; max-width: 100%; }
.ts-act-row .form-control { flex: 1 1 12rem; min-width: 0; }
.ts-act-picks { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 8px; }
.ts-act-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 8px; }
.ts-act-hint { font-size: 12px; color: var(--ts-muted); margin-top: 6px; }
.ts-act-foot .ts-act-hint { margin-top: 0; }

/* Who approves an offer, 6 Oct 2026: a dropdown a row with × beside it, and under it the two boxes for somebody typed,
   on Send for approval and the Admin's defaults alike. On a phone the two boxes go one above the other. */
.ts-approver + .ts-approver { margin-top: 6px; }
.ts-approver-pick { display: flex; align-items: center; gap: 6px; }
.ts-approver-pick > .form-select, .ts-approver-pick > .ts-combo { flex: 1 1 auto; min-width: 0; }
.ts-approver-drop { flex: none; padding: 3px 6px; line-height: 1; }
.ts-approver-drop svg { width: 14px; height: 14px; }
.ts-approver-typed { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); gap: 6px; margin-top: 6px; }
.ts-approver-add { padding: 6px 0 0; font-size: 12.5px; text-decoration: none; }
.ts-approver-add svg { width: 14px; height: 14px; vertical-align: -2px; }
@media (max-width: 575.98px) {
  .ts-approver-typed { grid-template-columns: 1fr; }
}

/* An email previewed, 6 Oct 2026: its envelope as a mail program lays it out, and its body in a frame of its own, white
   as the email will be whatever the page's theme. */
.ts-mail-head { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 2px 14px; margin: 0 0 10px; font-size: 13px; }
.ts-mail-head dt { color: var(--ts-muted); font-weight: 500; }
.ts-mail-head dd { margin: 0; overflow-wrap: anywhere; }
.ts-mail-body { display: block; width: 100%; height: 480px; border: 1px solid var(--ts-border); border-radius: var(--ts-radius-sm); background: #fff; }

/* The compose box. Who it is from and to, as a mail client heads a message; then the email itself, in the
   job description's editor at a height that leaves the feed in view under it. */
.ts-compose-meta { display: grid; grid-template-columns: auto 1fr; gap: 2px 10px; font-size: 12.5px; margin: 0 0 10px; }
.ts-compose-meta dt { font-weight: 600; color: var(--ts-muted); }
.ts-compose-meta dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
.ts-compose .ts-editor-box { min-height: 240px; max-height: 50vh; }
.ts-compose .ts-editor-box p { margin-bottom: .6em; }
.ts-compose [data-ts-blank] { margin-top: 6px; }

/* The fields beside the template editor under Settings, each a button that writes itself in. */
.ts-fields li { padding: 6px 0; border-bottom: 1px dashed var(--ts-border); }
.ts-fields li:last-child { border-bottom: 0; }
.ts-field-token { font-family: var(--ts-mono); font-size: 12.5px; text-decoration: none; }

/* A sent email on the feed: its subject, then who it went to and from, above the words. */
.ts-feed-mail { margin-top: 2px; }
.ts-feed-mail-subject { font-size: 13px; font-weight: 600; overflow-wrap: anywhere; }
.ts-feed-mail-to { font-size: 11.5px; color: var(--ts-muted); overflow-wrap: anywhere; }

/* The emails a step sent, 7 Oct 2026, a line each under its words: whom it went to and its subject, what went with it,
   and Open email at the end, as the user picked it. Open email is a link, so it reads as one wherever it sits. */
.ts-feed-mails { margin: 6px 0 0; font-size: 12px; color: var(--ts-text-2); }
.ts-feed-mails > li { display: flex; align-items: baseline; gap: 6px; padding: 2px 0; }
.ts-feed-mails > li > .lucide { width: 13px; height: 13px; flex: none; color: var(--ts-muted); align-self: flex-start; margin-top: 3px; }
.ts-feed-mails-what { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.ts-feed-mails-subject { color: var(--ts-text); font-weight: 500; }
.ts-feed-mails-what .ts-pill { margin-left: 4px; }
.ts-feed-mail-open { flex: none; font-size: 12px; white-space: nowrap; margin-left: 6px; }
/* On a phone the line keeps the width, and Open email goes under it, in line with its words, rather than squeezing
   them into a column beside it. */
@media (max-width: 575.98px) {
  .ts-feed-mails > li { flex-wrap: wrap; row-gap: 0; }
  .ts-feed-mails-what { flex-basis: calc(100% - 19px); }
  .ts-feed-mails > li > .ts-feed-mail-open { margin-left: 19px; }
}

/* Open email's window: the app's card rather than Bootstrap's, as the panes are, with the email under its envelope. */
.ts-mail-window .modal-content { background: var(--ts-card); color: var(--ts-text); border: 1px solid var(--ts-border); }
.ts-mail-window .modal-header { border-bottom: 1px solid var(--ts-border); }
.ts-mail-window .modal-title { font-size: 15px; font-weight: 600; overflow-wrap: anywhere; }
.ts-mail-problem { color: var(--ts-danger); }

/* The legacy's boxes, from the user's screenshot of them on 25 Sep 2026: a dotted border rather than a fill,
   a green arrow before a 17px figure, and the unit in a plain 12px label under it — in place of the mono
   uppercase caption this app uses on a KPI. These are facts about a person, not metrics. */
.ts-stat { background: transparent; border: 1px dashed var(--ts-dash); border-radius: 8px; padding: 8px 14px; min-width: 112px; }
.ts-stat-figure { font-size: 17px; font-weight: 650; letter-spacing: -.01em; display: flex; align-items: center; gap: 6px; }
.ts-stat-figure .lucide { width: 15px; height: 15px; stroke-width: 2.5; color: var(--ts-ok); flex: none; }
.ts-stat-label { font-family: var(--ts-sans); font-size: 12px; font-weight: 400; letter-spacing: 0; text-transform: none; color: var(--ts-muted); margin-top: 2px; }
/* The rise they are asking for, beside what they are asking. */
.ts-stat-rise { font-size: 12.5px; font-weight: 600; color: var(--ts-ok); }

/* LinkedIn's mark beside the name, in LinkedIn's blue. */
.ts-linkedin { display: inline-flex; line-height: 0; border-radius: 3px; }
.ts-linkedin svg { width: 20px; height: 20px; fill: #0a66c2; }
.ts-linkedin:hover svg { fill: #004182; }
.ts-linkedin:focus-visible { outline: 2px solid var(--ts-primary); outline-offset: 2px; }

/* Label and value on one line with a rule between rows, at the design's 140px. A Bootstrap dl.row put the
   label in a five-column gutter that went on widening with the card. */
.ts-facts { display: grid; grid-template-columns: 140px minmax(0, 1fr); gap: 0 10px; font-size: 13.5px; margin: 0; }
.ts-facts dt { color: var(--ts-muted); font-weight: 400; padding: 11px 0; border-top: 1px solid var(--ts-border); }
.ts-facts dd { margin: 0; padding: 11px 0; border-top: 1px solid var(--ts-border); font-weight: 500; line-height: 1.5; }
.ts-facts > dt:first-of-type, .ts-facts > dt:first-of-type + dd { border-top: 0; }
.ts-facts .ts-row-sub { font-weight: 400; }
@media (max-width: 400px) { .ts-facts { grid-template-columns: 1fr; } .ts-facts dd { padding-top: 0; border-top: 0; } }

/* A recruiter's rating, the form's stars, in the warm colour so an empty one still reads as a star. */
.ts-stars { color: var(--ts-warn); letter-spacing: 1px; }

/* The candidate form: four pieces of the design the user sent on 29 Sep 2026 (HF_ATS_v3_Design/add-candidate.html),
   asked for one by one once the rest of it had been taken back the same day (PLAN.md, The candidate form in
   the 29 Sep design, and Inter everywhere). The CV drop zone, a header with an icon and a line of its own for
   each section, light lines between the sections, and the highlighted button; the fields are the form's own.
   Every blue in the drawing is the workspace's accent here, and its indigo is the accent turned as far as the
   drawing turns its own blue, so a green workspace gets a green gradient rather than somebody else's blue. */
.ts-cf {
  --ts-cf-field: color-mix(in srgb, var(--ts-surface-2) 50%, var(--ts-card));
  --ts-cf-ring: color-mix(in srgb, var(--ts-primary) 18%, transparent);
  --ts-cf-to: var(--ts-primary-dark);
}
/* The gradient's second colour where the browser can turn a colour, and the accent's darker shade where not:
   14° and a shade darker in light (the drawing's #2563eb to #4f46e5), 21° at the same lightness in dark
   (#5b8cff to #8b7bff). */
@supports (color: oklch(from red l c h)) {
  .ts-cf { --ts-cf-to: oklch(from var(--ts-primary) calc(l - .035) c calc(h + 14)); }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .ts-cf { --ts-cf-to: oklch(from var(--ts-primary) l c calc(h + 21)); }
  }
  :root[data-theme="dark"] .ts-cf { --ts-cf-to: oklch(from var(--ts-primary) l c calc(h + 21)); }
}

/* The sections run to the card's edges, so the lines between them do too, as the drawing has them. */
.ts-card.ts-cf { padding: 0; }
.ts-cf-summary { margin: 18px 28px 0; }
.ts-cf-section { padding: 26px 28px; }
.ts-cf-section + .ts-cf-section { border-top: 1px solid var(--ts-border); }
.ts-cf-head { display: flex; align-items: center; gap: 12px; margin-bottom: 20px; }
.ts-cf-title { font-size: 17px; font-weight: 700; letter-spacing: -.01em; line-height: 1.3; margin: 0; }
.ts-cf-head p { font-size: 13px; color: var(--ts-muted); margin: 0; }
.ts-cf-ico {
  flex: none; width: 36px; height: 36px; border-radius: 10px; display: grid; place-items: center;
  background: var(--ts-primary-soft); color: var(--ts-primary);
}
.ts-cf-ico i, .ts-cf-ico svg { width: 18px; height: 18px; }
.ts-cf-ico.is-solid {
  width: 46px; height: 46px; border-radius: 12px; color: var(--ts-on-primary);
  background: linear-gradient(135deg, var(--ts-primary), var(--ts-cf-to));
}

/* The CV, dropped or chosen. The input is inside the label and off-screen, so the zone is the whole control
   and the keyboard still reaches the input; the ring shows for the keyboard only. */
.ts-cf-drop {
  position: relative; display: flex; align-items: center; gap: 16px; margin: 0; padding: 20px; cursor: pointer;
  border: 1.5px dashed color-mix(in srgb, var(--ts-primary) 35%, var(--ts-border)); border-radius: 14px;
  background: var(--ts-cf-field); transition: border-color .15s, background-color .15s, box-shadow .15s;
}
.ts-cf-drop:hover, .ts-cf-drop.is-over { border-color: var(--ts-primary); background: var(--ts-primary-soft); }
.ts-cf-drop:has(:focus-visible) { border-color: var(--ts-primary); box-shadow: 0 0 0 4px var(--ts-cf-ring); }
.ts-cf-drop-file { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.ts-cf-drop-text { min-width: 0; }
.ts-cf-drop-text b { display: block; font-size: 14.5px; font-weight: 600; color: var(--ts-text); overflow-wrap: anywhere; }
.ts-cf-drop.has-file .ts-cf-drop-text b { color: var(--ts-primary); }
.ts-cf-drop-text em { font-style: normal; font-size: 12.5px; color: var(--ts-muted); }
.ts-cf-browse {
  margin-left: auto; flex: none; font-size: 13px; font-weight: 600; color: var(--ts-primary);
  padding: 8px 14px; border-radius: 9px; border: 1px solid var(--ts-border); background: var(--ts-card);
}

/* The highlighted button, and Cancel drawn to match it. Both keep the app's own pill from .btn, as Add to this
   job on the candidate list has it: the design's 12 px corners were taken off the same day at the user's
   request, and nothing else about the two changed. */
.ts-cf-actions { display: flex; align-items: center; gap: 12px; padding: 20px 28px 26px; border-top: 1px solid var(--ts-border); }
.ts-cf-actions .btn {
  height: 46px; padding: 0 22px; font-size: 14.5px; font-weight: 600;
  display: inline-flex; align-items: center; gap: 8px; white-space: nowrap;
}
.ts-cf-actions .btn i, .ts-cf-actions .btn svg { width: 17px; height: 17px; }
.ts-cf-actions .btn-primary, .ts-cf-actions .btn-primary:hover, .ts-cf-actions .btn-primary:active,
.ts-cf-actions .btn-primary:focus-visible {
  border: 0; color: var(--ts-on-primary);
  background: linear-gradient(135deg, var(--ts-primary), var(--ts-cf-to));
  box-shadow: 0 10px 24px -10px var(--ts-primary);
}
.ts-cf-actions .btn-primary { transition: transform .15s, box-shadow .15s; }
.ts-cf-actions .btn-primary:hover { transform: translateY(-1px); box-shadow: 0 14px 28px -10px var(--ts-primary); }
.ts-cf-actions .btn-primary:focus-visible { box-shadow: 0 0 0 4px var(--ts-cf-ring), 0 10px 24px -10px var(--ts-primary); }
.ts-cf-actions .btn-light { background: var(--ts-card); color: var(--ts-text-2); border: 1px solid var(--ts-border); }
.ts-cf-actions .btn-light:hover { background: var(--ts-card); color: var(--ts-text); border-color: var(--ts-muted); }
@media (prefers-reduced-motion: reduce) {
  .ts-cf-actions .btn-primary:hover { transform: none; }
}

@media (max-width: 575.98px) {
  .ts-cf-summary { margin: 16px 20px 0; }
  .ts-cf-section { padding: 20px; }
  .ts-cf-browse { display: none; }
  .ts-cf-actions { padding: 18px 20px 22px; }
  /* The button takes the width Cancel leaves, so its words stay on one line. */
  .ts-cf-actions .btn-primary { flex: 1; justify-content: center; }
}

/* The ladder, Settings → Lists → Pipeline stages, laid out again on 5 Oct 2026. In two thirds of the row at 1280
   pixels with the sidebar open it had 614 pixels and needed 963: the name boxes, whose width was a percentage and so
   counted for nothing when the table shared out its width, were down to three letters, and every action sat behind
   a sideways scroll. It has the row now, each rung reads as its pill with its rename behind it, and what changes a
   rung's part in the ladder is in a menu beside up and down. */

/* The pill and the pencil are one control, the summary of the rename under them. No marker: the pencil says what
   pressing does. */
.ts-rung-edit > summary {
  display: inline-flex; align-items: center; gap: 6px; max-width: 100%;
  padding: 2px; border-radius: 999px; cursor: pointer; list-style: none;
}
.ts-rung-edit > summary::-webkit-details-marker { display: none; }
.ts-rung-edit > summary .lucide { width: 14px; height: 14px; flex: 0 0 auto; color: var(--ts-muted); }
.ts-rung-edit > summary:hover .lucide, .ts-rung-edit[open] > summary .lucide { color: var(--ts-text); }
.ts-rung-edit > summary:focus-visible { outline: 2px solid var(--ts-primary); outline-offset: 2px; }

/* Held to the column it opens in, with the name on a line of its own: a form wider than the column would widen the
   table and push the actions back behind the scroll. The floor shows about twenty letters of a name. */
.ts-rung-form { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; width: 100%; min-width: 10rem; max-width: 22rem; margin-top: 8px; }
.ts-rung-form input[name="name"] { flex: 1 1 100%; }
.ts-rung-form select { flex: 1 1 0; width: auto; min-width: 0; }
.ts-rung-form .btn { flex: 0 0 auto; }

/* Up, down and the menu in three slots of one width, and an empty slot where a rung has nothing to put in one, so
   the buttons line up from rung to rung whichever of them a rung has. 36 pixels, which is what lets the table fit at
   768 with the sidebar shut. Middle-aligned, since a row whose first slot is empty takes its baseline from the foot
   of that slot otherwise, and stands six pixels taller than the rest. */
.ts-rung-slots { display: inline-flex; gap: 4px; vertical-align: middle; }
.ts-rung-slots > form > .btn, .ts-rung-slots > .dropdown > .btn { width: 2.25rem; padding-left: 0; padding-right: 0; }
.ts-rung-gap { flex: 0 0 2.25rem; }

/* The answer that moves a job to a rung, 8 Oct 2026: as wide as its longest choice, "Sent back to revise". */
.ts-rung-answer-box { width: auto; min-width: 10.5rem; }

/* Eight pixels a side in its cells rather than twelve, since 24 Oct 2026: the Holds column (86 pixels) took the ladder
   51 past its card at 1280 with the sidebar open, and the narrower padding gives back 72, every word kept. */
@media (min-width: 768px) {
  .ts-ladder > :not(caption) > * > * { padding-left: .5rem; padding-right: .5rem; }
}

/* Drawn like the account menu: the same padding and rounded items, and Remove in the danger colour. */
.ts-rung-menu { min-width: 160px; padding: 6px; }
.ts-rung-menu .dropdown-item { border-radius: var(--ts-radius-sm); padding: 8px 12px; }
.ts-rung-menu .dropdown-item.ts-danger { color: var(--ts-danger); }
.ts-rung-menu .dropdown-item.ts-danger:hover, .ts-rung-menu .dropdown-item.ts-danger:focus { background: var(--ts-danger-soft); color: var(--ts-danger); }

/* Below 768 a rung is a block of six lines, made of its own cells rather than a second drawing of them, so nothing
   on the page is there twice: the pill; its status and count; Offers and Joining, each named as its column is; Holds,
   since 24 Oct 2026, beside the employer's switch, since 9 Oct 2026; the answer that moves a job there, since 8 Oct
   2026; then the buttons. The first column fits the widest status pill, so the second lines up from rung to rung. */
@media (max-width: 767.98px) {
  .ts-ladder > thead { display: none; }
  .ts-ladder, .ts-ladder > tbody { display: block; }
  .ts-ladder > tbody > tr {
    display: grid; grid-template-columns: 8.5rem 1fr; gap: 10px 16px; align-items: center;
    grid-template-areas: "name name" "status count" "offers joining" "holds employer" "answer answer" "actions actions";
    padding: 14px 0; border-bottom: 1px solid var(--ts-border);
  }
  .ts-ladder > tbody > tr:last-child { border-bottom: 0; }
  .ts-ladder > tbody > tr > td { display: flex; align-items: center; gap: 8px; padding: 0; border: 0; }
  .ts-ladder .ts-rung-name { grid-area: name; }
  .ts-ladder .ts-rung-status { grid-area: status; }
  .ts-ladder .ts-rung-count { grid-area: count; }
  .ts-ladder .ts-rung-offers { grid-area: offers; }
  .ts-ladder .ts-rung-joining { grid-area: joining; }
  .ts-ladder .ts-rung-holds { grid-area: holds; }
  .ts-ladder .ts-rung-employer { grid-area: employer; }
  .ts-ladder .ts-rung-answer { grid-area: answer; }
  .ts-ladder .ts-rung-actions { grid-area: actions; }
  .ts-ladder td[data-label]::before {
    content: attr(data-label); font-family: var(--ts-mono); font-size: 10.5px; font-weight: 600;
    letter-spacing: .08em; text-transform: uppercase; color: var(--ts-muted);
  }
}

/* Requirement List Stage Wise (Phase 6, 13 Oct 2026): one column per rung of the Vendor's ladder, so the table is as wide
   as the ladder is long and scrolls inside its card; the rung names stay on one line, and the job and who is allotted
   keep room enough not to stand every row on end. */
.ts-stage-wise th { white-space: nowrap; }
.ts-stage-wise td:first-child { min-width: 220px; }
.ts-stage-wise td:last-child { min-width: 200px; }

/* Recruiter Performance (15 Oct 2026): the same ladder across, one row per recruiter. Their name and whom they report
   to keep room, and the rung names stay on one line. */
.ts-recruiter-performance th { white-space: nowrap; }
.ts-recruiter-performance td:first-child { min-width: 220px; }

/* The dashboards (Phase 6, 13 Oct 2026): the user's ATS_Recruiter_Dashboard.html, its sizes and radii kept as the mock
   has them, in the app's Inter and on the app's cards.
   Coloured by the accent since 14 Oct 2026, at the user's word: the mock's purples were one accent among eight, so the
   bars, the funnel, the progress bars, the icon tiles and the avatars are now the accent the reader sees everywhere else
   (their own, where the Vendor allows it, or the Vendor's), and follow it into dark mode as --ts-primary does. What says
   better or worse (green, red, the status pills) and Team Performance's orange Offers bar stay as they are: they mean
   something, and a reader's taste should not change it. */
:root {
  --ts-dash-bar-a: var(--ts-primary);
  --ts-dash-bar-b: color-mix(in srgb, var(--ts-primary) 38%, var(--ts-card));
  --ts-dash-tile: var(--ts-primary-soft); --ts-dash-tile-ink: var(--ts-primary-ink);
  --ts-dash-fill-to: color-mix(in srgb, var(--ts-primary) 70%, #fff);
  /* The funnel runs from its top stage to its bottom one; its words are --ts-on-primary on every stage, so the ramp goes
     darker in light mode, where they are white, and lighter in dark, where they are near-black. */
  --ts-dash-stage-top: color-mix(in srgb, var(--ts-primary) 72%, #000); --ts-dash-stage-bottom: var(--ts-primary);
  --ts-dash-strip: color-mix(in srgb, var(--ts-primary) 6%, var(--ts-card));
  --ts-dash-track: #eef0f5; --ts-dash-rule: #f0f2f6;
  --ts-dash-up: #18a673; --ts-dash-down: #e85d75;
  --ts-dash-on: #e7f8f0; --ts-dash-on-ink: #17815c;
  --ts-dash-attention: #fff2df; --ts-dash-attention-ink: #b76b18;
  --ts-dash-aging: #ffe8ed; --ts-dash-aging-ink: #c33e59;
  --ts-dash-shadow: 0 8px 28px rgba(28, 39, 74, .07);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ts-dash-bar-b: color-mix(in srgb, var(--ts-primary) 42%, var(--ts-card));
    --ts-dash-tile-ink: var(--ts-primary);
    --ts-dash-stage-top: var(--ts-primary); --ts-dash-stage-bottom: color-mix(in srgb, var(--ts-primary) 70%, #fff);
    --ts-dash-strip: var(--ts-surface-2);
    --ts-dash-track: #1f2940; --ts-dash-rule: #1d2638;
    --ts-dash-up: #4ade80; --ts-dash-down: #fb7185;
    --ts-dash-on: #173a2c; --ts-dash-on-ink: #6ee7b7;
    --ts-dash-attention: #3e2e1a; --ts-dash-attention-ink: #fbbf24;
    --ts-dash-aging: #42202b; --ts-dash-aging-ink: #fb7185;
    --ts-dash-shadow: var(--ts-shadow);
  }
}
:root[data-theme="dark"] {
  --ts-dash-bar-b: color-mix(in srgb, var(--ts-primary) 42%, var(--ts-card));
  --ts-dash-tile-ink: var(--ts-primary);
  --ts-dash-stage-top: var(--ts-primary); --ts-dash-stage-bottom: color-mix(in srgb, var(--ts-primary) 70%, #fff);
  --ts-dash-strip: var(--ts-surface-2);
  --ts-dash-track: #1f2940; --ts-dash-rule: #1d2638;
  --ts-dash-up: #4ade80; --ts-dash-down: #fb7185;
  --ts-dash-on: #173a2c; --ts-dash-on-ink: #6ee7b7;
  --ts-dash-attention: #3e2e1a; --ts-dash-attention-ink: #fbbf24;
  --ts-dash-aging: #42202b; --ts-dash-aging-ink: #fb7185;
  --ts-dash-shadow: var(--ts-shadow);
}
/* The mock's title sits in the app's own top bar, so its line here is the subtitle; where the filters leave it too little
   room it takes a line of its own and the filters stay together in one row beneath it, at the right as the mock's are. */
.ts-dash-topbar { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 12px 24px; margin-bottom: 24px; }
.ts-dash-topbar > p { flex: 1 1 320px; }
.ts-dash-actions { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; justify-content: flex-end; margin-left: auto; }
.ts-dash-actions select { max-width: 180px; text-overflow: ellipsis; }
.ts-dash-actions select, .ts-dash-date {
  border: 1px solid var(--ts-border); background: var(--ts-card); border-radius: 10px; padding: 10px 13px;
  color: var(--ts-text-2); font-size: 13px; outline: none; font-family: inherit;
}
.ts-dash-actions select:focus-visible { box-shadow: 0 0 0 3px var(--ts-focus); }
.ts-dash-date { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.ts-dash-date strong { color: var(--ts-text); font-weight: 600; }
.ts-dash-date .lucide { width: 15px; height: 15px; }
.ts-dash-kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 15px; margin-bottom: 18px; }
.ts-dash-kpi, .ts-dash-card {
  background: var(--ts-card); border: 1px solid var(--ts-border); border-radius: 15px; box-shadow: var(--ts-dash-shadow); min-width: 0;
}
.ts-dash-kpi { padding: 18px; }
.ts-dash-kpi-top { display: flex; justify-content: space-between; align-items: center; }
.ts-dash-kpi-icon { width: 38px; height: 38px; border-radius: 11px; display: grid; place-items: center; background: var(--ts-dash-tile); color: var(--ts-dash-tile-ink); }
.ts-dash-kpi-icon .lucide { width: 18px; height: 18px; }
.ts-dash-change-badge { font-size: 13px; color: var(--ts-muted); }
.ts-dash-kpi-label { font-size: 12px; color: var(--ts-muted); margin-top: 12px; }
.ts-dash-kpi-value { font-size: 25px; font-weight: 800; margin-top: 4px; line-height: 1.3; }
.ts-dash-change { font-size: 11px; margin-top: 7px; color: var(--ts-muted); }
.ts-dash-change.up, .ts-dash-change-badge.up { color: var(--ts-dash-up); }
.ts-dash-change.down, .ts-dash-change-badge.down { color: var(--ts-dash-down); }
.ts-dash-grid { display: grid; grid-template-columns: 1.55fr 1fr; gap: 18px; margin-bottom: 18px; }
.ts-dash-bottom { display: grid; grid-template-columns: 1.4fr 1fr; gap: 18px; }
.ts-dash-card { padding: 20px; }
.ts-dash-card-head { display: flex; justify-content: space-between; align-items: center; gap: 10px; margin-bottom: 18px; }
.ts-dash-card-head h3 { font-size: 15px; font-weight: 700; margin: 0; }
.ts-dash-card-head > span { font-size: 11px; color: var(--ts-muted); }
.ts-dash-legend { display: flex; gap: 15px; font-size: 11px; color: var(--ts-muted); }
.ts-dash-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 5px; }
.ts-dash-dot.a { background: var(--ts-dash-bar-a); }
.ts-dash-dot.b { background: var(--ts-dash-bar-b); }
.ts-dash-chart { height: 235px; position: relative; }
.ts-dash-bars { height: 190px; display: flex; align-items: flex-end; gap: 15px; padding: 10px 8px 0; border-bottom: 1px solid var(--ts-border); }
.ts-dash-bar-col { height: 100%; flex: 1; display: flex; align-items: flex-end; justify-content: center; gap: 4px; }
.ts-dash-bar { width: 11px; border-radius: 5px 5px 0 0; }
.ts-dash-bar.a { background: var(--ts-dash-bar-a); }
.ts-dash-bar.b { background: var(--ts-dash-bar-b); }
.ts-dash-xlabels { display: flex; gap: 15px; padding: 9px 8px 0; color: var(--ts-muted); font-size: 10px; }
.ts-dash-xlabels span { flex: 1; text-align: center; }
.ts-dash-funnel { display: flex; flex-direction: column; gap: 8px; padding-top: 3px; }
.ts-dash-stage-wrap { display: flex; justify-content: center; }
.ts-dash-stage {
  height: 31px; border-radius: 7px; display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 0 11px; color: var(--ts-on-primary); font-size: 11px; font-weight: 600; min-width: 150px; max-width: 100%;
  background: color-mix(in srgb, var(--ts-dash-stage-bottom) var(--ts-dash-k, 0%), var(--ts-dash-stage-top));
}
.ts-dash-stage span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ts-dash-note { display: flex; justify-content: space-between; gap: 10px; color: var(--ts-muted); font-size: 10px; margin-top: 12px; }
.ts-dash-note b { color: var(--ts-text); }
.ts-dash-row { display: grid; grid-template-columns: 110px 1fr 42px; gap: 10px; align-items: center; margin: 15px 0; font-size: 11px; }
.ts-dash-row b { text-align: right; }
.ts-dash-progress { height: 8px; background: var(--ts-dash-track); border-radius: 10px; overflow: hidden; }
.ts-dash-progress i { display: block; height: 100%; border-radius: 10px; background: linear-gradient(90deg, var(--ts-dash-bar-a), var(--ts-dash-fill-to)); }
.ts-dash-table { width: 100%; border-collapse: collapse; font-size: 11px; }
.ts-dash-table th { text-align: left; color: var(--ts-muted); font-weight: 600; padding: 9px; border-bottom: 1px solid var(--ts-border); white-space: nowrap; }
.ts-dash-table td { padding: 11px 9px; border-bottom: 1px solid var(--ts-dash-rule); }
.ts-dash-table td:first-child { font-weight: 650; }
.ts-dash-table td:first-child a { color: var(--ts-text); text-decoration: none; }
.ts-dash-table td:first-child a:hover { color: var(--ts-primary); }
.ts-dash-sub { font-weight: 400; color: var(--ts-muted); font-size: 10px; margin-top: 2px; }
.ts-dash-status { padding: 5px 8px; border-radius: 20px; font-size: 10px; white-space: nowrap; }
.ts-dash-status.on { background: var(--ts-dash-on); color: var(--ts-dash-on-ink); }
.ts-dash-status.attention { background: var(--ts-dash-attention); color: var(--ts-dash-attention-ink); }
.ts-dash-status.aging { background: var(--ts-dash-aging); color: var(--ts-dash-aging-ink); }
.ts-dash-activity { display: flex; gap: 11px; padding: 12px 0; border-bottom: 1px solid var(--ts-dash-rule); }
.ts-dash-activity:last-child { border-bottom: 0; }
.ts-dash-act-icon { flex: none; width: 28px; height: 28px; border-radius: 8px; background: var(--ts-dash-tile); color: var(--ts-dash-tile-ink); display: grid; place-items: center; }
.ts-dash-act-icon .lucide { width: 14px; height: 14px; }
.ts-dash-activity b { font-size: 11px; }
.ts-dash-activity p { margin: 3px 0 0; color: var(--ts-muted); font-size: 10px; }
.ts-dash-activity p a { color: inherit; font-weight: 600; }
.ts-dash-empty { color: var(--ts-muted); font-size: 12px; margin: 0; }
@media (max-width: 1100px) {
  .ts-dash-kpis { grid-template-columns: repeat(2, 1fr); }
  .ts-dash-grid, .ts-dash-bottom { grid-template-columns: 1fr; }
}
@media (max-width: 760px) {
  .ts-dash-topbar { flex-direction: column; align-items: flex-start; }
  .ts-dash-topbar > p { flex: none; }
  .ts-dash-actions { width: 100%; justify-content: flex-start; }
  .ts-dash-kpis { grid-template-columns: 1fr; }
  .ts-dash-row { grid-template-columns: 85px 1fr 35px; }
}

/* Team Performance (Phase 6, 13 Oct 2026): the user's ATS_Team_Performance_Dashboard.html, on the same cards. Six
   smaller cards in a row, a third series of bars in the mock's orange, which stays orange whatever the accent, the people's table, and the workload's three.
   Under the amber accent the orange sat too close to the amber Hires bars, so there it is slate's (14 Oct 2026, at the
   user's word); the dark pair outranks the light one, as the dark rules above it would lose to it otherwise. */
:root { --ts-dash-bar-c: #f0a75b; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --ts-dash-bar-c: #f5b97a; }
}
:root[data-theme="dark"] { --ts-dash-bar-c: #f5b97a; }
:root[data-ts-accent="amber"] { --ts-dash-bar-c: rgb(71, 85, 105); }
@media (prefers-color-scheme: dark) {
  :root[data-ts-accent="amber"]:not([data-theme="light"]) { --ts-dash-bar-c: rgb(148, 163, 184); }
}
:root[data-ts-accent="amber"][data-theme="dark"] { --ts-dash-bar-c: rgb(148, 163, 184); }
.ts-dash-kpis.six { grid-template-columns: repeat(6, 1fr); gap: 14px; }
.ts-dash-kpis.six .ts-dash-kpi { padding: 16px; }
.ts-dash-kpis.six .ts-dash-kpi-icon { width: 35px; height: 35px; border-radius: 10px; }
.ts-dash-kpis.six .ts-dash-kpi-label { font-size: 11px; margin-top: 11px; }
.ts-dash-kpis.six .ts-dash-kpi-value { font-size: 23px; margin-top: 3px; }
.ts-dash-kpis.six .ts-dash-change { font-size: 10px; margin-top: 6px; }
.ts-dash-grid.team { grid-template-columns: 1.5fr 1fr; }
.ts-dash-spaced { margin-bottom: 18px; }
.ts-dash-dot.c, .ts-dash-bar.c { background: var(--ts-dash-bar-c); }
.ts-dash-bars.three { height: 185px; gap: 16px; padding: 10px 5px 0; }
.ts-dash-bars.three .ts-dash-bar-col { gap: 3px; }
.ts-dash-bars.three .ts-dash-bar { width: 10px; }
.ts-dash-row.target { grid-template-columns: 110px 1fr 45px; margin: 17px 0; }
.ts-dash-row.target .ts-dash-progress { height: 9px; }
.ts-dash-row.metric { grid-template-columns: 125px 1fr 45px; margin: 15px 0; font-size: 10px; }
.ts-dash-strip { margin-top: 20px; padding: 13px; border-radius: 11px; background: var(--ts-dash-strip); font-size: 11px; }
.ts-dash-person { display: flex; gap: 9px; align-items: center; font-weight: 650; }
.ts-dash-avatar {
  flex: none; width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center;
  background: var(--ts-dash-tile); color: var(--ts-dash-tile-ink); font-size: 10px; font-weight: 800;
}
.ts-dash-score { padding: 5px 8px; border-radius: 20px; font-size: 10px; background: var(--ts-dash-on); color: var(--ts-dash-on-ink); white-space: nowrap; }
.ts-dash-score.warn { background: var(--ts-dash-attention); color: var(--ts-dash-attention-ink); }
.ts-dash-work { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.ts-dash-mini { border: 1px solid var(--ts-border); border-radius: 12px; padding: 14px; }
.ts-dash-mini small { color: var(--ts-muted); font-size: 11px; }
.ts-dash-mini strong { display: block; font-size: 20px; font-weight: 800; margin-top: 5px; }
.ts-dash-mini em { font-style: normal; font-size: 9px; color: var(--ts-muted); }
.ts-dash-mini em.up { color: var(--ts-dash-up); }
.ts-dash-mini em.down { color: var(--ts-dash-down); }
@media (max-width: 1200px) {
  .ts-dash-kpis.six { grid-template-columns: repeat(3, 1fr); }
  .ts-dash-grid.team { grid-template-columns: 1fr; }
}
@media (max-width: 700px) {
  .ts-dash-kpis.six { grid-template-columns: 1fr 1fr; }
  .ts-dash-work { grid-template-columns: 1fr; }
}

/* Coming up (24 Oct 2026, PLAN.md, *Joinings and interviews to come*): the dashboards' and the Admin's overview's card,
   interviews and joinings due side by side, each row a day's tile, the person, and what it is. Today's tile is the
   accent's, a joining day passed with nothing recorded red; on a phone the two lists stack, and the line under each
   name wraps rather than losing the employer to an ellipsis. */
.ts-coming { display: grid; grid-template-columns: 1fr 1fr; gap: 14px 28px; }
.ts-coming > div { min-width: 0; }
.ts-coming-head { display: flex; align-items: center; gap: 7px; font-size: 12px; font-weight: 700; margin: 0 0 4px; color: var(--ts-text-2); }
.ts-coming-head .lucide { width: 15px; height: 15px; color: var(--ts-muted); }
.ts-coming-count { font-weight: 600; color: var(--ts-muted); }
.ts-coming-range { margin-left: auto; font-size: 12px; font-weight: 500; color: var(--ts-muted); }
.ts-coming-list { list-style: none; margin: 0; padding: 0; }
.ts-coming-list li { display: flex; gap: 11px; align-items: center; padding: 10px 0; border-bottom: 1px solid var(--ts-dash-rule); }
.ts-coming-list li:last-child { border-bottom: 0; }
.ts-coming-day {
  flex: none; width: 38px; height: 40px; border-radius: 9px; display: grid; place-content: center; text-align: center;
  background: var(--ts-dash-tile); color: var(--ts-dash-tile-ink); font-size: 9px; text-transform: uppercase; letter-spacing: .04em; line-height: 1.15;
}
.ts-coming-day b { display: block; font-size: 14px; letter-spacing: 0; }
.ts-coming-day.today { background: var(--ts-primary); color: var(--ts-on-primary); }
.ts-coming-day.late { background: var(--ts-danger-soft); color: var(--ts-danger); }
.ts-coming-main { min-width: 0; }
.ts-coming-main a { font-size: 12px; font-weight: 650; color: var(--ts-text); text-decoration: none; }
.ts-coming-main a:hover { color: var(--ts-primary); }
.ts-coming-main .ts-dash-sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ts-coming-late { color: var(--ts-danger); font-weight: 600; }
@media (max-width: 760px) {
  .ts-coming { grid-template-columns: 1fr; }
  .ts-coming-main .ts-dash-sub { white-space: normal; }
}

/* AI screening (PLAN.md, *AI screening*, 14 Oct 2026): the candidate page's tab after Offers, laid out as the user's
   screenshot. The recommendation card (score, assessment, strengths, gaps), then the analysis, a row per requirement
   tinted by how the CV meets it. The score's colour is what it means (green from 75, amber from 50, red under), not the
   accent; the glyphs beside the titles are the accent's. */
.ts-screen-head { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin-bottom: 12px; }
.ts-screen-head-side { display: flex; align-items: center; gap: 10px; }
.ts-screen-glyph { width: 30px; height: 30px; border-radius: 9px; display: inline-grid; place-items: center; background: var(--ts-primary-soft); color: var(--ts-primary-ink); flex: none; }
.ts-screen-glyph.violet { background: var(--ts-info-soft); color: var(--ts-info); }
.ts-card-title .ts-screen-glyph .lucide { width: 16px; height: 16px; color: inherit; }
.ts-screen-score { font-size: 20px; font-weight: 800; line-height: 1; padding: 7px 12px; border-radius: 12px; white-space: nowrap; }
.ts-screen-score small { font-size: 11px; font-weight: 600; opacity: .75; margin-left: 2px; }
.ts-screen-score.green { background: var(--ts-ok-soft); color: var(--ts-ok); }
.ts-screen-score.orange { background: var(--ts-warn-soft); color: var(--ts-warn); }
.ts-screen-score.red { background: var(--ts-danger-soft); color: var(--ts-danger); }
.ts-screen-meta { font-size: 12px; color: var(--ts-muted); margin-bottom: 4px; }
/* Instead of Re-screen while nothing it reads has changed (14 Oct 2026). */
.ts-screen-current { display: inline-flex; align-items: center; gap: 5px; font-size: 12.5px; font-weight: 600; color: var(--ts-muted); white-space: nowrap; cursor: help; }
.ts-screen-current .lucide { width: 14px; height: 14px; }
.ts-screen-label { font-size: 12.5px; font-weight: 650; margin: 16px 0 7px; }
.ts-screen-summary { background: var(--ts-surface-2); border-radius: 10px; padding: 12px 14px; font-size: 13.5px; line-height: 1.6; color: var(--ts-text-2); }
.ts-screen-list { list-style: none; padding: 0; margin: 0; }
.ts-screen-list li { display: flex; gap: 8px; align-items: flex-start; font-size: 13.5px; margin: 7px 0; }
.ts-screen-list .lucide { width: 17px; height: 17px; flex: none; margin-top: 1px; }
.ts-screen .ok { color: var(--ts-ok); }
.ts-screen .part { color: var(--ts-warn); }
.ts-screen .gap { color: var(--ts-danger); }
.ts-screen-table th { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; color: var(--ts-muted); white-space: nowrap; }
.ts-screen-table td { vertical-align: middle; font-size: 13px; }
.ts-screen-table tr.met > td { --bs-table-bg: color-mix(in srgb, var(--ts-ok-soft) 55%, var(--ts-card)); }
.ts-screen-table tr.partial > td { --bs-table-bg: color-mix(in srgb, var(--ts-warn-soft) 55%, var(--ts-card)); }
.ts-screen-table tr.gap > td { --bs-table-bg: color-mix(in srgb, var(--ts-danger-soft) 55%, var(--ts-card)); }
.ts-screen-req { font-weight: 600; min-width: 160px; }
.ts-screen-from { font-weight: 400; font-size: 11px; color: var(--ts-muted); margin-top: 2px; }
.ts-screen-status { width: 20px; height: 20px; }
.ts-screen-rating { white-space: nowrap; font-weight: 600; }
.ts-screen-evidence { font-size: 11.5px; color: var(--ts-muted); margin-top: 5px; }
.ts-screen-source { font-size: 11.5px; color: var(--ts-primary-ink); margin-top: 2px; }
@media (max-width: 760px) {
  .ts-screen-head { flex-wrap: wrap; }
}
/* The AI score on the Candidates list and a job's Candidates tab (step 2, 14 Oct 2026): a narrow column, the score a pill
   in what it means, linking to the report. */
.ts-ai-col { width: 1%; text-align: center; white-space: nowrap; }
th.ts-ai-col { padding-left: 6px !important; padding-right: 6px !important; }
td.ts-ai-col { padding-left: 4px !important; padding-right: 4px !important; }
.ts-ai-score { display: inline-block; min-width: 32px; padding: 3px 7px; border-radius: 999px; font-size: 12px; font-weight: 700; line-height: 1.3; text-decoration: none; }
.ts-ai-score:hover { text-decoration: underline; }
.ts-ai-score.green { background: var(--ts-ok-soft); color: var(--ts-ok); }
.ts-ai-score.orange { background: var(--ts-warn-soft); color: var(--ts-warn); }
.ts-ai-score.red { background: var(--ts-danger-soft); color: var(--ts-danger); }
/* Better-matched jobs (14 Oct 2026): the reader's own allotted jobs that scored 60 or more, each a row with its score,
   the job, Report and Put forward, its summary under it and its report a press away. */
/* A waiting alert with Refresh at its end (14 Oct 2026), so nobody reaches for F5. */
.ts-waiting { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.ts-waiting .btn { flex: none; }
.ts-better-none { font-size: 13px; color: var(--ts-muted); margin-bottom: 6px; }
.ts-better-list { margin-top: 6px; }
.ts-better-job { border-top: 1px solid var(--ts-border); padding: 10px 0; }
.ts-better-job:first-child { border-top: 0; padding-top: 4px; }
.ts-better-job:last-child { padding-bottom: 0; }
.ts-better-job-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.ts-better-job-head .ts-ai-score { text-align: center; flex: none; }
.ts-better-job-head .ts-ai-score:hover { text-decoration: none; }
.ts-better-job-name { flex: 1 1 200px; min-width: 0; font-weight: 600; }
.ts-better-job-sub { display: block; font-size: 12px; font-weight: 400; color: var(--ts-muted); }
.ts-better-job-acts { display: flex; align-items: center; gap: 6px; margin-left: auto; }
.ts-better-job-acts form { margin: 0; }
.ts-better-job-summary { font-size: 13px; line-height: 1.55; color: var(--ts-text-2); margin: 6px 0 0 42px; }
.ts-better-job-report { margin: 4px 0 0 42px; }
/* Relevant candidates (step 2, 15 Oct 2026): each person's latest stage, and the hiring rule's flag, under the summary. */
.ts-relevant-stage, .ts-relevant-flag { font-size: 12px; line-height: 1.5; margin: 6px 0 0 42px; color: var(--ts-muted); }
.ts-relevant-stage .lucide, .ts-relevant-flag .lucide { width: 13px; height: 13px; vertical-align: -2px; margin-right: 4px; }
.ts-relevant-flag { color: var(--ts-warn); }
@media (max-width: 575.98px) {
    .ts-better-job-summary, .ts-better-job-report, .ts-relevant-stage, .ts-relevant-flag { margin-left: 0; }
}
/* The New mark (15 Oct 2026): relevant candidates found for the reader, after the tab's count and a job's title on the list,
   until they open the tab. Solid, in the card's own colour on the accent, so it reads in both themes. */
.ts-new-mark { display: inline-block; margin-left: 6px; padding: 1px 7px; border-radius: 999px; background: var(--ts-primary); color: var(--ts-card); font-size: 10.5px; font-weight: 700; letter-spacing: .03em; line-height: 1.5; vertical-align: 1px; text-decoration: none; }
a.ts-new-mark:hover, a.ts-new-mark:focus { color: var(--ts-card); text-decoration: none; }

/* The header's AI match (14 Oct 2026): the job in hand's score as a bar, in the space the tiles leave under the buttons. */
.ts-ai-match { display: flex; flex-direction: column; justify-content: center; gap: 7px; margin-left: auto; width: 17rem; max-width: 100%; padding: 8px 14px; border: 1px dashed var(--ts-dash); border-radius: 8px; color: var(--ts-text); text-decoration: none; }
.ts-ai-match:hover { border-style: solid; color: var(--ts-text); }
.ts-ai-match-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.ts-ai-match-job { font-size: 12px; font-weight: 600; color: var(--ts-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.ts-ai-match-job .lucide { width: 13px; height: 13px; vertical-align: -2px; }
.ts-ai-match-figure { font-size: 19px; font-weight: 700; letter-spacing: -.02em; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ts-ai-match-figure small { font-size: 11px; font-weight: 600; color: var(--ts-muted); }
.ts-ai-match-bar { display: block; height: 7px; border-radius: 999px; background: var(--ts-surface-2); overflow: hidden; }
.ts-ai-match-bar > span { display: block; height: 100%; border-radius: inherit; }
.ts-ai-match.green .ts-ai-match-figure { color: var(--ts-ok); }
.ts-ai-match.green .ts-ai-match-bar > span { background: var(--ts-ok); }
.ts-ai-match.orange .ts-ai-match-figure { color: var(--ts-warn); }
.ts-ai-match.orange .ts-ai-match-bar > span { background: var(--ts-warn); }
.ts-ai-match.red .ts-ai-match-figure { color: var(--ts-danger); }
.ts-ai-match.red .ts-ai-match-bar > span { background: var(--ts-danger); }

/* The Super Admin's AI usage (14 Oct 2026): each Vendor's share of the month, against the biggest. */
.ts-ai-usage-share { width: 9rem; white-space: nowrap; }
.ts-ai-usage-bar { display: inline-block; width: 5.5rem; height: 7px; margin-right: 6px; border-radius: 999px; background: var(--ts-surface-2); overflow: hidden; vertical-align: middle; }
.ts-ai-usage-bar > span { display: block; height: 100%; border-radius: inherit; background: var(--ts-primary); }

/* The candidate's video interview (Phase 11, slice 2, 21 Oct 2026): one column, the camera on top, the question under it. */
.ts-video { max-width: 640px; margin: 0 auto; }
.ts-video-steps { padding-left: 18px; margin-bottom: 16px; }
.ts-video-steps li { margin-bottom: 6px; }
.ts-video-notice { font-size: 14px; background: var(--ts-surface-2); border-radius: 10px; padding: 12px 14px; }
/* A warning while the interview is answered (Phase 11, slice 5): kept in view above the camera. */
.ts-video-warning { position: sticky; top: .5rem; z-index: 5; }
.ts-video-frame { position: relative; background: #111; border-radius: 12px; overflow: hidden; aspect-ratio: 4 / 3; }
.ts-video-preview { width: 100%; height: 100%; object-fit: cover; transform: scaleX(-1); display: block; }
.ts-video-badge { position: absolute; top: 10px; left: 10px; background: rgba(0, 0, 0, .6); color: #fff; border-radius: 999px; padding: 4px 10px; font-size: 13px; font-weight: 600; }
.ts-video-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; background: #ef4444; margin-right: 4px; }
.ts-video-meter { height: 8px; background: var(--ts-surface-2); border-radius: 999px; overflow: hidden; }
.ts-video-meter span { display: block; height: 100%; width: 0; background: var(--ts-primary); transition: width .1s linear; }
.ts-video-of { font-size: 12px; text-transform: uppercase; letter-spacing: .06em; color: var(--ts-muted); font-weight: 600; }
.ts-video-timer { font-variant-numeric: tabular-nums; font-weight: 600; }
.ts-video-question { font-size: 18px; font-weight: 600; line-height: 1.5; margin: 6px 0 8px; }

/* The record's Video interview tab (Phase 11, slice 3), drawn to the user's own design on 22 Oct 2026 in the app's type:
   a header, the score in a ring beside the overall assessment, the advice note, numbered strengths and gaps, then the
   questions one at a time, each with its question and bars on the left, the recording on the right, and its strengths,
   weaknesses and suggestions under both. The ring and the bars take the score's colour, as the pills do. Without scripts
   every question shows, one under another. */
:root { --ts-vr-good: #15803d; --ts-vr-bad: #b91c1c; --ts-vr-tip: #1d4ed8; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --ts-vr-good: #4ade80; --ts-vr-bad: #f87171; --ts-vr-tip: #93c5fd; }
}
:root[data-theme="dark"] { --ts-vr-good: #4ade80; --ts-vr-bad: #f87171; --ts-vr-tip: #93c5fd; }
.ts-vr { display: flex; flex-direction: column; gap: 16px; max-width: 1120px; margin-left: auto; margin-right: auto; container-type: inline-size; }
.ts-vr .ts-card { margin: 0; }
.ts-vr .green { --ts-vr-tone: var(--ts-ok); }
.ts-vr .orange { --ts-vr-tone: var(--ts-warn); }
.ts-vr .red { --ts-vr-tone: var(--ts-danger); }
.ts-vr-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 8px 16px; }
.ts-vr-eyebrow { display: flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--ts-muted); margin-bottom: 4px; }
.ts-vr-eyebrow .lucide { width: 16px; height: 16px; }
.ts-vr-title { font-size: 20px; font-weight: 600; margin: 0; }
.ts-vr-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 20px; font-size: 13px; color: var(--ts-muted); }
/* Two or more interviews on a job fold under their headers (22 Oct 2026). */
.ts-vr-toggle { display: inline-flex; align-items: center; gap: 4px; }
.ts-vr-toggle .lucide { width: 16px; height: 16px; transition: transform .15s; }
.ts-vr-toggle[aria-expanded="true"] .lucide { transform: rotate(180deg); }
.ts-vr-toggle[aria-expanded="true"] .ts-vr-toggle-show,
.ts-vr-toggle[aria-expanded="false"] .ts-vr-toggle-hide { display: none; }
.ts-vr-hero { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.ts-vr-score { display: flex; align-items: center; gap: 22px; }
.ts-vr-ring { position: relative; width: 120px; height: 120px; flex: none; }
.ts-vr-ring svg { transform: rotate(-90deg); display: block; }
.ts-vr-ring circle { fill: none; stroke-width: 10; }
.ts-vr-ring .track { stroke: var(--ts-surface-2); }
.ts-vr-ring .arc { stroke: var(--ts-vr-tone, var(--ts-primary)); stroke-linecap: round; }
.ts-vr-ring-num { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; }
.ts-vr-ring-num b { font-size: 36px; font-weight: 700; line-height: 1; color: var(--ts-vr-tone, var(--ts-text)); }
.ts-vr-ring-num span { font-size: 12px; color: var(--ts-muted); margin-top: 2px; }
.ts-vr-verdict { font-size: 18px; font-weight: 600; line-height: 1.3; }
.ts-vr-assess p { margin: 0; font-size: 15px; line-height: 1.6; }
.ts-vr-note { display: flex; align-items: center; gap: 10px; padding: 10px 16px; border-radius: var(--ts-radius-sm); background: var(--ts-surface-2); font-size: 13.5px; line-height: 1.5; }
.ts-vr-note .lucide { width: 16px; height: 16px; flex: none; color: var(--ts-muted); }
.ts-vr-h { font-size: 16px; font-weight: 600; margin: 0 0 8px; }
.ts-vr-numbered { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 32px; margin: 0; padding: 0; list-style: none; }
.ts-vr-numbered li { display: flex; align-items: baseline; gap: 14px; padding: 10px 0; border-top: 1px solid var(--ts-border); font-size: 14px; line-height: 1.5; }
.ts-vr-numbered li span { font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums; }
.ts-vr-list.good li span { color: var(--ts-vr-good); }
.ts-vr-list.bad li span { color: var(--ts-vr-bad); }
.ts-vr-questions { display: flex; flex-direction: column; gap: 12px; }
.ts-vr-qhead { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 16px; margin-top: 4px; }
.ts-vr-qtitle { display: flex; align-items: baseline; gap: 12px; }
.ts-vr-pos { font-size: 13px; color: var(--ts-muted); }
.ts-vr-nav:not([hidden]) { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.ts-vr-steps { display: flex; gap: 6px; padding: 0 4px; }
.ts-vr-btn { display: inline-flex; align-items: center; gap: 4px; min-height: 36px; padding: 0 14px 0 10px; border-radius: 18px; border: 1px solid var(--ts-border); background: var(--ts-card); color: var(--ts-text); font-size: 14px; font-weight: 500; cursor: pointer; }
.ts-vr-btn .lucide { width: 16px; height: 16px; }
.ts-vr-btn-next { padding: 0 10px 0 14px; background: var(--ts-text); border-color: var(--ts-text); color: var(--ts-card); }
.ts-vr-btn:disabled { opacity: .4; cursor: not-allowed; }
.ts-vr-step { width: 36px; height: 36px; border-radius: 50%; border: 1px solid var(--ts-border); background: var(--ts-card); color: var(--ts-text); font-size: 14px; font-weight: 600; cursor: pointer; }
.ts-vr-step[aria-current="true"] { background: var(--ts-text); border-color: var(--ts-text); color: var(--ts-card); }
.ts-vr-btn:focus-visible, .ts-vr-step:focus-visible { outline: 3px solid var(--ts-primary); outline-offset: 2px; }
.ts-vr-q { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px 24px; }
.ts-vr-q-left { display: flex; flex-direction: column; justify-content: space-between; gap: 16px; min-width: 0; }
.ts-vr-q-label { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.ts-vr-tag { font-size: 11px; font-weight: 600; padding: 2px 7px; border-radius: 6px; background: var(--ts-surface-2); color: var(--ts-text-2); }
.ts-vr-q-text { margin: 0; font-size: 18px; font-weight: 600; line-height: 1.4; }
.ts-vr-q-score-row { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 8px; font-size: 13px; color: var(--ts-muted); }
.ts-vr-q-score .val { font-size: 18px; font-weight: 700; color: var(--ts-vr-tone, var(--ts-text)); }
.ts-vr-q-score .val small { font-size: 13px; font-weight: 400; color: var(--ts-muted); }
.ts-vr-segs { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 6px; }
.ts-vr-segs i { height: 8px; border-radius: 4px; background: var(--ts-surface-2); }
.ts-vr-segs i.on { background: var(--ts-vr-tone, var(--ts-primary)); }
.ts-vr-q-right { min-width: 0; }
.ts-vr-video { display: block; width: 100%; aspect-ratio: 16 / 10; background: #111; border-radius: var(--ts-radius-sm); }
.ts-vr-video-none { display: flex; align-items: center; justify-content: center; padding: 16px 24px; text-align: center; color: #d9d6ce; font-size: 14px; line-height: 1.5; }
.ts-vr-video-meta { font-size: 12px; color: var(--ts-muted); margin-top: 6px; }
.ts-vr-transcript { margin-top: 6px; }
.ts-vr-transcript summary { font-size: 13px; cursor: pointer; }
.ts-vr-transcript p { font-size: 14px; white-space: pre-wrap; margin: 6px 0 0; }
.ts-vr-sw { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px 24px; padding-top: 16px; border-top: 1px solid var(--ts-border); }
.ts-vr-sw-col.tip { grid-column: 1 / -1; }
/* Strengths or weaknesses alone take the width, rather than leaving half the row empty. */
.ts-vr-sw:not(:has(.ts-vr-sw-col.good)) .ts-vr-sw-col.bad, .ts-vr-sw:not(:has(.ts-vr-sw-col.bad)) .ts-vr-sw-col.good { grid-column: 1 / -1; }
/* Two blocks side by side, as the user's design, until the tab itself is too narrow for them (a phone, or a narrow window
   with the sidebar open): then one under another. */
@container (max-width: 640px) {
  .ts-vr-hero, .ts-vr-numbered, .ts-vr-q, .ts-vr-sw { grid-template-columns: minmax(0, 1fr); }
}
.ts-vr-sw h4 { display: flex; align-items: center; gap: 6px; margin: 0 0 8px; font-size: 12px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; }
.ts-vr-sw h4 .lucide { width: 15px; height: 15px; }
.ts-vr-sw-col.good h4 { color: var(--ts-vr-good); }
.ts-vr-sw-col.bad h4 { color: var(--ts-vr-bad); }
.ts-vr-sw-col.tip h4 { color: var(--ts-vr-tip); }
.ts-vr-sw ul { margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 6px; font-size: 14px; line-height: 1.5; }
.ts-vr-reason { margin: 0; font-size: 14px; }
.ts-vr-foot { font-size: 12.5px; color: var(--ts-muted); margin: 0; }
/* The integrity section (Phase 11, slice 5): each warning with its snapshot. */
.ts-vr-events { display: grid; gap: .5rem; }
.ts-vr-event { display: flex; gap: .75rem; align-items: center; }
.ts-vr-event img, .ts-vr-event-none { width: 96px; height: 72px; object-fit: cover; border-radius: 6px; background: var(--ts-surface-2, #f1f3f5); flex: none; }
.ts-vr-event-none { display: inline-flex; align-items: center; justify-content: center; color: var(--bs-secondary-color); }
/* The employer's view of a finished video interview on People to review (slice 4): each question, its recording and
   transcript, one under another. */
.ts-hiring-video-q + .ts-hiring-video-q { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--ts-border); }
.ts-hiring-video-question { font-size: 14.5px; line-height: 1.5; margin: 0 0 8px; }
/* A video interview's score under the screening's in a list's AI column (Phase 11, slice 3): its own line, a camera before it. */
.ts-video-score { display: flex; width: fit-content; align-items: center; gap: 3px; margin-top: 4px; }
.ts-video-score .lucide { width: 12px; height: 12px; }

/* The first-run guide on the Admin's dashboard (Phase 11, 23 Oct 2026): ten steps in two columns, each ticked from what
   is there, the ones left with a button to their page. */
.ts-setup-bar { height: 6px; margin: 12px 0 14px; background: var(--ts-surface-2); border-radius: 6px; overflow: hidden; }
.ts-setup-bar i { display: block; height: 100%; background: var(--ts-primary); border-radius: 6px; }
.ts-setup-steps { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr)); gap: 10px 24px; list-style: none; margin: 0; padding: 0; }
.ts-setup-steps li { display: flex; align-items: center; gap: 10px; min-width: 0; }
.ts-setup-step-main { flex: 1; min-width: 0; }
.ts-setup-step-main strong { display: block; font-size: 13.5px; font-weight: 600; }
.ts-setup-step-main small { display: block; color: var(--ts-muted); font-size: 12px; line-height: 1.35; }
.ts-setup-steps .ts-step-no .lucide { width: 13px; height: 13px; }
.ts-setup-steps li.is-done .ts-step-no { background: var(--ts-ok-soft); color: var(--ts-ok); }
.ts-setup-steps li.is-done .ts-setup-step-main strong { color: var(--ts-muted); font-weight: 500; }
