:root {
  --bg: #f4f5f7;
  --surface: #ffffff;
  --border: #e2e5ea;
  --border-strong: #cbd2dc;
  --text: #1c2027;
  --muted: #6b7484;
  --accent: #2f6feb;
  --accent-soft: #eaf1fe;
  --ok: #14804a;
  --ok-soft: #e6f4ec;
  --warn: #9a6200;
  --warn-soft: #fdf3e2;
  --danger: #b3261e;
  --danger-soft: #fdecea;
  --radius: 10px;
  --shadow: 0 1px 2px rgba(16, 24, 40, .06), 0 1px 3px rgba(16, 24, 40, .1);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 15px/1.5 -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ---------- layout ---------- */
.topbar {
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 20;
}
.topbar-inner {
  max-width: 1200px; margin: 0 auto; padding: 0 20px;
  display: flex; align-items: center; gap: 24px; height: 56px;
}
.brand { font-weight: 700; color: var(--text); font-size: 16px; }
.brand:hover { text-decoration: none; }
.nav { display: flex; gap: 4px; margin-right: auto; }
.nav a {
  padding: 7px 12px; border-radius: 8px; color: var(--muted); font-weight: 500;
}
.nav a:hover { background: var(--bg); color: var(--text); text-decoration: none; }
.nav a.active { background: var(--accent-soft); color: var(--accent); }
.user-menu { display: flex; align-items: center; gap: 10px; }
.user-chip { color: var(--text); font-weight: 500; font-size: 14px; }

.lang-switch {
  display: inline-flex; align-items: center; gap: 2px; padding: 2px;
  border: 1px solid var(--border); border-radius: 8px; font-size: 12px; font-weight: 600;
}
.lang-switch a, .lang-switch .lang-current { padding: 3px 7px; border-radius: 6px; }
.lang-switch a { color: var(--muted); }
.lang-switch a:hover { background: var(--bg); color: var(--text); text-decoration: none; }
.lang-switch .lang-current { background: var(--accent-soft); color: var(--accent); }
.lang-standalone { display: flex; justify-content: flex-end; margin-bottom: 12px; }

/* Account switcher: several people signed in, one active per tab. */
.account-menu { position: relative; }
.account-menu > summary {
  cursor: pointer; list-style: none; display: flex; align-items: center; gap: 6px;
  padding: 5px 9px; border-radius: 8px;
}
.account-menu > summary::-webkit-details-marker { display: none; }
.account-menu > summary:hover { background: var(--bg); }
.account-menu[open] > summary { background: var(--bg); }
.caret { color: var(--muted); font-size: 11px; }
.account-list {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 30;
  min-width: 280px; padding: 6px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: 0 8px 24px rgba(16, 24, 40, .14);
}
.account-heading {
  padding: 8px 10px 4px; font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em; color: var(--muted);
}
.account-row {
  display: flex; align-items: center; gap: 8px; justify-content: space-between;
  padding: 8px 10px; border-radius: 8px; color: var(--text); font-size: 14px;
}
.account-row:hover { background: var(--bg); text-decoration: none; }
.account-row.is-active { background: var(--accent-soft); font-weight: 600; }
.account-note { margin: 6px 10px; font-size: 12px; color: var(--muted); }
.account-actions {
  display: flex; flex-wrap: wrap; gap: 6px; padding: 8px 6px 4px;
  border-top: 1px solid var(--border); margin-top: 4px;
}

/* The eighty pixels that used to sit under every page were dead space a
   list could have been using. */
.page { max-width: 1200px; margin: 0 auto; padding: 28px 20px 24px; }
.page-narrow { max-width: 420px; padding-top: 12vh; }

/* ---------- pieces ---------- */
.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow); margin-bottom: 14px;
}
.card-head {
  padding: 16px 20px; border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
}
.card-head h2 { margin: 0; font-size: 16px; }
.card-body { padding: 20px; }
.card-body.tight { padding: 0; }

