/* ─────────────────────────────────────────────────────────────────────────────
   LABOUR
   Where the cost of work went, by project and by person, over the period.

   Part 15 of 16. THE ORDER OF THESE FILES IS LOAD-BEARING — the list lives in
   lib/app_css.php and this sits AFTER overview.css, which is what makes the rules
   below possible: the statement at the top of this screen is built from Overview's
   own .cf-grid / .cf-hero / .cf-status / .cf-cap / .cf-val, and this file adds
   nothing to them. It used to carry its own .lab-state-* card system — a second
   visual language inside one product, which is a product that looks unfinished
   however good either half is. Those rules are gone; what is left is the one thing
   Overview has no equivalent of.

   THE TIMELINE IS THAT ONE THING. A shared time axis with a row per project or per
   person. It is the reason this screen exists and the only part that needed new CSS.

   PHONE FIRST: the axis survives at every width, because a shared axis is the whole
   idea; what gives way is the row's secondary figures.

   EVERY CLASS IS cal-* / lab-*.
   ───────────────────────────────────────────────────────────────────────────── */

/* the boards carry their own padding, so a note sits inside the body's rhythm */
.lab-note {
    margin: 0; padding: 14px var(--space-6) 18px;
    font-size: 12px; line-height: var(--leading-relaxed); color: var(--text-muted); max-width: 82ch;
}

/* ── THE READING ──────────────────────────────────────────────────────────── */
.lab-ai-body { margin: 0 0 12px; font-size: 13px; line-height: var(--leading-relaxed); color: var(--text-muted); }
.lab-ai-read { display: block; color: var(--text-main); }
/* the thing to watch is set off, because it is the one line asking for a decision */
.lab-ai-watch { display: block; margin-top: 9px; padding-left: 12px; border-left: 2px solid var(--divider-strong); }
.lab-ai-body--warn { color: var(--warning-yellow); }
.cal-ai-btn {
    border: 1px solid var(--divider); border-radius: var(--radius-pill); background: transparent;
    font: inherit; font-size: 11.5px; color: var(--text-main);
    padding: 6px 15px; cursor: pointer; transition: border-color .18s ease;
}
.cal-ai-btn:hover:not([disabled]) { border-color: var(--divider-strong); }
.cal-ai-btn[disabled] { opacity: 0.5; cursor: default; }

/* ── THE TIMELINE ────────────────────────────────────────────────────────────
   Row = a project or a person. Track = the period, one cell per bucket. The bar
   behind the cells is the row's share of the largest row, so the eye ranks the rows
   before reading a figure; the cells say when. Figures take Overview's figure-unit
   weight rather than a second type scale. */
.lab-table { padding: 0 var(--space-6); }
.lab-row {
    display: grid; grid-template-columns: minmax(150px, 1.7fr) minmax(0, 3fr) 116px 66px 78px;
    align-items: center; gap: 14px;
    padding: 12px 0; border-bottom: 1px solid var(--divider);
    transition: background .15s ease;
}
.lab-row:last-child { border-bottom: none; }
.lab-row--head {
    padding: 10px 0 8px;
    font-size: 10.5px; letter-spacing: var(--tracking-caps); text-transform: uppercase;
    font-weight: var(--fw-medium); color: var(--text-muted);
}
/* the row nothing carries sits with the others and is marked, never hidden or sorted
   away — it is the finding, not an exception to tidy up */
.lab-row--none { background: var(--active-theme-bg); }
/* a row that opens something says so before it is clicked */
.lab-row[data-entry] { cursor: pointer; }
.lab-row[data-entry]:hover { background: var(--active-theme-bg); }
.lab-row[data-entry]:focus-visible { outline: 2px solid var(--text-main); outline-offset: -2px; }

/* THE FOOT. It must equal the statement above it, and it says whether it does — a
   costing screen whose parts do not add to its own headline has to be checked
   somewhere else, which is the same as not being trusted. */
.lab-row--foot { border-bottom: none; border-top: 1px solid var(--divider-strong); }
.lab-row--foot .lab-name b {
    font-size: 10.5px; letter-spacing: var(--tracking-caps); text-transform: uppercase;
    font-weight: var(--fw-medium); color: var(--text-muted);
}
.lab-row--bad .lab-name b, .lab-row--bad .lab-fig { color: var(--danger-red); }

.lab-name { display: flex; align-items: baseline; gap: 8px; min-width: 0; flex-wrap: wrap; }
.lab-chip { width: 8px; height: 8px; border-radius: 2px; flex: 0 0 auto; align-self: center; }
.lab-name b {
    font-size: 13px; font-weight: var(--fw-regular); color: var(--text-main);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
.lab-name i {
    font-size: 10px; font-style: normal; letter-spacing: var(--tracking-caps);
    text-transform: uppercase; color: var(--text-muted);
}

/* 16px, not the full row height. At full height the cells read as solid blocks and the
   strip stopped being a distribution and started being a bar; a heat strip has to be
   thinner than the row it sits in for the eye to read across it. */
.lab-track { position: relative; display: flex; gap: 2px; align-items: stretch; height: 16px; min-width: 0; }
.lab-bar {
    position: absolute; left: 0; top: 50%; transform: translateY(-50%);
    height: 3px; border-radius: 2px; opacity: 0.22; pointer-events: none;
}
.lab-cell { position: relative; flex: 1 1 0; min-width: 0; border-radius: 2px; }
/* inside the span but with nothing in it still reads as "this was running" */
.lab-cell--span { background: var(--divider); }
.lab-fill { position: absolute; inset: 0; border-radius: 2px; }
.lab-tick { flex: 1 1 0; min-width: 0; text-align: center; font-size: 8.5px; overflow: hidden; white-space: nowrap; }
.lab-row--head .lab-track { height: auto; }

/* the money column takes Overview's figure-unit weight; the ratios stay muted */
.lab-fig {
    font-size: 14px; font-weight: var(--fw-bold); color: var(--text-main);
    text-align: right; white-space: nowrap;
    font-variant-numeric: tabular-nums; letter-spacing: var(--tracking-tight);
}
.lab-fig--dim { font-size: 12px; font-weight: var(--fw-regular); color: var(--text-muted); letter-spacing: 0; }
.lab-row--head .lab-fig { font-size: 10.5px; font-weight: var(--fw-medium); color: var(--text-muted); letter-spacing: var(--tracking-caps); }

/* the readout answers "what is that cell?" — a title attribute is not an answer on a
   touch screen — and it holds its height so the table never shifts under the pointer */
.lab-readout { min-height: 34px; }
.lab-readout b { color: var(--text-main); font-weight: var(--fw-semibold); }

/* PHONE: the axis survives, the figures move under the name. A timeline whose axis
   collapses is a table, and a table of labour by month is what this replaced. */
@media (max-width: 759px) {
    .lab-table { padding: 0 var(--space-4); }
    .lab-row { grid-template-columns: 1fr auto; gap: 4px 10px; }
    .lab-track { grid-column: 1 / -1; order: 3; }
    .lab-fig { order: 2; }
    .lab-fig--dim { display: none; }
    .lab-note { padding-left: var(--space-4); padding-right: var(--space-4); }
}

/* ── the calendar ─────────────────────────────────────────────────────────── */
.cal-wrap { padding: var(--space-4) var(--space-6) var(--space-2); }
.cal-grid-head, .cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
.cal-grid-head {
    margin-bottom: 6px; font-size: 9.5px; letter-spacing: var(--tracking-caps);
    text-transform: uppercase; color: var(--text-muted); text-align: center;
}
.cal-day {
    position: relative; min-height: 64px; padding: 6px;
    border: 1px solid var(--divider); border-radius: var(--radius-sm); background: var(--bg-card);
    display: flex; flex-direction: column; gap: 4px;
}
.cal-day--pad { border-color: transparent; background: transparent; }
.cal-day--empty { background: transparent; }
.cal-day--today { border-color: var(--text-main); }
.cal-num { font-size: 11px; color: var(--text-muted); }
.cal-day--today .cal-num { color: var(--text-main); font-weight: var(--fw-semibold); }
.lab-day-v { font-size: 11px; font-weight: var(--fw-semibold); color: var(--text-main); font-variant-numeric: tabular-nums; }
.lab-day-bar { margin-top: auto; height: 4px; border-radius: 2px; background: var(--divider); overflow: hidden; }
.lab-day-bar > span { display: block; height: 100%; background: var(--text-main); }

@media (min-width: 760px) {
    .cal-day { min-height: 88px; padding: 8px; }
    .cal-num { font-size: 12px; }
    .lab-day-v { font-size: 12px; }
}

/* ── THE ASKING TREE ─────────────────────────────────────────────────────────
   Drawn in the LOGIC VIEW'S connectors, not a third set of its own: .lg-branch,
   .lg-kids and .lg-node come from logic.css, which loads before this file, so the
   spine down each branch and the generously rounded elbow on each child are the
   ones that screen already established. A conversation that branches is the same
   claim a decomposition tree makes — "this follows from that" — and it should not
   be drawn in a different hand.

   Only the INSIDE of a node is new. .lg-node is a one-line flex row built for a
   label and a figure; a turn is a question, an answer, its evidence and its
   actions, so it stacks. */
.aiq-tree { margin-bottom: 4px; }
.lg-node--ai {
    display: flex; align-items: flex-start; gap: 10px;
    padding: 12px 14px; cursor: default; text-align: left;
}
.lg-node--ai:hover { border-color: var(--divider); }
.lg-node--ai .lg-tick { height: 16px; margin-top: 2px; }
.aiq-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 6px; }