.page-head {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin-bottom: 20px;
}
.page-head h1 { margin: 0; font-size: 22px; }
.spacer { margin-left: auto; }
.toolbar { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
/* A tick box standing in a toolbar reads as one line, not label-above-control. */
.toolbar-check {
  display: inline-flex; align-items: center; gap: 6px; margin: 0;
  font-size: 13px; color: var(--muted); white-space: nowrap;
}
.toolbar-check input { width: auto; margin: 0; }
.muted { color: var(--muted); }
.small { font-size: 13px; }
.mono { font-variant-numeric: tabular-nums; }

.layout-split { display: grid; grid-template-columns: 1fr 300px; gap: 20px; align-items: start; }
@media (max-width: 980px) { .layout-split { grid-template-columns: 1fr; } }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 6px; justify-content: center;
  padding: 8px 14px; border-radius: 8px; border: 1px solid var(--border-strong);
  background: var(--surface); color: var(--text); font: inherit; font-weight: 500;
  cursor: pointer; white-space: nowrap;
}
.btn:hover { background: var(--bg); text-decoration: none; }
.btn-primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn-primary:hover { background: #2760cf; }
.btn-ghost { border-color: transparent; background: transparent; color: var(--muted); }
.btn-ghost:hover { background: var(--bg); color: var(--text); }
.btn-danger { color: var(--danger); border-color: var(--border); }
.btn-danger:hover { background: var(--danger-soft); }
.btn-sm { padding: 5px 10px; font-size: 13px; }
.btn-icon { padding: 4px 9px; font-size: 15px; line-height: 1.2; }
/* The padlock shows how a contract stands. Shut, it should be noticed; open,
   it is only an offer, so it sits back until the row is pointed at. */
.btn-icon.is-locked { border-color: var(--border-strong); }
tr:not(:hover) .btn-icon.is-unlocked { opacity: .45; }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
/* Five controls at full size do not fit the width of a table's last column, so
   they stack, and every row of the table becomes as tall as that pile. Made
   small enough to sit on one line they still wrap if they ever have to — the
   row gets shorter and nothing can push the table sideways. */
.btn-row-compact { gap: 3px; }
.btn-row-compact .btn-icon { padding: 2px 5px; font-size: 13px; line-height: 1.15; }
.btn-row-compact .btn-count { min-width: 11px; padding: 0 2px; font-size: 9px; line-height: 12px; }
/* Controls stacked one line under another rather than strung across a cell. */
.btn-stack { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }

/* ---------- forms ---------- */
label { display: block; font-size: 13px; font-weight: 500; color: var(--muted); margin-bottom: 5px; }
/* Date boxes are in this list so they stand the same height as the rest: left
   to the browser they size themselves from their own calendar control. */
input[type=text], input[type=email], input[type=password], input[type=number],
input[type=week], input[type=date], select, textarea {
  width: 100%; padding: 8px 11px; border: 1px solid var(--border-strong);
  border-radius: 8px; font: inherit; line-height: 1.5; background: var(--surface); color: var(--text);
}
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft);
}
.field { margin-bottom: 14px; }
.field-row { display: flex; gap: 12px; flex-wrap: wrap; }
.field-row > .field { flex: 1 1 180px; margin-bottom: 0; }
.inline-form { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; }
.inline-form .field { margin-bottom: 0; }
/* Two fields that belong together — a from and a to — wrap as one or not at
   all, so a narrow window never leaves the pair split across two lines. */
/* A button standing in a row of fields sits on the inputs' baseline, not
   floating at the top where the labels are. */
.field-action { display: flex; align-items: flex-end; }

/* Editing a share where it is read, rather than in a form somewhere else. */
.percent-form { display: flex; align-items: center; justify-content: flex-end; gap: 4px; }
.percent-input {
  width: 64px; text-align: right; padding: 4px 6px;
  font-variant-numeric: tabular-nums;
}
/* A money box sitting inside a table row: tight enough not to burst the
   column, still right-aligned like the figure it replaced. */
.money-input {
  text-align: right; padding: 4px 6px;
  font-variant-numeric: tabular-nums;
}
.field-pair { display: flex; gap: 12px; flex-wrap: nowrap; }
.field-pair .field { margin-bottom: 0; }
/* Likewise the pair of dates in the table: never broken between them. */
.dates-cell { white-space: nowrap; }
/* A form laid out as deliberate rows rather than one long flowing line. */
.stacked-form .field-row + .field-row { margin-top: 14px; }
.stacked-form .btn-row { margin-top: 16px; }