.aiq-q { font-size: 12.5px; font-weight: var(--fw-semibold); color: var(--text-main); }
.aiq-a { font-size: 12.5px; line-height: var(--leading-relaxed); color: var(--text-muted); }
/* the thing to watch is the one line asking for a decision, so it is set off */
.aiq-w {
    font-size: 12px; line-height: var(--leading-relaxed); color: var(--text-muted);
    padding-left: 10px; border-left: 2px solid var(--divider-strong);
}
/* THE EVIDENCE, ON THE NODE. What the ledger said at the moment this turn was asked —
   without it the tree is a pile of opinions. */
.aiq-meta {
    display: flex; flex-wrap: wrap; gap: 4px 12px;
    font-size: 9.5px; letter-spacing: var(--tracking-caps); text-transform: uppercase;
    color: var(--text-muted); font-variant-numeric: tabular-nums;
}
.aiq-ev { color: var(--text-main); }

.aiq-acts { display: flex; align-items: center; gap: 12px; margin-top: 2px; }
.aiq-act {
    border: 0; background: transparent; padding: 0; font: inherit;
    font-size: 10.5px; letter-spacing: var(--tracking-caps); text-transform: uppercase;
    color: var(--text-muted); cursor: pointer; text-decoration: underline;
    text-underline-offset: 3px; text-decoration-color: var(--divider-strong);
}
.aiq-act:hover { color: var(--text-main); }
.aiq-n { font-size: 9.5px; letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--text-muted); }

/* the question box hangs off the branch it will belong to, so where you are asking
   FROM is never in doubt */
.aiq-box { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 8px 0 4px; }
.aiq-input {
    flex: 1 1 240px; min-width: 0;
    border: 1px solid var(--divider); border-radius: var(--radius-pill);
    background: var(--bg-card); font: inherit; font-size: 12.5px; color: var(--text-main);
    padding: 8px 14px;
}
.aiq-input:focus { outline: none; border-color: var(--text-main); }

.aiq-foot { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 10px; }
.aiq-note { font-size: 11px; color: var(--text-muted); }

/* THE FETCH TRAIL. Each lookup the model went and ran, named, in order. Deliberately
   quiet — it is provenance, not a result — but never hidden, because "the AI looked it
   up" is otherwise a claim the reader has to take on trust. */
.aiq-trail { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; margin-top: 2px; }
.aiq-trail-cap {
    font-size: 9px; letter-spacing: var(--tracking-caps); text-transform: uppercase;
    color: var(--text-muted);
}
.aiq-trail-i {
    font-size: 9.5px; letter-spacing: var(--tracking-caps); text-transform: uppercase;
    color: var(--text-muted); border: 1px solid var(--divider); border-radius: var(--radius-pill);
    padding: 2px 8px; white-space: nowrap;
}

/* ═══════════════════════════════════════════════ THE TIMESHEET ═══════════════
   MARKING TIME, AND WHAT MARKING IT IS WORTH.

   The bar takes its shape from what the market's time tools get right (Toggl, Harvest):
   logging has to cost nothing or the timesheet does not exist. So it is ONE ROW, always
   visible, with the hours field as the target — Return there logs and returns the cursor
   to it, and WHO and WHAT survive between entries. Five entries is five numbers.

   Everything below borrows the type scale already on this screen — .lab-fig's weights,
   .cf-cap's tracked caps, .lab-chip's colour mark — because a second visual language
   inside one product is a product that looks unfinished however good either half is.
   ───────────────────────────────────────────────────────────────────────────── */
.ts-wrap { padding: var(--space-5) var(--space-6) var(--space-6); }

/* ── THE DOCK ─────────────────────────────────────────────────────────────────
   STICKY, because scrolling the timesheet to check what you already logged must not
   cost you the thing you were about to log — the exact friction that makes a separate
   "add time" page lose to a bar that is always in reach. 68px clears the fixed top bar.

   The board around it needs `overflow: clip`, not `hidden`: both clip the rounded
   corners, but `hidden` makes the board a scroll container, and a sticky child inside a
   container that never scrolls never sticks. See views/calendar.php. */
.lab-board--dock { overflow: clip; }

/* `top` is overwritten by dockTop() in js/views/calendar.js, which measures the fixed
   chrome above it; this value is only what applies before that runs. z-index stays UNDER
   the period control's 20 — the dock is this screen's tool, that is the app's, and a
   panel that covers the global controls to keep itself visible has the priority the
   wrong way round. */
.ts-dock {
    position: sticky; top: 96px; z-index: 6;
    margin: 0 0 var(--space-6);
    padding: 14px 14px 12px;
    border: 1px solid var(--divider); border-radius: var(--radius-sm);
    background: var(--bg-card);
    box-shadow: 0 1px 2px rgba(0,0,0,.04), 0 8px 24px -14px rgba(0,0,0,.18);
}

/* THE WEIGHTS MATCH THE USE. One control changes on every entry and four barely change
   at all, so the number gets the display size and its own row, the context gets field
   size, and one tall target commits. A row of seven equal fields — the first version —
   is a form, and a form is a thing you fill in once. */
.ts-bar {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-rows: auto auto;
    gap: 10px 16px; align-items: center;
}

/* ── the instrument ────────────────────────────────────────────────────────── */
.ts-hrs {
    grid-column: 1; grid-row: 1;
    display: inline-flex; align-items: center; gap: 2px;
    padding: 3px 5px; border: 1px solid var(--divider); border-radius: var(--radius-sm);
    background: var(--bg-main);
    transition: border-color .16s ease;
}
.ts-hrs:focus-within { border-color: var(--text-main); }
.ts-hrs-in {
    width: 84px; padding: 2px 0; border: 0; background: transparent; text-align: right;
    font: inherit; font-size: 27px; font-weight: var(--fw-bold); line-height: 1.15;
    color: var(--text-main); letter-spacing: var(--tracking-tight);
}
.ts-hrs-in:focus { outline: none; }
.ts-hrs-in::placeholder { color: var(--divider-strong); }
.ts-hrs-u { padding: 0 9px 0 3px; font-size: 13px; color: var(--text-muted); }
.ts-step {
    display: grid; place-items: center; width: 30px; height: 30px;
    border: 0; border-radius: var(--radius-sm); background: transparent;
    font: inherit; font-size: 17px; line-height: 1; color: var(--text-muted);
    cursor: pointer; transition: background .15s ease, color .15s ease;
}
.ts-step:hover { background: var(--active-theme-bg); color: var(--text-main); }

/* the durations a studio actually logs — they ADD, so +4h twice is a working day */
.ts-quick { grid-column: 1; grid-row: 2; display: flex; gap: 5px; }
.ts-q {
    padding: 5px 9px; border: 1px solid var(--divider); border-radius: 999px;
    background: transparent; font: inherit; font-size: 11px; color: var(--text-muted);
    cursor: pointer; font-variant-numeric: tabular-nums;
    transition: border-color .15s ease, color .15s ease;
}
.ts-q:hover { border-color: var(--text-main); color: var(--text-main); }

/* ── the context, which survives between entries ───────────────────────────── */
.ts-ctx { grid-column: 2; grid-row: 1; display: flex; align-items: center; gap: 8px; min-width: 0; }
.ts-sel {
    min-width: 0; padding: 9px 11px; font: inherit; font-size: 12.5px;
    border: 1px solid var(--divider); border-radius: var(--radius-sm);
    background: var(--bg-main); color: var(--text-main);
}
.ts-sel:focus { outline: none; border-color: var(--text-main); }
.ts-sel--who { flex: 0 1 190px; }
.ts-ctx > select:not(.ts-sel--who) { flex: 1 1 auto; }
.ts-sel--day { flex: 0 0 auto; }