/* ---------- tables ---------- */
table { width: 100%; border-collapse: collapse; }
th, td { padding: 8px 12px; text-align: left; border-bottom: 1px solid var(--border); }
th {
  font-size: 12px; text-transform: uppercase; letter-spacing: .03em;
  color: var(--muted); font-weight: 600; background: #fafbfc;
}
tbody tr:last-child td { border-bottom: none; }
tbody tr:hover { background: #fafbfc; }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
tfoot td { font-weight: 600; background: #fafbfc; border-top: 1px solid var(--border-strong); }
/* Every list scrolls inside its own frame rather than with the page, so its
   headings stay above the rows and a column keeps its meaning however far
   down you are. It has to be this way round: `position: sticky` resolves
   against the nearest scroll container, and `overflow-x: auto` already makes
   this box one — so leaving the vertical scroll to the page would let the
   heading slide away with it. Same reasoning as .grid-frozen further down.
   The frame is capped short of the viewport, leaving room for whatever sits
   above it, and a table shorter than the cap simply never scrolls. */
.table-scroll { overflow: auto; max-height: 78vh; }
.table-scroll thead th {
  position: sticky; top: 0; z-index: 2;
  /* Collapsed borders belong to the table, not the cell, so they do not
     travel with a sticky heading; this line is drawn by the cell instead. */
  box-shadow: inset 0 -1px 0 var(--border);
}
.row-inactive td { opacity: .55; }
/* The bench sits between the projects and the total, and belongs to neither:
   ruled off above so it reads as part of the sum rather than another project. */
.row-bench td { border-top: 2px solid var(--border-strong); }
/* The control that unfolds a project sits under its code rather than beside
   it, which was breaking the code across two lines in a narrow column. */
.cell-open { margin-top: 4px; }
/* A contract shown under the project it belongs to: set in from the left and
   drawn back, so the eye still reads the projects as the list. */
.row-child td { font-size: 13px; border-top: none; }
.row-child td:nth-child(2) { padding-left: 26px; }
/* A project heading and the contracts filed under it. The heading is the list;
   the contracts are what it opens onto, so they are set in and drawn back. */
.row-group > td { border-top: 2px solid var(--border-strong); background: #fafbfc; }
.row-group .cell-open { display: flex; align-items: center; gap: 8px; margin: 0; }
tr.row-child > td.cell-indent { padding-left: 30px; }

/* Sits above the table, over the column of carets it works on. */
.group-toolbar {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 14px; border-bottom: 1px solid var(--border);
}

/* ---------- tags & flashes ---------- */
.tag {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .03em;
}
.tag-manager { background: var(--accent-soft); color: var(--accent); }
.tag-supervisor { background: #efe6fb; color: #6b3fa0; }
/* An executive reads the company; an administrator keeps its timesheets.
   Both were falling through to no colour at all. */
.tag-executive { background: #e6f0fb; color: #1f5c96; }
.tag-administrator { background: #fbf0e2; color: #8a5a12; }
.tag-employee { background: var(--bg); color: var(--muted); }
.tag-pending { background: var(--warn-soft); color: var(--warn); }
.tag-approved { background: var(--ok-soft); color: var(--ok); }
.tag-declined { background: var(--danger-soft); color: var(--danger); }

.badge {
  display: inline-block; min-width: 18px; padding: 1px 6px; margin-left: 4px;
  border-radius: 999px; background: var(--danger); color: #fff;
  font-size: 11px; font-weight: 700; text-align: center; vertical-align: 1px;
}
/* Must follow .badge: same specificity, so only order decides which wins.
   A plain count is not an alarm — red is for work that is waiting. */
.badge-quiet { background: var(--muted); }

/* A count riding inside an icon button. Tighter than .badge, which is sized
   for a navigation label and would push a row of these onto a second line.
   Shown only when there is something to count. */
.btn-count {
  display: inline-block; min-width: 13px; margin-left: 3px; padding: 0 3px;
  border-radius: 999px; background: var(--muted); color: #fff;
  font-size: 10px; font-weight: 700; line-height: 15px; text-align: center;
  vertical-align: 2px;
}

/* week state banner */
.banner {
  display: flex; align-items: center; gap: 10px; padding: 12px 16px;
  border-radius: var(--radius); margin-bottom: 20px; font-size: 14px;
  border: 1px solid var(--border);
}
.banner-closed { background: var(--danger-soft); border-color: #f3c9c5; color: var(--danger); }
.banner-future { background: var(--bg); color: var(--muted); }
/* Not a warning: a week that was worked out is a normal week, it just
   was not typed by anybody. */
.banner-info { background: var(--accent-soft); border-color: #c6d9fb; color: var(--accent); }

.review-note {
  margin-top: 4px; font-size: 12px; color: var(--danger);
}
.locked-cell { color: var(--muted); font-variant-numeric: tabular-nums; }
.decline-form { display: flex; gap: 6px; align-items: center; }
.decline-form input[type=text] { width: 150px; padding: 5px 9px; font-size: 13px; }

/* Approve and Decline sit on a single line and never wrap apart. */
.review-actions { display: flex; gap: 8px; align-items: center; flex-wrap: nowrap; }
.review-actions form { display: flex; gap: 6px; align-items: center; }
.review-actions .decline-form input[type=text] { width: 130px; min-width: 90px; }
.review-actions .btn { white-space: nowrap; }

/* The current week's column in the week-by-week grid: a blue stripe running
   down the table so you can find "now" without reading the headers. Drawn with
   inset shadows rather than borders so it does not shift the column width. */
.col-now {
  background: var(--accent-soft) !important;
  box-shadow: inset 2px 0 0 var(--accent), inset -2px 0 0 var(--accent);
}
thead .col-now { color: var(--accent); font-weight: 700; }

/* Report view switcher. */
.tabs { display: flex; gap: 4px; margin-bottom: 18px; border-bottom: 1px solid var(--border); }
.tabs a {
  padding: 9px 14px; color: var(--muted); font-weight: 500;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.tabs a:hover { color: var(--text); text-decoration: none; }
.tabs a.active { color: var(--accent); border-bottom-color: var(--accent); }

/* How far a project's week has been reviewed, at a glance. */
.progress {
  display: flex; height: 8px; width: 100%; border-radius: 999px;
  overflow: hidden; background: var(--border); margin-bottom: 5px;
}
.progress span { display: block; height: 100%; }
.bar-approved { background: var(--ok); }
.bar-pending  { background: var(--warn); }
.bar-declined { background: var(--danger); }

/* A project's title next to its code. Full-strength text, not the faint
   "muted small" treatment — this is content you read, not a caption. */
.project-name { color: var(--text); font-size: 14px; margin-left: 4px; }

/* Holiday and sick days, kept visually apart from the project rows. */
.away-bar {
  display: flex; align-items: flex-end; gap: 16px; flex-wrap: wrap;
  padding: 14px 20px; border-top: 1px solid var(--border);
  background: #fbfcfd;
}
.away-label { font-weight: 600; align-self: center; }
.away-field { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--muted); }
.away-field input[type=number] { width: 92px; }
.away-field.away-note { flex: 1 1 180px; }
.away-field.away-note input { width: 100%; }
.away-bar > .muted { align-self: center; }

/* Frozen panes for the days-by-employee grid.
   The box scrolls in both directions itself, rather than the page, because
   `position: sticky` resolves against the nearest scroll container — leaving
   the vertical scroll to the page would let the header slide away. */
.grid-frozen {
  max-height: 70vh;
  overflow: auto;
  /* Belt and braces: the row and column that stay put are drawn over the rest. */
  position: relative;
}
.grid-sticky { border-collapse: separate; border-spacing: 0; }
.grid-sticky th,
.grid-sticky td { border-bottom: 1px solid var(--border); }

/* Column widths have to be fixed, or the frozen offset below cannot be. */
.grid-sticky th:first-child,
.grid-sticky td:first-child { width: 220px; min-width: 220px; }
.grid-sticky th:nth-child(2),
.grid-sticky td:nth-child(2) { width: 104px; min-width: 104px; }

/* The two header rows stay at the top. */
.grid-sticky thead th {
  position: sticky; z-index: 4; background: #fafbfc;
  box-shadow: inset 0 -1px 0 var(--border);
}
.grid-sticky thead tr:first-child th { top: 0; height: 38px; }
.grid-sticky thead tr.totals-row th {
  top: 38px; height: 34px;
  background: var(--accent-soft); color: var(--accent); font-weight: 700;
}

/* The name and its total stay at the left. */
.grid-sticky th:first-child,
.grid-sticky td:first-child { position: sticky; left: 0; z-index: 3; background: var(--surface); }
.grid-sticky th:nth-child(2),
.grid-sticky td:nth-child(2) {
  position: sticky; left: 220px; z-index: 3; background: var(--surface);
  box-shadow: inset -1px 0 0 var(--border);
}
/* Where a frozen row meets a frozen column, the corner must win. */
.grid-sticky thead th:first-child,
.grid-sticky thead th:nth-child(2) { z-index: 6; }
.grid-sticky tbody tr:hover td:first-child,
.grid-sticky tbody tr:hover td:nth-child(2) { background: #fafbfc; }

@media (prefers-color-scheme: dark) {
  .grid-sticky thead th { background: #171b21; }
  .grid-sticky th:first-child,
  .grid-sticky td:first-child,
  .grid-sticky th:nth-child(2),
  .grid-sticky td:nth-child(2) { background: var(--surface); }
  .grid-sticky thead tr.totals-row th { background: #1e2a3f; }
  .grid-sticky tbody tr:hover td:first-child,
  .grid-sticky tbody tr:hover td:nth-child(2) { background: #1f242c; }
}

/* Pin a project so it waits on your timesheet every week. */
.pin-toggle {
  border: 0; background: none; cursor: pointer; padding: 4px 6px;
  font-size: 16px; line-height: 1; border-radius: 8px;
  filter: grayscale(1); opacity: .35;   /* unpinned: present but quiet */
  transition: opacity .12s, filter .12s;
}
.pin-toggle:hover { opacity: .8; background: var(--bg); }
.pin-toggle.is-pinned { filter: none; opacity: 1; background: var(--accent-soft); }
.pin-mark { margin-left: 6px; opacity: .75; font-size: 13px; }
/* On the contracts page the pin shares a line with the contract's number,
   so the form around it must not take a line of its own. */
.pin-form { display: inline; }
.pin-form .pin-toggle { padding: 0 4px 0 0; font-size: 13px; vertical-align: baseline; }

/* Find-a-project box above the timesheet rows. */
.lookup-bar {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 20px; border-bottom: 1px solid var(--border);
}
.lookup-bar input[type=search] { width: 260px; flex: 0 0 auto; }
.lookup-bar .muted { flex: 1; }

/* Inline day editing on the approvals table. */
.days-input { width: 80px; text-align: right; padding: 6px 8px; }

/* Salary: dots until you point at them. The dots are the control — there is
   no button to press — and an ordinary table cell, so the figures line up with
   the columns either side of them. */
.salary-cell { white-space: nowrap; }
.salary-mask {
  font-variant-numeric: tabular-nums; letter-spacing: .06em;
  min-width: 74px; display: inline-block; cursor: help;
}
.salary-mask:hover, .salary-mask:focus { color: var(--accent); }
.salary-mask:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.salary-mask.revealed { letter-spacing: normal; font-weight: 600; }

/* Checkbox rows read as one line, not label-above-control. */
.checkbox-field label { display: flex; align-items: center; gap: 8px; font-weight: 500; color: var(--text); }
.checkbox-field input[type=checkbox] { width: auto; margin: 0; }

/* Reports: keep the employee column visible while scrolling sideways. */
.sticky-first th:first-child,
.sticky-first td:first-child {
  position: sticky; left: 0; z-index: 2;
  background: var(--surface);
  box-shadow: 1px 0 0 var(--border);
}
.sticky-first thead th:first-child { z-index: 3; background: #fafbfc; }
.sticky-first tfoot td:first-child { z-index: 3; background: #fafbfc; }
.sticky-first tbody tr:hover td:first-child { background: #fafbfc; }

/* Employees: the same trick at the other edge, so the row's buttons stay on
   screen however many columns the table grows. The editor row spans the whole
   width and must not be pinned with them, or it would slide over its own form. */
.sticky-last thead th:last-child,
.sticky-last tbody tr:not(.js-edit-row) td:last-child {
  position: sticky; right: 0; z-index: 2;
  background: var(--surface);
  box-shadow: -1px 0 0 var(--border);
}
.sticky-last thead th:last-child { z-index: 3; background: #fafbfc; }
.sticky-last tbody tr:not(.js-edit-row):hover td:last-child { background: #fafbfc; }
/* Three icons to a line: five of them fold into two short lines instead of one
   long strip, which is what keeps the pinned column narrow. */
.sticky-last tbody td:last-child .btn-row {
  display: grid; grid-template-columns: repeat(3, max-content);
  gap: 6px; justify-content: start;
}
.group-head {
  display: flex; align-items: center; gap: 10px; padding: 12px 20px;
  background: #fafbfc; border-bottom: 1px solid var(--border); font-weight: 600;
}
.tag-ok { background: var(--ok-soft); color: var(--ok); }
.tag-warn { background: var(--warn-soft); color: var(--warn); }
.tag-muted { background: var(--bg); color: var(--muted); }
.tag-danger { background: var(--danger-soft); color: var(--danger); }

/* Planned versus actual: which way a figure moved, not whether it is positive.
   Earning more than planned and spending more than planned are both "+". */
.money-up { color: var(--ok); font-weight: 600; }
.money-down { color: var(--danger); font-weight: 600; }

.flashes { margin-bottom: 20px; display: grid; gap: 8px; }
.flash {
  padding: 11px 15px; border-radius: 8px; border: 1px solid var(--border);
  background: var(--surface); font-size: 14px;
}
.flash-success { background: var(--ok-soft); border-color: #bfe3ce; color: var(--ok); }
.flash-warning { background: var(--warn-soft); border-color: #f0dcb4; color: var(--warn); }
.flash-error   { background: var(--danger-soft); border-color: #f3c9c5; color: var(--danger); }
.flash-info    { background: var(--accent-soft); border-color: #cfe0fb; color: var(--accent); }

/* ---------- week switcher ---------- */
/* Every part of the week switcher has a fixed footprint, so Prev and Next stay
   under the pointer as you page through weeks. The label slot is wide enough
   for the longest case (a week spanning two months, plus the badge), and the
   "This week" button keeps its place — greyed out — once you are on it. */
.weekbar { display: flex; align-items: center; gap: 8px; }
.weekbar > .btn { flex: 0 0 auto; }
.weekbar .week-slot {
  /* Fits the worst case — a week spanning two months plus the badge — in both
     languages; Russian is the wider of the two. */
  flex: 0 0 370px; width: 370px;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  white-space: nowrap; overflow: hidden;
}
.weekbar .week-name { font-weight: 600; }
.weekbar .week-jump { flex: 0 0 auto; min-width: 96px; text-align: center; }

/* The week you are actually in, so nobody reviews the wrong one by accident. */
.weekbar .week-slot.week-now {
  color: var(--accent);
  background: var(--accent-soft);
  border-radius: 8px;
}
.btn-disabled {
  opacity: .45; cursor: default; pointer-events: none;
}

@media (max-width: 720px) {
  .weekbar .week-slot { flex: 1 1 auto; width: auto; min-width: 0; }
}
.tag-now {
  background: var(--accent); color: #fff;
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .03em;
}

/* ---------- timesheet ---------- */
.entry-table td { vertical-align: middle; }
.entry-table .col-days { width: 130px; }
.entry-table .col-actions { width: 52px; }
.entry-table select, .entry-table input { margin: 0; }
.total-bar {
  display: flex; align-items: center; gap: 12px; padding: 14px 20px;
  border-top: 1px solid var(--border); background: #fafbfc;
  border-radius: 0 0 var(--radius) var(--radius);
}
.total-value { font-size: 20px; font-weight: 700; font-variant-numeric: tabular-nums; }
.empty-state { padding: 32px 20px; text-align: center; color: var(--muted); }
select.duplicate { border-color: var(--warn); background: var(--warn-soft); }

.team-row { display: flex; align-items: center; gap: 8px; padding: 9px 14px; border-bottom: 1px solid var(--border); }
.team-row:last-child { border-bottom: none; }
.team-row a { color: var(--text); flex: 1; font-size: 14px; }
.team-row.is-me { background: var(--accent-soft); }
/* The name, and under it the days that were not worked. The second line only
   exists for somebody who was away, so an ordinary week is still one line. */
.team-who { flex: 1; min-width: 0; }
.team-away { display: flex; gap: 8px; margin-top: 2px; font-size: 12px; color: var(--muted); }

/* ---------- login ---------- */
.login-card { background: var(--surface); border: 1px solid var(--border); border-radius: 14px; padding: 28px; box-shadow: var(--shadow); }
.login-card h1 { margin: 0 0 4px; font-size: 20px; }
.login-card p.sub { margin: 0 0 22px; color: var(--muted); font-size: 14px; }

/* ---------- a form that folds away ----------
   One element, two shapes: shut it is a dashed slot inviting a new record,
   open it is a working panel with an accent rail. The two states are told
   apart at a glance, so nobody types into a form thinking it is closed. */
details.editor {
  margin: 0; border-radius: var(--radius); overflow: hidden;
  transition: background .12s ease, border-color .12s ease;
}
details.editor > summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: center; gap: 10px;
  font-size: 14px; font-weight: 600;
}
details.editor > summary::-webkit-details-marker { display: none; }
details.editor > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.editor-mark {
  flex: 0 0 auto; width: 22px; height: 22px; border-radius: 6px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--accent-soft); color: var(--accent);
  font-size: 16px; font-weight: 700; line-height: 1;
}
.editor-mark::before { content: "+"; }

/* shut — a dashed slot */
details.editor:not([open]) { border: 1px dashed var(--border-strong); }
details.editor:not([open]) > summary { padding: 10px 12px; color: var(--muted); }
details.editor:not([open]):hover { border-color: var(--accent); background: var(--accent-soft); }
details.editor:not([open]):hover > summary { color: var(--accent); }

/* open — a panel, headed and railed */
details.editor[open] { border: 1px solid var(--border); border-left: 3px solid var(--accent); }
details.editor[open] > summary {
  padding: 11px 14px; color: var(--text);
  background: var(--accent-soft); border-bottom: 1px solid var(--border);
}
details.editor[open] .editor-mark { background: var(--accent); color: var(--surface); }
details.editor[open] .editor-mark::before { content: "\2212"; }  /* a real minus, not a hyphen */
details.editor[open] > form { padding: 14px; }

/* ---------- misc ---------- */
.hidden { display: none !important; }

/* ---------- summary tiles ---------- */
.stat-row {
  display: grid; gap: 12px; margin-bottom: 18px;
  grid-template-columns: repeat(auto-fit, minmax(165px, 1fr));
}
.stat {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 13px 16px; box-shadow: var(--shadow);
}
.stat-label {
  color: var(--muted); font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .05em;
}
.stat-value {
  margin-top: 5px; font-size: 20px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.stat-note { margin-top: 3px; color: var(--muted); font-size: 12px; }
.stat-accent .stat-value { color: var(--accent); }
.stat-ok .stat-value { color: var(--ok); }
.stat-warn .stat-value { color: var(--warn); }

/* ---------- a compact "parameter: value" summary ----------
   The colon comes from the stylesheet so the catalogue holds plain labels
   that can be reused as table headings without punctuation in them. */
.facts {
  margin: 0; display: grid; gap: 8px 12px;
  /* One fact per line: labels share a column so the values line up under
     each other, however long the label happens to be. */
  grid-template-columns: max-content auto;
}
/* Enough of them and one column becomes a long thin list nobody reads to the
   end of, so they run into a second and a third as the window allows. */
@media (min-width: 720px) {
  .facts { grid-template-columns: repeat(2, max-content auto); }
}
@media (min-width: 1080px) {
  .facts { grid-template-columns: repeat(3, max-content auto); }
}
/* Room between one pair and the next label, which the grid's own gap cannot
   tell apart from the space inside a pair. */
.facts .fact dd { padding-right: 26px; }
.fact { display: contents; }
.fact dt { color: var(--muted); font-size: 13px; white-space: nowrap; }
.fact dt::after { content: ":"; }
.fact dd {
  margin: 0; font-weight: 600; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.fact-note { margin-left: 6px; color: var(--muted); font-size: 12px; font-weight: 400; }

/* ---------- contract states ----------
   Six states need six looks, and there are only four colour pairs to build
   them from: two of the six are the outlined and filled versions of one. */
.state {
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
  padding: 3px 10px; border-radius: 999px; border: 1px solid transparent;
  font-size: 12px; font-weight: 600;
}
.state::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor;
}
.state-to_be_contracted { background: var(--bg); color: var(--muted); border-color: var(--border); }
.state-in_review { background: var(--warn-soft); color: var(--warn); }
.state-active { background: var(--accent-soft); color: var(--accent); }
.state-fulfilled { background: transparent; color: var(--accent); border-color: var(--accent); }
.state-accepted { background: var(--ok-soft); color: var(--ok); }
.state-paid { background: var(--ok); color: #fff; }

/* ---------- how much of a contract has arrived ---------- */
.meter {
  height: 5px; margin-top: 6px; border-radius: 999px;
  background: var(--border); overflow: hidden;
}
.meter-fill { height: 100%; border-radius: 999px; background: var(--accent); }
.meter-full .meter-fill { background: var(--ok); }
.meter-over .meter-fill { background: var(--warn); }

/* ---------- a panel nested inside a table row ---------- */
.subpanel { background: var(--bg); border-radius: var(--radius); padding: 16px; }
.subpanel > h3 { margin: 0 0 12px; font-size: 13px; color: var(--muted); }
.subpanel table {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 8px; overflow: hidden;
}
.subpanel .inline-form {
  margin-top: 14px; padding-top: 14px; border-top: 1px dashed var(--border-strong);
}

/* A cell carrying a headline with quieter lines under it: the middle one
   still reads as content, the last one as a note. */
.cell-main { font-weight: 600; }
.cell-title { margin-top: 2px; font-size: 13px; }
.cell-sub { margin-top: 2px; color: var(--muted); font-size: 12px; font-weight: 400; }
/* A comment is somebody's aside about the row, not part of its data. */
.cell-comment { font-style: italic; }

/* ---------- help ---------- */
/* Prose, unlike every other page here, so it is measured in characters rather
   than pixels: a line of running text is unreadable at the full width of a
   table. */
.help-intro { max-width: 62ch; margin: -8px 0 20px; }
.help-guide .card-body { max-width: 76ch; }
.help-lead { margin: 0 0 18px; }
.help-also { max-width: 62ch; margin: -4px 0 20px; }

.help-terms { margin: 0; padding-left: 18px; }
.help-terms li + li { margin-top: 8px; }

/* The heading of a step sits on its own line above the explanation: a reader
   scanning for the one thing they came for reads only the bold lines. */
.help-steps { margin: 0; padding-left: 22px; }
.help-steps li { margin-bottom: 16px; }
.help-steps li:last-child { margin-bottom: 0; }
.help-steps li::marker { color: var(--muted); font-variant-numeric: tabular-nums; }
.help-steps strong { display: block; margin-bottom: 2px; }
.help-steps span { color: var(--muted); }

/* Help is a resort, not a destination — it sits apart from the pages somebody
   navigates between on purpose. */
.nav a.nav-help { margin-left: 8px; color: var(--muted); }

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #14171c; --surface: #1b1f26; --border: #2a2f39; --border-strong: #3a414e;
    --text: #e7eaf0; --muted: #98a1b0; --accent: #6da3ff; --accent-soft: #1e2a3f;
    --ok: #63d199; --ok-soft: #16291f; --warn: #e8b164; --warn-soft: #2c2417;
    --danger: #f08b83; --danger-soft: #2e1b1a;
  }
  th, tfoot td, .total-bar, .group-head, .away-bar { background: #171b21; }
  tbody tr:hover { background: #1f242c; }
  .tag-supervisor { background: #2b2140; color: #c4a7f0; }
  .tag-executive { background: #16293d; color: #8fc0f0; }
  .tag-administrator { background: #33270f; color: #e0b366; }
  /* The light theme's solid green is too bright to carry white text here. */
  .state-paid { background: var(--ok-soft); color: var(--ok); border-color: var(--ok); }
  .subpanel table { background: #171b21; }
  .sticky-first thead th:first-child,
  .sticky-first tfoot td:first-child,
  .sticky-first tbody tr:hover td:first-child { background: #171b21; }
  .sticky-last thead th:last-child,
  .sticky-last tbody tr:not(.js-edit-row):hover td:last-child { background: #171b21; }
}