.ts-note {
    grid-column: 2; grid-row: 2; min-width: 0;
    padding: 8px 11px; font: inherit; font-size: 12.5px;
    border: 1px solid var(--divider); border-radius: var(--radius-sm);
    background: var(--bg-main); color: var(--text-main);
}
.ts-note:focus { outline: none; border-color: var(--text-main); }

.ts-bill {
    display: inline-flex; align-items: center; gap: 8px; flex: 0 0 auto;
    padding: 9px 13px; border: 1px solid var(--divider); border-radius: var(--radius-sm);
    background: var(--bg-card); font: inherit; font-size: 12px; color: var(--text-muted);
    cursor: pointer; white-space: nowrap;
    transition: border-color .16s ease, color .16s ease;
}
.ts-bill.is-on { border-color: var(--text-main); color: var(--text-main); }
.ts-box {
    display: grid; place-items: center; width: 15px; height: 15px; border-radius: 4px;
    border: 1.5px solid var(--divider-strong); font-size: 10px; line-height: 1;
}
.ts-bill.is-on .ts-box { background: var(--text-main); border-color: var(--text-main); color: var(--bg-card); }

/* ── one tall target, and it names its own shortcut ────────────────────────── */
.ts-go {
    grid-column: 3; grid-row: 1 / 3;
    display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
    min-width: 96px; align-self: stretch; padding: 12px 20px;
    border: 1px solid var(--text-main); border-radius: var(--radius-sm);
    background: var(--text-main); color: var(--bg-card);
    font: inherit; font-size: 13px; font-weight: var(--fw-semibold);
    cursor: pointer; transition: opacity .16s ease;
}
.ts-go:hover:not([disabled]) { opacity: .88; }
.ts-go[disabled] { opacity: .45; cursor: default; }
.ts-go kbd {
    font: inherit; font-size: 10px; line-height: 1; padding: 3px 6px;
    border-radius: 5px; background: rgba(255,255,255,.18); opacity: .85;
}

/* ── the entry, read back before it exists ─────────────────────────────────── */
.ts-prev {
    margin: 12px 2px 0; padding-top: 11px; border-top: 1px solid var(--divider);
    font-size: 12px; line-height: 1.5; color: var(--text-main);
}
.ts-prev b { font-weight: var(--fw-semibold); }
.ts-prev-s { color: var(--divider-strong); padding: 0 3px; }
.ts-prev-w { font-variant-numeric: tabular-nums; }
.ts-prev--hint { color: var(--text-muted); }

.ts-msg { min-height: 0; margin: 8px 2px 0; font-size: 11.5px; color: var(--text-muted); }
.ts-msg:empty { display: none; }
.ts-msg b { color: var(--text-main); font-weight: var(--fw-semibold); }
.ts-undo {
    border: 0; background: transparent; font: inherit; font-size: 11.5px;
    color: var(--text-main); text-decoration: underline; cursor: pointer; padding: 0 0 0 6px;
}
/* ── worth beside paid ─────────────────────────────────────────────────────── */
.ts-table { margin-top: var(--space-6); }
.ts-row {
    display: grid; grid-template-columns: minmax(160px, 2.4fr) 84px 84px 108px 108px;
    align-items: center; gap: 14px;
    padding: 11px 0; border-bottom: 1px solid var(--divider);
}
.ts-row:last-child { border-bottom: none; }
.ts-row--head {
    padding: 8px 0; font-size: 10.5px; letter-spacing: var(--tracking-caps);
    text-transform: uppercase; font-weight: var(--fw-medium); color: var(--text-muted);
}
.ts-row[role="button"] { cursor: pointer; }
.ts-row[role="button"]:hover { background: var(--active-theme-bg); }
.ts-name { display: flex; align-items: center; gap: 8px; min-width: 0; }
.ts-name b { font-size: 13px; font-weight: var(--fw-semibold); color: var(--text-main);
             overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ts-name i { font-style: normal; font-size: 10.5px; color: var(--text-muted); white-space: nowrap; }
.ts-fig {
    font-size: 14px; font-weight: var(--fw-bold); color: var(--text-main); text-align: right;
    font-variant-numeric: tabular-nums; letter-spacing: var(--tracking-tight); white-space: nowrap;
}
.ts-fig--dim { font-size: 12px; font-weight: var(--fw-regular); color: var(--text-muted); letter-spacing: 0; }
/* A CLAIM IS NOT A FACT, and the column says so before the caption is read: the worth
   of logged hours wears the muted weight, the ledger's figure wears the full one. */
.ts-fig--claim { font-weight: var(--fw-medium); color: var(--text-muted); }
.ts-row--head .ts-fig { font-size: 10.5px; font-weight: var(--fw-medium); color: var(--text-muted); letter-spacing: var(--tracking-caps); }

/* the + that brings a row to the bar — quiet until the row is under the pointer */
.ts-plus {
    flex: 0 0 auto; display: grid; place-items: center; width: 20px; height: 20px;
    border: 1px solid var(--divider); border-radius: 999px; background: transparent;
    font: inherit; font-size: 13px; line-height: 1; color: var(--text-muted);
    cursor: pointer; opacity: 0; transition: opacity .16s ease, border-color .16s ease, color .16s ease;
}
.lab-row:hover .ts-plus, .ts-row:hover .ts-plus,
.ts-plus:focus-visible { opacity: 1; }
.ts-plus:hover { border-color: var(--text-main); color: var(--text-main); }
@media (hover: none) { .ts-plus { opacity: .55; } }

/* ── what is actually in there ─────────────────────────────────────────────── */
.ts-log { margin-top: var(--space-6); }
.ts-log-cap {
    font-size: 10.5px; letter-spacing: var(--tracking-caps); text-transform: uppercase;
    color: var(--text-muted); padding-bottom: 8px;
}
.ts-e {
    display: grid; grid-template-columns: 96px minmax(0, 1.5fr) minmax(0, 2fr) 88px 60px 26px;
    align-items: center; gap: 12px;
    padding: 9px 0; border-bottom: 1px solid var(--divider); font-size: 12px;
}
.ts-e:last-child { border-bottom: none; }
.ts-e-d { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.ts-e-w { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.ts-e-w b { font-size: 12.5px; font-weight: var(--fw-semibold); color: var(--text-main);
            overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ts-e-w i { font-style: normal; font-size: 10.5px; color: var(--text-muted);
            overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ts-e-n { color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ts-e-b { font-size: 10px; letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--text-muted); }
.ts-e-b.is-on { color: var(--text-main); }
.ts-e-h { text-align: right; font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; }
.ts-e-x {
    border: 0; background: transparent; font: inherit; font-size: 15px; line-height: 1;
    color: var(--text-muted); cursor: pointer; opacity: 0; transition: opacity .16s ease, color .16s ease;
}
.ts-e:hover .ts-e-x, .ts-e-x:focus-visible { opacity: 1; }
.ts-e-x:hover { color: var(--danger-red); }

/* ── HOW IT WAS ENGAGED ───────────────────────────────────────────────────────
   Contractor against payroll against the employer's own MPF, off the account codes.
   One bar, because the question is a proportion; three figures in a row would invite
   subtraction instead of comparison. */
.lab-mix { padding: 0 var(--space-6) var(--space-5); }
.lab-mix-bar {
    display: flex; height: 6px; border-radius: 999px; overflow: hidden;
    background: var(--divider); margin-bottom: 12px;
}
.lab-mix-seg { display: block; min-width: 2px; }
.lab-mix-keys { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 20px; }
.lab-mix-cap {
    font-size: 10.5px; letter-spacing: var(--tracking-caps); text-transform: uppercase;
    color: var(--text-muted);
}
.lab-mix-key { display: inline-flex; align-items: baseline; gap: 7px; cursor: pointer; }
.lab-mix-key b { font-size: 12px; font-weight: var(--fw-medium); color: var(--text-main); }
.lab-mix-key i { font-style: normal; font-size: 12px; font-weight: var(--fw-semibold);
                 color: var(--text-main); font-variant-numeric: tabular-nums; }
.lab-mix-key u { text-decoration: none; font-size: 11px; color: var(--text-muted);
                 font-variant-numeric: tabular-nums; }
.lab-mix-key:hover b, .lab-mix-key:hover u { color: var(--text-main); }

/* PHONE: the bar becomes a stack and the tables drop their thinnest columns. A logging
   row that needs a mouse to reach its own button is a logging row nobody uses on the
   device they are standing up with. */
@media (max-width: 900px) {
    .ts-bar { grid-template-columns: 1fr 1fr; }
    .ts-f--note { grid-column: 1 / -1; }
    .ts-go { grid-column: 1 / -1; }
    .ts-row { grid-template-columns: minmax(0, 2fr) 66px 92px; }
    .ts-row .ts-fig:nth-of-type(2) { display: none; }
    .ts-e { grid-template-columns: 76px minmax(0, 1fr) 52px 22px; }
    .ts-e-n, .ts-e-b { display: none; }
}

/* ═══════════════════════════════════════════ WHAT JUST HAPPENED ══════════════
   The timesheet answers a write by re-reading the server and redrawing everything, which
   is correct and completely silent: the row you just created looks exactly like the forty
   above it. These say what changed, once, and then stop.

   Nothing here moves a figure or delays a control — the entry is already saved by the
   time any of it runs. */
@keyframes ts-land {
    0%   { opacity: 0; transform: translateY(-6px); }
    60%  { opacity: 1; }
    100% { opacity: 1; transform: none; }
}
@keyframes ts-flash {
    0%   { background: var(--active-theme-bg); }
    100% { background: transparent; }
}
/* the newest entry is the one at the top, and it is the one that just arrived */
/* `backwards`, never `both`. A suspended animation — a background tab pauses them the
   same way it pauses rAF — holds whatever the fill says, and a `to` fill of the flash
   would hold a highlight on screen for ever. `backwards` only covers the delay. */
.ts-log .ts-e:first-child {
    animation: ts-land .34s cubic-bezier(.22, 1, .36, 1) backwards,
               ts-flash 1.1s ease-out .34s backwards;
}
/* the rest of the list settles behind it rather than snapping into place */
.ts-log .ts-e:nth-child(2) { animation: ts-land .3s cubic-bezier(.22,1,.36,1) 40ms backwards; }
.ts-log .ts-e:nth-child(3) { animation: ts-land .3s cubic-bezier(.22,1,.36,1) 70ms backwards; }

/* the read-back line changes on every keystroke, so it may not draw attention to itself —
   a colour transition only, and none of the movement the rows get */
.ts-prev { transition: color .18s ease; }
.ts-prev-w { transition: color .18s ease; }

/* the reconciliation rows arrive with the tab */
.ts-table .ts-row:not(.ts-row--head) { animation: ts-land .3s cubic-bezier(.22,1,.36,1) backwards; }
.ts-table .ts-row:nth-child(2)  { animation-delay: 0ms; }
.ts-table .ts-row:nth-child(3)  { animation-delay: 24ms; }
.ts-table .ts-row:nth-child(4)  { animation-delay: 46ms; }
.ts-table .ts-row:nth-child(5)  { animation-delay: 64ms; }
.ts-table .ts-row:nth-child(n+6) { animation-delay: 78ms; }

/* the engagement bar draws itself from the left, once, when the period changes */
@keyframes lab-mix-grow { from { transform: scaleX(0); } to { transform: none; } }
.lab-mix-bar { transform-origin: left center; animation: lab-mix-grow .5s cubic-bezier(.22,1,.36,1) backwards; }

/* the docked bar lifts as it leaves the flow — the only cue that it is now floating */
.ts-dock { transition: box-shadow .2s ease, border-color .2s ease; }

@media (prefers-reduced-motion: reduce) {
    .ts-log .ts-e, .ts-table .ts-row, .lab-mix-bar { animation: none; }
    .ts-dock, .ts-prev, .ts-prev-w { transition: none; }
}

/* ── THE BREAKDOWN, INSIDE THE TIMESHEET ──────────────────────────────────────
   Subordinate, and it has to look it. A second .board with its own h3 gave three cuts
   of one subject the same weight as the subject; a hairline, an h4 and a segmented
   control say "still the timesheet, seen another way" without a word. */
.lab-sub { border-top: 1px solid var(--divider); margin-top: var(--space-2); }
.lab-sub-head {
    display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
    padding: var(--space-5) var(--space-6) var(--space-2);
}
.lab-sub-titles { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.lab-sub-title {
    margin: 0; font-size: 11.5px; font-weight: var(--fw-semibold);
    letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--text-main);
}
.lab-sub-tools { display: flex; align-items: center; gap: 10px; margin-left: auto; flex-wrap: wrap; }

@media (max-width: 759px) {
    .lab-sub-head { padding-left: var(--space-4); padding-right: var(--space-4); }
    .lab-sub-tools { margin-left: 0; width: 100%; }
}
