/* ============================================================
   TLC BIM Hub — Worklog
   Written for this app specifically. The previous sheet was lifted from
   bim-manage: 2,100 lines / 80KB, most of it CSS for Finance / GMC / Kanban /
   LopRevit — none of which exists here.

   The principle: a tool used every day has to be scannable at a glance.
   Few borders, few colours, legible text. A border appears only on the cell
   being edited.
   ============================================================ */

/* The app opens at 110% (Dat, 04/09/2026: "tăng giao diện mặc định của nó là
   110% lúc bật lun"). It is browser zoom, applied by the page itself rather than
   left to whoever remembers to press Ctrl+plus — the screens this is read on are
   1080p at arm's length and the default 100% was being zoomed by hand every
   morning.

   Kept as a variable because everything measured against the VIEWPORT has to be
   divided by it: `zoom` scales the box but not the meaning of 100vh, so a body
   asking for 100vh inside a 1.1 zoom asks for 110% of the window and puts a
   scrollbar on every page. Every vh/vw below is written `/ var(--ui-zoom)` for
   that reason. Browser zoom still works on top of this, as it always did. */
/* Printing (07/09/2026). "Export PDF" is the browser's own print dialog, so the
   page has to be worth printing: the app's chrome — the tab bar, the toolbar,
   the scan and share buttons, the week picker — is navigation, and navigation on
   paper is ink spent on things nobody can click. The report itself is left
   alone; the board brings its own print rules. */
@media print {
  body { zoom: 1; background: #fff; }
  .tlc-top, .cl-toolbar, .ib-weeks, .ib-pills, .toast, #login { display: none !important; }
  #view { padding: 0 !important; }
}

:root {
  --ui-zoom:   1.1;
  --ink:       #12171C;
  --ink-2:     #4C5761;
  /* --ink-3 carries real information (the Project and Person columns, the column
     headers) so it has to reach 4.5 contrast on white — the first pass used
     #7B8590, which only managed 3.75. */
  --ink-3:     #646E79;
  --ink-4:     #98A1AA;

  /* Light grey PAGE background + white cards: the layering comes from the
     background colour itself, no drop shadows needed. This is how spreadsheets
     and Notion separate a data region from its surroundings. */
  --bg:        #F4F6F8;
  /* A multi-colour mesh background (indigo/blue/purple/teal) so the glass surface catches light */
  --bg-grad:   radial-gradient(820px 680px at 4% -4%, rgba(99,102,241,.26), transparent 56%),
               radial-gradient(760px 620px at 98% 2%, rgba(56,189,248,.22), transparent 55%),
               radial-gradient(720px 680px at 82% 108%, rgba(139,92,246,.18), transparent 55%),
               radial-gradient(680px 640px at 12% 112%, rgba(45,212,191,.14), transparent 55%),
               #EBEEF6;
  --card-solid:#FFFFFF;              /* SOLID background — for the donut hole and anywhere that must block what's behind */
  --card:      rgba(255,255,255,.64);/* frosted glass — denser so text stands out */
  --head:      rgba(255,255,255,.5);
  --hover:     rgba(255,255,255,.7);
  --rule:      #E4E8EA;
  --rule-2:    #CBD2D7;
  --glass-brd:    rgba(255,255,255,.8);   /* the bright edge of the glass */
  --glass-hi:     rgba(255,255,255,.95);  /* the thin highlight along the top */
  --glass-sheen:  rgba(255,255,255,.5);   /* the top-lit sheen that makes it read as glass */
  --glass-shadow: rgba(49,46,129,.22);    /* the raised shadow that gives depth */

  /* Palette taken from tlc-revit-addin-report.pages.dev (the page Dat built
     himself, adopted as the standard on 16/07): indigo #27226E + blue #4f6fd9,
     with orange as the accent. */
  --brand:     #27226E;
  --brand2:    #4F6FD9;
  --orange:    #E8541E;
  --accent:    #27226E;
  --accent-fg: #FFFFFF;
  --accent-soft: rgba(39, 34, 110, .08);

  --done:      #067647;
  --done-bg:   #E8F5EF;
  --doing:     #B45309;
  --doing-bg:  #FDF3E7;
  --pending:   #64748B;
  --pending-bg:#F1F3F5;
  --danger:    #B42318;
  --danger-bg: #FBEAE8;

  --font: "Segoe UI", system-ui, -apple-system, "Helvetica Neue", sans-serif;
  --mono: "Consolas", "Cascadia Mono", ui-monospace, Menlo, monospace;

  --r: 6px;

  /* ===== Type scale (17/08/2026) =====
     Measured before: 96% of the font-size declarations in this file sat between
     9px and 15px — 192 of them, in eleven half-pixel steps. With nothing large,
     nothing reads as important, which is precisely why the screen looked flat.
     Four steps now, and the hours are the one big thing on the page.
     Applied to the screens rebuilt on 17/08 (Time Sheet, Week Plan) — the clash /
     model / issue screens keep their own density and are untouched. */
  --fs-label: 10.5px;   /* mono, uppercase, letterspaced — the small print */
  --fs-meta:  11.5px;   /* secondary figures beside a value */
  --fs-body:  13.5px;   /* everything you actually read */
  --fs-lead:  17px;     /* the heading of a block */
  --fs-hero:  42px;     /* the one number the screen exists to answer */
  --ls-label: .12em;
}

@media (prefers-color-scheme: dark) {
  :root {
        --ink:#E9EDF0; --ink-2:#A6B0B8; --ink-3:#868F97; --ink-4:#69737B;
    --bg:#0D1014;
    --bg-grad: radial-gradient(820px 680px at 4% -4%, rgba(99,102,241,.34), transparent 56%),
               radial-gradient(760px 620px at 98% 2%, rgba(56,189,248,.20), transparent 55%),
               radial-gradient(720px 680px at 82% 108%, rgba(168,85,247,.22), transparent 55%),
               radial-gradient(680px 640px at 12% 112%, rgba(20,184,166,.16), transparent 55%),
               #080A0F;
    --card-solid:#171B20;
    --card:rgba(30,36,46,.60); --head:rgba(40,47,58,.54); --hover:rgba(255,255,255,.1);
    --rule:#2C3238; --rule-2:#3D454C;
    --glass-brd:rgba(255,255,255,.16); --glass-hi:rgba(255,255,255,.14); --glass-sheen:rgba(255,255,255,.1); --glass-shadow:rgba(0,0,0,.6);
    --brand:#8FA3F0; --brand2:#4F6FD9; --orange:#F07A4A;
    --accent:#4A63C9; --accent-fg:#FFFFFF; --accent-soft:rgba(74,99,201,.18);
    --done:#4ABF87; --done-bg:#12291F;
    --doing:#E09A4C; --doing-bg:#2C2317;
    --pending:#8B96A2; --pending-bg:#222831;
    --danger:#F0796B; --danger-bg:#2B1A18;
  }
}
:root[data-theme="dark"] {
    --ink:#E9EDF0; --ink-2:#A6B0B8; --ink-3:#868F97; --ink-4:#69737B;
  --bg:#0D1014;
  --bg-grad: radial-gradient(820px 680px at 4% -4%, rgba(99,102,241,.34), transparent 56%),
             radial-gradient(760px 620px at 98% 2%, rgba(56,189,248,.20), transparent 55%),
             radial-gradient(720px 680px at 82% 108%, rgba(168,85,247,.22), transparent 55%),
             radial-gradient(680px 640px at 12% 112%, rgba(20,184,166,.16), transparent 55%),
             #080A0F;
  --card-solid:#171B20;
  --card:rgba(30,36,46,.60); --head:rgba(40,47,58,.54); --hover:rgba(255,255,255,.1);
  --rule:#2C3238; --rule-2:#3D454C;
  --glass-brd:rgba(255,255,255,.16); --glass-hi:rgba(255,255,255,.14); --glass-sheen:rgba(255,255,255,.1); --glass-shadow:rgba(0,0,0,.6);
  --brand:#8FA3F0; --brand2:#4F6FD9; --orange:#F07A4A;
  --accent:#4A63C9; --accent-fg:#FFFFFF; --accent-soft:rgba(74,99,201,.18);
  --done:#4ABF87; --done-bg:#12291F;
  --doing:#E09A4C; --doing-bg:#2C2317;
  --pending:#8B96A2; --pending-bg:#222831;
  --danger:#F0796B; --danger-bg:#2B1A18;
}
:root[data-theme="light"] {
  --ink:#12171C; --ink-2:#4C5761; --ink-3:#646E79; --ink-4:#98A1AA;
  --bg:#F4F6F8;
  --bg-grad: radial-gradient(820px 680px at 4% -4%, rgba(99,102,241,.26), transparent 56%),
             radial-gradient(760px 620px at 98% 2%, rgba(56,189,248,.22), transparent 55%),
             radial-gradient(720px 680px at 82% 108%, rgba(139,92,246,.18), transparent 55%),
             radial-gradient(680px 640px at 12% 112%, rgba(45,212,191,.14), transparent 55%),
             #EBEEF6;
  --card-solid:#FFFFFF;
  --card:rgba(255,255,255,.64); --head:rgba(255,255,255,.5); --hover:rgba(255,255,255,.7);
  --rule:#E4E8EA; --rule-2:#CBD2D7;
  --glass-brd:rgba(255,255,255,.8); --glass-hi:rgba(255,255,255,.95); --glass-sheen:rgba(255,255,255,.5); --glass-shadow:rgba(49,46,129,.22);
  --brand:#27226E; --brand2:#4F6FD9; --orange:#E8541E;
  --accent:#27226E; --accent-fg:#FFFFFF; --accent-soft:rgba(39,34,110,.08);
  --done:#067647; --done-bg:#E8F5EF;
  --doing:#B45309; --doing-bg:#FDF3E7;
  --pending:#64748B; --pending-bg:#F1F3F5;
  --danger:#B42318; --danger-bg:#FBEAE8;
}

/* MUST come before every display rule: HTML's hidden attribute works through
   [hidden]{display:none} (0-1-0), so a rule targeting an id overrides it and the
   element stays visible. This exact bug bit the sign-in box once already. */
[hidden] { display: none !important; }

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }

body {
  background: var(--bg-grad) fixed;
  background-color: var(--bg);
  zoom: var(--ui-zoom);
  min-height: calc(100vh / var(--ui-zoom));
  color: var(--ink);
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

button, input, select { font: inherit; color: inherit; }

/* The "Resolution Rate" tab embeds the dashboard in an iframe. The embedded page
   sets its own height (same origin) so there is no nested scrollbar; min-height
   only covers the loading moment. */
/* Divided by the zoom like every other viewport measure — see --ui-zoom. */
iframe.rs-frame { width: 100%; border: 0; display: block; min-height: calc(70vh / var(--ui-zoom)); }

/* The "Scan folder" dropdown: everything / one project. */
.cl-scan-wrap { position: relative; display: inline-block; }
.cl-scan-menu { position: absolute; top: calc(100% + 4px); right: 0; z-index: 50;
  background: var(--card-solid, var(--card)); border: 1px solid var(--rule, var(--line));
  border-radius: var(--r); box-shadow: 0 10px 28px rgba(16,24,40,.18); min-width: 236px; padding: 4px; }
.cl-menu-item { display: flex; flex-direction: column; align-items: flex-start; gap: 1px;
  width: 100%; text-align: left; background: transparent; border: 0; padding: 8px 10px;
  border-radius: var(--r); cursor: pointer; color: var(--ink); font-weight: 600; font-size: 13px; }
.cl-menu-item:hover { background: var(--hover, rgba(0,0,0,.05)); }
.cl-menu-item small { font-weight: 400; color: var(--ink-3, var(--muted)); font-size: 11px; }

/* The major-package selector on each package row (manual assignment).
   Placed on its OWN row, right-aligned: the project card is ~320px wide and the
   line above is already full with the package name + Rev + status; squeezing the
   selector onto the same line crushes the package name to two words and pushes it
   onto four lines. Right-aligned so its edge lines up with the status column,
   reading immediately as "an accessory to this row" rather than a new package row.
   Faint at rest, clear on hover / keyboard focus: assigning by hand is rare (only
   to correct a wrong auto-guess), and showing it prominently at all times would
   sprout 20 grey boxes down a 20-package list, competing with the clash numbers
   themselves. .is-set = a manual override is in place -> always clear, because
   that is what a reader needs in order to know this group was assigned by a person
   rather than guessed by the rules. */
.cl-major-sel { font-size: 11px; border: 1px solid transparent; border-radius: var(--r);
  background: transparent; color: var(--ink-3, var(--muted));
  padding: 1px 4px; max-width: 140px; cursor: pointer;
  grid-column: 1 / -1; justify-self: end; margin-top: 2px;
  opacity: .5; transition: opacity .12s, border-color .12s; }
.cl-pkg-row:hover .cl-major-sel, .cl-major-sel:focus, .cl-major-sel.is-set {
  opacity: 1; border-color: var(--rule, var(--line)); background: var(--card-solid, var(--card)); }
/* Touch devices have no hover -> there is no way to reveal it. Show it always. */
@media (hover: none) { .cl-major-sel { opacity: 1; border-color: var(--rule, var(--line)); } }
/* The status chip and the "N deferred" chip occupy ONE cell of the package row (see pkgStatus). */
.cl-pkg-sts { display: inline-flex; align-items: start; margin-top: 1px; }
.cl-pkg-major > .cl-pkg-blk-h .cl-pkg-blk-name { font-weight: 700; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; border-radius: var(--r); }

/* ===== Buttons ===== */

.btn {
  border: 1px solid var(--rule-2);
  background: var(--card);
  color: var(--ink-2);
  padding: 7px 14px;
  border-radius: var(--r);
  cursor: pointer;
  font-size: 13px;
  font-weight: 500;
  white-space: nowrap;
  transition: background .12s, border-color .12s;
}
.btn:hover { background: var(--hover); border-color: var(--ink-4); }
.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-fg);
  font-weight: 600;
}
.btn-primary:hover { filter: brightness(1.08); }

/* ===== Top bar ===== */

.tlc-top {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 12px 24px;
  border-bottom: 1px solid var(--rule);
  background: var(--card);
  position: sticky;
  top: 0;
  z-index: 20;
}
.tlc-title { font-size: 15px; font-weight: 700; letter-spacing: -0.01em; }
.tlc-title small {
  display: block;
  font-size: 11.5px;
  font-weight: 400;
  color: var(--ink-3);
  margin-top: 1px;
}
/* Logo TLC + "BIM TEAM" */
.tlc-brand { display: flex; align-items: center; gap: 10px; }
/* The logo was extracted from the image embedded in a Coordination Report
   (246x68), with the white background converted to alpha. Height is fixed and the
   width follows, so it never distorts. */
.tlc-logo { height: 26px; width: auto; display: block; }
/* The logo's ink is #00021b — effectively invisible on a dark background.
   brightness(0) forces it to pure black and invert(1) turns it white, keeping the
   shape and its antialiased edges intact. */
@media (prefers-color-scheme: dark) { .tlc-logo { filter: brightness(0) invert(1); } }
:root[data-theme="dark"] .tlc-logo { filter: brightness(0) invert(1); }
:root[data-theme="light"] .tlc-logo { filter: none; }
.tlc-brand-sep { width: 1px; height: 20px; background: var(--rule-2); flex: none; }
.tlc-brand-name {
  font-size: 12px;
  font-weight: 800;
  letter-spacing: .08em;
  color: var(--brand);
  white-space: nowrap;
}

/* The Time Sheet / Diary Clash Check tabs + the external link */
.tlc-tabs { display: flex; gap: 2px; margin-left: 8px; }
.tlc-tab {
  border: 0;
  background: transparent;
  color: var(--ink-3);
  font-size: 13.5px;
  font-weight: 600;
  padding: 6px 14px;
  border-radius: var(--r);
  cursor: pointer;
}
.tlc-tab:hover { background: var(--hover); color: var(--ink-2); }
/* The active tab is TEXT with a rule under it, not a filled block. A solid
   indigo pill is the heaviest thing on the bar, and it competes with the one
   button on the screen that should be that colour — "+ Add". */
.tlc-tab.active {
  background: transparent; color: var(--ink);
  box-shadow: inset 0 -2px 0 var(--brand);
  border-radius: 0;
}

/* Narrow screens: logo + "BIM TEAM" + 3 tabs = 397px, which doesn't fit a 375px
   phone -> the WHOLE PAGE slides sideways. So the text beside the logo goes, the
   padding shrinks, and the tab strip gets its own horizontal scroll — min-width:0
   is mandatory, because without it a flex item cannot shrink below its content
   size and still pushes the page out. */
@media (max-width: 720px) {
  .tlc-top { padding: 10px 12px; gap: 8px; }
  .tlc-brand-sep, .tlc-brand-name { display: none; }
  .tlc-tab { padding: 6px 9px; font-size: 12.5px; }
  .tlc-tabs {
    margin-left: 0;
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .tlc-tabs::-webkit-scrollbar { display: none; }
  .tlc-tab { flex: none; }
}

/* Dark / light / follow the system. Last thing on the bar, after "Logging for":
   it is set once and then ignored for months, so it must not sit where the eye
   lands. Square and quiet — the same weight as a tab, not a primary button. */
.tlc-theme {
  flex: none; width: 30px; height: 30px; padding: 0;
  border: 1px solid var(--rule); border-radius: var(--r);
  background: transparent; color: var(--ink-2);
  font-size: 14px; line-height: 1; cursor: pointer;
  display: grid; place-items: center;
  transition: border-color .12s, background .12s;
}
.tlc-theme:hover { border-color: var(--brand); background: var(--hover); }
.tlc-theme:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.tlc-me {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
  color: var(--ink-3);
}
@media (max-width: 560px) { .tlc-me-lbl { display: none; } }
.tlc-me select {
  padding: 5px 9px;
  border-radius: var(--r);
  border: 1px solid var(--rule-2);
  background: var(--card);
  color: var(--ink);
  font-weight: 600;
  font-size: 13px;
  cursor: pointer;
}
.tlc-body { padding: 18px 24px 80px; max-width: 1180px; margin: 0 auto; }

/* ===== Sign-in ===== */

#login { min-height: calc(100vh / var(--ui-zoom)); display: flex; align-items: center; justify-content: center; padding: 20px; }
.login-box {
  width: 320px;
  padding: 28px;
  border-radius: var(--r);
  border: 1px solid var(--rule);
  background: var(--card);
  box-shadow: 0 2px 20px rgba(0,0,0,.05);
}
.login-box h1 { font-size: 18px; margin: 0 0 3px; }
.login-box p { font-size: 13px; color: var(--ink-3); margin: 0 0 18px; }
.login-box input {
  width: 100%;
  padding: 9px 11px;
  border-radius: var(--r);
  border: 1px solid var(--rule-2);
  background: var(--card);
  margin-bottom: 10px;
}
.login-box .btn { width: 100%; }
#login-msg { color: var(--danger); font-size: 12.5px; min-height: 18px; margin-top: 8px; }

/* ===== Quick-entry block — RIGHT AT THE TOP =====
   It is done ~4 times a day per person, so it comes first. It used to sit after
   "Upcoming", which pushed the table down by 555px. */

/* SOLID, not the frosted --card the other cards use. This card is STICKY: it
   floats over the week plan and the table while the page scrolls, and at 64%
   white the rows underneath showed straight through it — two sets of text on top
   of each other, neither readable (Dat, 17/08/2026). A surface that covers
   something has to actually cover it. */
.wl-add {
  background: var(--card-solid);
  border: 1px solid var(--rule);
  border-radius: var(--r);
  padding: 12px 14px;
  margin-bottom: 14px;
}

/* Desktop: the entry block STICKS just below the top bar while scrolling —
   whichever day you are looking at further down, you can click its header and
   start typing without scrolling back to the top of the page. (On mobile it
   sticks to the BOTTOM of the screen — see the media block at the end of the file.)
   --tlc-top-h is measured by app.js from the real .tlc-top, because the bar's
   height changes with the screen width; 57px is only a fallback for before the JS
   has measured. */
@media (min-width: 721px) {
  body[data-tab="worklog"] .wl-add {
    position: sticky;
    top: calc(var(--tlc-top-h, 57px) + 10px);
    z-index: 15;
  }
}

.wl-add-projects {
  display: flex;
  gap: 5px;
  flex-wrap: wrap;
  align-items: center;
  margin-bottom: 9px;
}

/* Project chips: the 8 most used. All 69 used to be shown -> 5 rows. */
.wl-proj-pill {
  font-size: 12px;
  padding: 3px 10px;
  border-radius: 999px;
  border: 1px solid var(--rule-2);
  background: var(--card);
  color: var(--ink-2);
  cursor: pointer;
  white-space: nowrap;
  transition: background .1s, border-color .1s;
}
.wl-proj-pill:hover { border-color: var(--ink-4); background: var(--hover); }
.wl-proj-pill.active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-fg);
  font-weight: 600;
}
/* A dropdown holding the remaining projects */
.wl-proj-more {
  font-size: 12px;
  padding: 3px 8px;
  border-radius: 999px;
  border: 1px dashed var(--rule-2);
  background: transparent;
  color: var(--ink-3);
  cursor: pointer;
  max-width: 190px;
}
.wl-proj-more:hover { border-color: var(--accent); color: var(--accent); }
.wl-proj-more.active {
  border-style: solid;
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-fg);
  font-weight: 600;
}
/* The box for typing a new project name, shown after pressing ＋ */
.wl-proj-addbox { display: inline-flex; }
.wl-proj-addbox .wl-input { padding: 3px 9px; font-size: 12px; }

.wl-add-row { display: flex; gap: 8px; align-items: center; }
.wl-input {
  flex: 1;
  min-width: 0;
  padding: 8px 11px;
  border: 1px solid var(--rule-2);
  border-radius: var(--r);
  background: var(--bg);
}
.wl-input:focus { background: var(--card); }
.wl-add-hours { display: flex; align-items: center; gap: 6px; }
.wl-add-hours label { font-size: 12px; color: var(--ink-3); }
.wl-add-hours input {
  width: 64px;
  padding: 8px;
  border: 1px solid var(--rule-2);
  border-radius: var(--r);
  background: var(--bg);
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}

.wl-sugs {
  display: flex;
  gap: 5px;
  flex-wrap: wrap;
  align-items: center;
  margin-top: 9px;
  padding-top: 9px;
  border-top: 1px solid var(--rule);
}
.wl-sugs-label {
  font-size: 11px;
  color: var(--ink-3);
  font-family: var(--mono);
  letter-spacing: .04em;
  margin-right: 2px;
}
/* The "Frequently used" chips that used to fill this row were removed on
   17/08/2026 (.wl-sug-chip / .wl-sug-h went with them): the autocomplete says the
   same thing over the whole history the moment anything is typed, and the week
   plan puts the day's own work one click above the input. What is left in the row
   is the copy shortcuts. */

/* ============================================================
   The "today" block + the week ribbon (17/08/2026)
   ------------------------------------------------------------
   Replaces: the "Log for:" chip row, the 11px hour meter tucked at the end of
   it, and the 49px amber reminder banner above the card. All three answered the
   same question — where am I against 8.5h — in the smallest type on the screen.

   NOT sticky: only the entry card below it is. Pinning 320px of header would
   take a third of the viewport away from the table while scrolling.
   ============================================================ */
.wl-hero {
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--r);
  margin-bottom: 10px;
  overflow: hidden;
}
.wl-hero-top { display: flex; align-items: center; gap: 28px; padding: 12px 16px; }
.wl-hero-day { flex: 1; min-width: 0; }
.wl-hero-eyebrow {
  font-family: var(--mono); font-size: var(--fs-label); letter-spacing: var(--ls-label);
  text-transform: uppercase; color: var(--ink-4); margin-bottom: 6px;
}
.wl-hero-date { font-size: var(--fs-lead); font-weight: 650; letter-spacing: -.01em; }
.wl-hero-today {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .1em; text-transform: uppercase;
  background: var(--accent); color: var(--accent-fg); padding: 2px 8px; border-radius: var(--r);
  margin-left: 8px; vertical-align: 2px;
}
/* Rides on the date line rather than taking a line of its own — the ribbon below
   says the same thing per day, so this is a reminder, not a headline. */
.wl-hero-sub { font-size: var(--fs-body); font-weight: 400; color: var(--ink-3); margin-left: 10px; }
.wl-hero-num { flex: none; text-align: right; }
.wl-hero-big {
  font-family: var(--mono); font-size: var(--fs-hero); font-weight: 700; line-height: 1;
  letter-spacing: -.03em; font-variant-numeric: tabular-nums; color: var(--ink);
}
.wl-hero-big small { font-size: 17px; font-weight: 400; letter-spacing: 0; color: var(--ink-4); }
.wl-hero-big.met { color: var(--done); }
.wl-hero-big.over { color: var(--danger); }
.wl-hero-delta {
  display: inline-block; margin-top: 7px; padding: 2px 8px; border-radius: var(--r);
  font-family: var(--mono); font-size: var(--fs-meta); font-weight: 600;
  background: var(--doing-bg); color: var(--doing);
}
.wl-hero-delta.met  { background: var(--done-bg);  color: var(--done); }
.wl-hero-delta.over { background: var(--pending-bg); color: var(--danger); }

/* The reminder, now one line inside the block instead of a banner above it */
.wl-hero .wl-nag {
  margin: 0; border-radius: 0; border: 0; border-top: 1px solid var(--rule);
  background: var(--doing-bg); padding: 8px 16px; font-size: var(--fs-body);
}

/* --- the week ribbon: five days, logged vs planned --- */
.wl-ribbon { display: grid; grid-template-columns: repeat(5, 1fr); border-top: 1px solid var(--rule); }
.wl-rib-cell {
  display: block; width: 100%; text-align: left; cursor: pointer;
  border: 0; border-right: 1px solid var(--rule); border-bottom: 2px solid transparent;
  background: transparent; padding: 12px 16px 12px; font: inherit; color: inherit;
  transition: background .1s;
}
.wl-rib-cell:last-child { border-right: 0; }
.wl-rib-cell:hover:not(:disabled) { background: var(--hover); }
.wl-rib-cell.on { border-bottom-color: var(--accent); background: var(--accent-soft); }
.wl-rib-cell:disabled { cursor: default; opacity: .6; }
.wl-rib-cell:focus-visible { outline: 2px solid var(--brand2); outline-offset: -2px; }
.wl-rib-top { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-bottom: 8px; }
.wl-rib-dow {
  font-family: var(--mono); font-size: var(--fs-meta); font-weight: 600;
  color: var(--ink-2); letter-spacing: .04em;
}
/* --brand, not --accent: the accent is a BACKGROUND colour, and as text on the
   dark ground it measured 2.91:1. --brand is the text half of the pair. */
.wl-rib-cell.today .wl-rib-dow { color: var(--brand); }
.wl-rib-h {
  font-family: var(--mono); font-size: 12.5px; font-variant-numeric: tabular-nums; color: var(--ink-3);
}
.wl-rib-cell.on .wl-rib-h { color: var(--ink); font-weight: 700; }
.wl-rib-track { display: block; height: 5px; border-radius: 2px; background: var(--rule); overflow: hidden; margin-bottom: 8px; }
.wl-rib-track i { display: block; height: 100%; border-radius: 2px; }
.wl-rib-track i.met  { background: var(--done); }
.wl-rib-track i.short { background: var(--doing); }
.wl-rib-track i.over { background: var(--danger); }
.wl-rib-track i.none { background: transparent; }
.wl-rib-plan { display: flex; align-items: center; gap: 4px; font-size: var(--fs-meta); color: var(--ink-3); }
.wl-rib-dot { width: 5px; height: 5px; border-radius: 50%; background: var(--brand2); flex: none; }
.wl-rib-plan .none { color: var(--ink-4); font-style: italic; }

@media (max-width: 720px) {
  /* Five cells at 375px are 70px wide — the hour bar survives, the words do not.
     Wrapping them onto two rows made the block 381px, nearly half the phone
     screen. A scroll strip instead, which is what the project and hour rows on
     this screen already do. */
  .wl-ribbon { display: flex; overflow-x: auto; scrollbar-width: none; }
  .wl-ribbon::-webkit-scrollbar { display: none; }
  .wl-rib-cell { flex: 0 0 132px; }
  .wl-hero-top { align-items: flex-start; gap: 16px; }
  .wl-hero-big { font-size: 34px; }
}

/* ===== Day chips — the date a new row is logged against ===== */
.wl-days { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; margin-bottom: 9px; }
.wl-days-lbl {
  font-size: 11px;
  color: var(--ink-3);
  font-family: var(--mono);
  letter-spacing: .04em;
  margin-right: 2px;
}
.wl-day-chip {
  font-size: 12px;
  font-family: var(--mono);
  padding: 3px 12px;
  border-radius: 999px;
  border: 1px solid var(--rule-2);
  background: var(--card);
  color: var(--ink-2);
  cursor: pointer;
  white-space: nowrap;
  transition: background .1s, border-color .1s;
}
.wl-day-chip:hover:not(:disabled) { border-color: var(--ink-4); background: var(--hover); }
.wl-day-chip.active { background: var(--accent); border-color: var(--accent); color: var(--accent-fg); font-weight: 600; }
/* A day still in the future — disabled; planned work belongs in Upcoming */
.wl-day-chip:disabled { opacity: .35; cursor: default; }

/* Progress for the selected day — reuses .wl-fill, just pushed to the end of the row */
.wl-today { margin-left: auto; }

/* ===== Quick-hour chips — instead of hunting the spinner in 0.5 steps ===== */
.wl-add-hours { flex-wrap: wrap; }
.wl-hour-chip {
  font-size: 12px;
  font-family: var(--mono);
  font-weight: 600;
  padding: 3px 8px;
  border-radius: 999px;
  border: 1px solid var(--rule-2);
  background: var(--card);
  color: var(--ink-2);
  cursor: pointer;
  white-space: nowrap;
}
.wl-hour-chip:hover { border-color: var(--ink-4); background: var(--hover); }
.wl-hour-chip.active { background: var(--accent); border-color: var(--accent); color: var(--accent-fg); }
/* "Xh left" — fills in exactly what is missing to round out the daily target */
.wl-hour-chip.fill { border-style: dashed; border-color: var(--doing); color: var(--doing); background: var(--doing-bg); }
.wl-hour-chip.fill.active { border-style: solid; background: var(--doing); color: #fff; }

/* ===== The suggestion list — drops below the input =====
   Since the "Frequently used" chips were removed this is THE suggestion list, and
   it hangs over the plan board. --card is frosted glass (64% white): with the
   plan chips and the board's column heads showing through it, the list could not
   be read. It is the one surface here that has to block what is behind it, which
   is exactly what --card-solid is for. */
.wl-add-row { position: relative; }
.wl-ac {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  width: min(480px, 100%);
  max-height: 244px;
  overflow: hidden auto;
  background: var(--card-solid);
  border: 1px solid var(--rule-2);
  border-radius: var(--r);
  box-shadow: 0 10px 30px rgba(20, 25, 60, .18);
  z-index: 40;
}
.wl-ac-item {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  border: 0;
  background: none;
  text-align: left;
  cursor: pointer;
  padding: 8px 12px;
  font-size: 12.5px;
  color: var(--ink);
  border-bottom: 1px solid var(--rule);
}
.wl-ac-item:last-child { border-bottom: 0; }
.wl-ac-item.on, .wl-ac-item:hover { background: var(--accent-soft); }
.wl-ac-lbl { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wl-ac-lbl b { color: var(--brand2); }
.wl-ac-meta { margin-left: auto; font-family: var(--mono); font-size: 10.5px; color: var(--ink-3); white-space: nowrap; }

/* ===== Week bar ===== */

.wl-header { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.wl-week-nav { display: flex; align-items: center; gap: 2px; }
.wl-week-btn {
  border: 1px solid var(--rule-2);
  background: var(--card);
  color: var(--ink-2);
  width: 28px; height: 28px;
  border-radius: var(--r);
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
  display: grid;
  place-items: center;
}
.wl-week-btn:hover:not(:disabled) { background: var(--hover); border-color: var(--ink-4); }
.wl-week-btn:disabled { opacity: .3; cursor: default; }
.wl-week-label { margin: 0 8px; display: flex; align-items: baseline; gap: 8px; }
.wl-week-label strong { font-size: 14.5px; font-weight: 600; }
.wl-week-label span { font-size: 12px; color: var(--ink-3); font-family: var(--mono); }
/* The week total — took over the spot of the removed "Copy for Excel" button */
.wl-week-total { margin-left: auto; font-size: 12.5px; color: var(--ink-3); }
.wl-week-total strong { color: var(--ink); font-family: var(--mono); font-weight: 600; }
/* The weekly target beside the total: green on target / amber short — the same language as the day bar */
.wl-wt { font-family: var(--mono); font-weight: 600; }
.wl-wt.met { color: var(--done); }
.wl-wt.short { color: var(--doing); }

/* ===== Reminder banner: the previous working day is short of target ===== */
.wl-nag {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  background: var(--doing-bg);
  border: 1px solid rgba(180, 83, 9, .3);
  border-radius: var(--r);
  padding: 8px 16px;
  margin-bottom: 12px;
  font-size: 13px;
  color: var(--doing);
}
.wl-nag b { font-family: var(--mono); }
.wl-nag-go {
  margin-left: auto;
  border: 0;
  background: var(--doing);
  color: #fff;
  border-radius: var(--r);
  padding: 4px 12px;
  font-weight: 600;
  font-size: 12.5px;
  cursor: pointer;
  white-space: nowrap;
}
.wl-nag-go:hover { filter: brightness(1.08); }
.wl-nag-skip {
  border: 0;
  background: none;
  color: var(--ink-3);
  font-size: 12px;
  text-decoration: underline;
  cursor: pointer;
  white-space: nowrap;
}

/* The copy button on an empty day row */
.wl-day-copy {
  font-size: 11px;
  padding: 2px 12px;
  margin-left: 10px;
  border: 1px dashed var(--rule-2);
  border-radius: 999px;
  background: transparent;
  color: var(--brand2);
  cursor: pointer;
  white-space: nowrap;
}
.wl-day-copy:hover { border-color: var(--brand2); background: var(--accent-soft); }

/* The − / + stepper around the hours cell being edited — ONLY on narrow screens (see the 720 media query) */
.wl-hstep { display: inline-flex; align-items: center; gap: 3px; width: 100%; }
.wl-hstep .wl-e { flex: 1; min-width: 0; }
.wl-hstep-btn {
  display: none;
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: var(--r);
  border: 1px solid var(--rule-2);
  background: var(--card);
  color: var(--ink-2);
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
  place-items: center;
  padding: 0;
}
.wl-hstep-btn:hover { background: var(--hover); }

/* ===== Table =====
   No cell borders. Ordinary text. A cell becomes an input only when clicked.
   Previously: 294 permanently bordered inputs, 93 of them on one screen. */

.wl-table-wrap {
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--r);
  overflow: hidden;
}
.wl-table { width: 100%; border-collapse: collapse; }

.wl-table thead th {
  text-align: left;
  font-family: var(--mono);
  font-size: var(--fs-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--ink-3);
  font-weight: 600;
  padding: 8px 12px;
  border-bottom: 1px solid var(--rule-2);
  background: var(--bg);
  white-space: nowrap;
}
.wl-table td {
  padding: 0 12px;
  height: 29px;                  /* 43px -> 29px */
  border-bottom: 1px solid var(--rule);
  vertical-align: middle;
}
/* Vertical rules between the columns — the crux of the spreadsheet look.
   The Task column is 659px wide while the text occupies only ~200px, so without
   vertical rules the eye drifts freely between the task name and the hours and the
   table reads as disconnected. The rules anchor each column, turning the white
   space into a cell's margin rather than a gap. */
.wl-table th:not(:last-child),
.wl-table td:not(:last-child) { border-right: 1px solid var(--rule); }
.wl-table tbody tr:last-child td { border-bottom: none; }
.wl-table tbody tr:hover td { background: var(--hover); }

/* The per-day header row — replaces a Date column that repeated identically 49
   times a week.
   The band has to STAND OUT against the task rows: taller, bolder, with a 2px rule
   between days — it used to be thin and the same colour, so the days ran together. */
.wl-day-sep td {
  background: var(--bg) !important;
  height: 34px;
  border-top: 2px solid var(--rule-2);
}
.wl-day-sep:first-child td { border-top: none; }
.wl-day-title { font-weight: 700; font-size: 12.5px; color: var(--ink); }
.wl-day-sub { font-size: 11px; color: var(--ink-3); margin-left: 8px; font-family: var(--mono); }
/* The group badge for today */
.wl-day-today {
  font-size: 10px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  background: var(--accent); color: var(--accent-fg);
  padding: 1px 8px; border-radius: 999px; margin-left: 8px; vertical-align: 1px;
}
/* A clickable day header -> makes that day the entry date */
tr[data-wl-dayhead] { cursor: pointer; }

/* Alternating background BY GROUP (day/person): odd groups get a light wash — the
   boundary between days is obvious at a glance even after scrolling past the
   header row. */
.wl-table tbody tr.wl-alt td { background: rgba(120, 144, 180, .07); }

/* A light wash in the PERSON's colour across the whole row — on a multi-person
   table you can see at a glance whose block of work is whose, instead of tracking
   a 3px stripe at the edge of the task cell. --oc-bg/--oc-hov are set inline on
   the <tr> by app.js (the person's hex + an alpha byte). When the tint is on there
   is NO wl-alt (app.js applies one or the other). Hover deepens the person's
   colour rather than switching to grey var(--hover) — changing colour systems
   halfway looks badly out of place.
   (These two rules must come AFTER the shared :hover rule above; wl-tint:hover
   wins on specificity, and wl-tint td wins by coming later.) */
.wl-table tbody tr.wl-tint td { background: var(--oc-bg); }
.wl-table tbody tr.wl-tint:hover td { background: var(--oc-hov); }

/* The "day full" bar — replaces a warning sentence. Green on target, amber short, red over. */
.wl-fill { display: inline-flex; align-items: center; gap: 8px; margin-left: 10px; vertical-align: middle; }
.wl-fill-bar {
  display: inline-block; width: 110px; height: 5px;
  background: var(--rule); border-radius: 999px; overflow: hidden;
}
.wl-fill-bar i { display: block; height: 100%; border-radius: 999px; }
.wl-fill-n { font-size: 11px; font-family: var(--mono); font-weight: 600; }
.wl-fill.met    .wl-fill-bar i { background: var(--done); }
.wl-fill.met    .wl-fill-n     { color: var(--done); }
.wl-fill.short .wl-fill-bar i { background: var(--doing); }
.wl-fill.short .wl-fill-n     { color: var(--doing); }
/* Over target: usually a mistyped hour count — it has to be seen immediately */
.wl-fill.over  .wl-fill-bar i { background: var(--danger); }
.wl-fill.over  .wl-fill-n     { color: var(--danger); }
@media (max-width: 560px) { .wl-fill-bar { width: 60px; } }

/* The hours cell: a background bar proportional to the daily target, so the length
   of a task is visible without reading. Placed on the <td> rather than the <span>
   inside it — while editing, the span becomes an input and the bar would vanish
   with it. */
/* The hour-proportion bar: a THIN strip along the bottom of the cell, not a block
   behind the number. The old version drew a 17px block at 15% opacity right under
   the figure — a different length on every row, so the whole column looked like a
   smear and read as a rendering fault rather than a chart. */
.wl-h-cell { position: relative; }
.wl-h-cell::after {
  content: ''; position: absolute; left: 0; bottom: 0;
  width: var(--h-pct, 0); max-width: 100%; height: 2px;
  background: var(--brand2); opacity: .5; pointer-events: none;
}
.wl-h-cell .wl-v { position: relative; font-weight: 700; font-size: 14px; font-variant-numeric: tabular-nums; }

/* ===== People chips: week total + shortfall, click to filter ===== */
.wl-ppl { display: flex; gap: 4px; flex-wrap: wrap; align-items: center; margin-bottom: 9px; }
.wl-ppl-chip {
  font-size: 12px;
  padding: 3px 12px;
  border-radius: 999px;
  border: 1px solid var(--rule-2);
  background: var(--card);
  color: var(--ink-2);
  cursor: pointer;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  transition: background .1s, border-color .1s;
}
.wl-ppl-chip:hover { border-color: var(--ink-4); background: var(--hover); }
.wl-ppl-chip.active { background: var(--accent); border-color: var(--accent); color: var(--accent-fg); font-weight: 600; }
.wl-ppl-chip b { font-family: var(--mono); font-weight: 600; }
/* "nothing yet" is NOT red: at the start of the week the whole team has nothing
   logged, and 5 red chips at once make the screen look like an alarm going off,
   at which point the warning stops meaning anything. Only the SHORTFALL gets
   colour, and in amber (doing) rather than danger red. */
.wl-ppl-chip b.zero { color: var(--ink-4); font-weight: 400; }
.wl-ppl-miss { color: var(--doing); font-weight: 600; font-size: 11px; }
/* On the indigo background of the selected chip, coloured text is unreadable */
.wl-ppl-chip.active b.zero, .wl-ppl-chip.active .wl-ppl-miss { color: var(--accent-fg); }
.wl-ppl-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
/* "＋ N others" — the rest of the team, folded away by default. Dashed like the
   copy shortcuts: it is a tool, not one of the people. */
.wl-ppl-more {
  font-size: 11.5px; padding: 3px 12px; border-radius: 999px;
  border: 1px dashed var(--rule-2); background: transparent;
  color: var(--ink-3); cursor: pointer; white-space: nowrap;
}
.wl-ppl-more:hover { border-style: solid; border-color: var(--ink-4); background: var(--hover); color: var(--ink-2); }

/* The table grouping toggle: Day | Person */
.wl-group-toggle { display: flex; border: 1px solid var(--rule-2); border-radius: var(--r); overflow: hidden; }
.wl-group-toggle button {
  font-size: 12px;
  padding: 4px 12px;
  border: none;
  background: var(--card);
  color: var(--ink-2);
  cursor: pointer;
}
.wl-group-toggle button + button { border-left: 1px solid var(--rule-2); }
.wl-group-toggle button.active { background: var(--accent); color: var(--accent-fg); font-weight: 600; }

/* The export-to-MODUQA button + its script modal */
.wl-mq-btn {
  font-size: 12px;
  padding: 4px 12px;
  border: 1px solid var(--rule-2);
  border-radius: var(--r);
  background: var(--card);
  color: var(--ink-2);
  cursor: pointer;
  white-space: nowrap;
}
.wl-mq-btn:hover { border-color: var(--accent); color: var(--accent); }
.mq-steps { margin: 0 0 12px; padding-left: 20px; font-size: 13px; line-height: 1.65; }
.mq-steps code {
  font-family: var(--mono); font-size: 12px;
  background: var(--head); padding: 1px 4px; border-radius: var(--r);
}
.mq-warns {
  font-size: 12.5px; line-height: 1.6; color: var(--doing);
  background: color-mix(in srgb, var(--doing) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--doing) 30%, transparent);
  border-radius: var(--r); padding: 8px 12px; margin-bottom: 10px;
}
.mq-script {
  width: 100%; height: 150px; resize: vertical;
  font-family: var(--mono); font-size: 11px; line-height: 1.5;
  background: var(--bg); color: var(--ink-2);
  border: 1px solid var(--rule-2); border-radius: var(--r); padding: 8px 12px;
  white-space: pre; overflow: auto;
}

/* The date column when grouped by person */
.wl-row-day { font-size: 11.5px; color: var(--ink-3); font-family: var(--mono); white-space: nowrap; }

/* The copy-repeat-work buttons — pushed to the end of the row under the input */
.wl-copy { margin-left: auto; display: inline-flex; gap: 4px; flex: none; }
.wl-copy-btn {
  font-size: 11.5px; padding: 2px 8px;
  border: 1px dashed var(--rule-2); border-radius: 999px;
  background: transparent; color: var(--ink-3); cursor: pointer; white-space: nowrap;
}
.wl-copy-btn:hover { border-style: solid; border-color: var(--ink-4); background: var(--hover); color: var(--ink-2); }
/* The person selector: looks like a button, but it is a select so the list opens on click */
.wl-copy-sel { max-width: 150px; padding-right: 4px; }

/* The day picker used when copying from someone else */
.cpy-days { display: flex; flex-direction: column; gap: 2px; margin: 4px 0 12px; }
.cpy-day {
  display: grid;
  grid-template-columns: auto 88px 96px auto 1fr;
  align-items: center; gap: 8px;
  padding: 8px 8px; border-radius: var(--r); cursor: pointer;
  border: 1px solid transparent;
}
.cpy-day:hover { background: var(--hover); border-color: var(--rule); }
.cpy-day input { cursor: pointer; }
.cpy-day-n { font-size: 12.5px; font-weight: 600; color: var(--ink); }
.cpy-day-m { font-size: 11.5px; color: var(--ink-3); font-family: var(--mono); }
.cpy-day-warn {
  font-size: 10.5px; color: var(--doing); background: var(--doing-bg);
  padding: 1px 8px; border-radius: 999px; white-space: nowrap;
}
/* The task list: truncate rather than letting the box stretch sideways */
.cpy-day-t {
  font-size: 11px; color: var(--ink-4);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
.cpy-all {
  border: none; background: none; padding: 0;
  font-size: 11.5px; color: var(--brand2); cursor: pointer; text-decoration: underline;
}
@media (max-width: 560px) {
  .cpy-day { grid-template-columns: auto 1fr; }
  .cpy-day-t { display: none; }
}
@media (max-width: 560px) { .wl-copy { margin-left: 0; width: 100%; } }

/* The discipline prompt while typing — sits right below the input, shown only when needed */
.wl-disc { display: flex; align-items: center; gap: 4px; margin: 8px 0 0; flex-wrap: wrap; }
.wl-disc-lbl { font-size: 11.5px; color: var(--ink-3); }
.wl-disc-chip {
  font-size: 12px; font-weight: 600;
  padding: 2px 12px; border-radius: 999px;
  border: 1px solid var(--brand2); background: var(--card); color: var(--brand2);
  cursor: pointer;
}
.wl-disc-chip:hover { background: var(--brand2); color: #fff; }
.wl-disc-skip {
  font-size: 11.5px; padding: 2px 8px;
  border: none; background: none; color: var(--ink-4);
  cursor: pointer; text-decoration: underline;
}

/* ===== Reports screen ===== */

.rep-dates { display: inline-flex; align-items: center; gap: 4px; margin-left: 6px; }
.rep-dates input[type="date"] {
  font-size: 12px; padding: 3px 8px;
  border: 1px solid var(--rule-2); border-radius: var(--r);
  background: var(--card); color: var(--ink-2); font-family: var(--mono);
}
.rep-dates span { color: var(--ink-4); font-size: 12px; }

.rep-filters { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 12px; }
.rep-filters select, .rep-filters input[type="search"] {
  font-size: 12.5px; padding: 4px 8px;
  border: 1px solid var(--rule-2); border-radius: var(--r);
  background: var(--card); color: var(--ink);
}
/* The search box absorbs the remaining space, but min-width:0 keeps it from overflowing the row */
.rep-filters input[type="search"] { flex: 1; min-width: 140px; }

/* A report row has 4 cells (label · bar · hours · row count), whereas .cl-row on
   the clash screen has only 3 columns. Without this declaration the 4th cell is
   pushed to a new line and appears as a number dangling with no explanation.

   The label takes the flexible space and the BAR is fixed at 320px — the reverse
   of the old version (label capped at 190px, bar 1fr ~630px). The task name is
   what people read, and it was being cut to 'KGH1-MODULE WALL FRAME …' while the
   bar — which only serves to gauge more-or-less — ran three times as long.

   The 540px ceiling was measured against real data: the longest label is 526px and
   90% are under 362px — enough room for nearly all of them without letting the
   column run out to 640px the way 1fr did. */
.cl-row.rep-row { grid-template-columns: minmax(200px, 540px) 320px 52px 58px; }

/* The row-count column — fainter, being a secondary figure, and labelled "rows" so it explains itself */
.rep-row-n2 {
  font-family: var(--mono); font-size: 10.5px; color: var(--ink-4);
  text-align: right; white-space: nowrap;
}
.rep-more { font-size: 11.5px; color: var(--ink-4); padding: 8px 2px 2px; }

/* The scope reminder line — scroll down and you still know which period and which filters are in play */
.rep-scope {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  padding: 8px 12px; margin-bottom: 12px;
  border: 1px solid var(--rule); border-radius: var(--r); background: var(--bg);
}
.rep-scope-l { font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-4); font-family: var(--mono); }
.rep-scope-v { font-size: 12.5px; color: var(--ink); font-weight: 600; }
.rep-scope-t { margin-left: auto; font-size: 12px; color: var(--ink-3); }
.rep-scope-t b { font-family: var(--mono); color: var(--ink); }

/* A task row that can be clicked to expand the per-person breakdown */
.rep-row-btn {
  width: 100%; border: none; background: none; text-align: left;
  cursor: pointer; font: inherit; color: inherit; padding: 0;
}
.rep-row-btn:hover .cl-row-lbl { color: var(--brand2); }
.rep-caret { display: inline-block; width: 11px; font-size: 9px; color: var(--ink-4); }

/* The per-person breakdown — indented to show it belongs to the row above */
.rep-people { padding: 2px 0 8px 16px; border-left: 2px solid var(--rule); margin-left: 4px; }
/* The same grid as the parent row, so the hours and row-count columns line up.
   Subtract the 18px indent + the 7px colour dot + 2 gaps from the parent's label
   column. */
.rep-person {
  display: grid;
  grid-template-columns: auto minmax(140px, 507px) 320px 52px 58px;
  align-items: center; gap: 8px; padding: 2px 0;
}
.rep-person-n { width: 7px; height: 7px; border-radius: 50%; flex: none; }
.rep-person-name {
  font-size: 11.5px; color: var(--ink-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* The discipline colour dot before the label — the same colour as that row's bar */
.rep-dot {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  margin-right: 6px; vertical-align: 1px; flex: none;
}

/* ── Overview charts at the top of the Reports screen ──────────────────
   The time columns: plain divs, for responsiveness and a native title tooltip.
   The axis labels sit BELOW the gridline with a --card background, or they would
   overlap the columns. */
.rep-trend { position: relative; height: 132px; margin-top: 8px; }
.rep-grid { position: absolute; left: 0; right: 0; height: 0; border-top: 1px dashed var(--rule); }
.rep-grid span {
  position: absolute; right: 0; top: 2px; z-index: 1;
  font-size: 10.5px; color: var(--ink-3); font-family: var(--mono);
  background: var(--card); padding: 0 3px; border-radius: var(--r); opacity: .92;
}
.rep-cols { position: absolute; inset: 0; display: flex; align-items: flex-end; gap: 2px; }
.rep-col { flex: 1 1 0; min-width: 1px; height: 100%; display: flex; align-items: flex-end; }
.rep-col-fill { width: 100%; background: var(--accent); opacity: .85; border-radius: 2px 2px 0 0; }
.rep-col:hover .rep-col-fill { opacity: 1; }
.rep-cols-x {
  display: flex; justify-content: space-between; margin-top: 6px;
  font-size: 10.5px; color: var(--ink-3); font-family: var(--mono);
}

/* The composition donut: the arcs are separated by gaps (the background shows through) so they can be counted even in black and white */
.rep-donut-wrap { display: flex; align-items: center; gap: 16px; padding: 8px 0 2px; }
.rep-donut { width: 132px; height: 132px; flex: none; }
.rep-donut-n { font-size: 17px; font-weight: 700; fill: var(--ink); font-family: var(--mono); }
.rep-donut-l { font-size: 10px; fill: var(--ink-3); }
.rep-leg { display: flex; flex-direction: column; gap: 4px; min-width: 0; flex: 1; }
.rep-leg-i { display: flex; align-items: center; gap: 8px; font-size: 12.5px; min-width: 0; }
.rep-leg-dot { width: 10px; height: 10px; border-radius: var(--r); flex: none; }
.rep-leg-n { color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rep-leg-v { margin-left: auto; color: var(--ink-3); font-family: var(--mono); font-size: 11.5px; white-space: nowrap; }

@media (max-width: 720px) {
  .rep-dates { margin-left: 0; }
  .rep-filters select, .rep-filters input[type="search"] { flex: 1 1 100%; }
  .rep-donut-wrap { gap: 12px; }
  .rep-donut { width: 108px; height: 108px; }
}

/* A cell at rest — no border, no background */
.wl-v {
  display: block;
  cursor: text;
  border-radius: var(--r);
  padding: 2px 4px;
  margin: 0 -4px;
  min-height: 20px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.wl-v:hover { background: var(--rule); }
/* A cell selected with the keyboard — you must be able to see where you are while tabbing */
.wl-v:focus-visible { outline: 2px solid var(--brand2); outline-offset: -1px; background: var(--hover); }
.wl-v.muted { color: var(--ink-3); }
.wl-v.num { font-family: var(--mono); font-variant-numeric: tabular-nums; text-align: right; }
.wl-v.empty { color: var(--ink-4); font-style: italic; }

/* The cell being edited — only this one gets a border */
.wl-e {
  width: 100%;
  padding: 2px 4px;
  border: 1px solid var(--accent);
  border-radius: var(--r);
  background: var(--card);
  font-size: 13px;
  outline: none;
}
.wl-e.num { font-family: var(--mono); text-align: right; }

/* Status as a DOT, clicked to cycle Done -> Doing -> Pending.
   It was a pill carrying the word: 19 rows in 20 say "Done", so the column spent
   its width repeating a word that means "nothing to see here". The dot keeps the
   colour (which is the part that carries information) and gives the width back to
   the task. Done is a hollow ring — present, quiet, clearly not an empty cell. */
.wl-st-dot {
  width: 11px; height: 11px; padding: 0; border-radius: 50%;
  border: 1.5px solid var(--rule-2); background: transparent;
  cursor: pointer; display: block; margin: 0 auto;
  transition: transform .1s, border-color .1s, background .1s;
}
.wl-st-dot:hover { transform: scale(1.25); }
.wl-st-dot:focus-visible { outline: 2px solid var(--brand2); outline-offset: 2px; }
.wl-st-dot.done    { border-color: var(--done); }
.wl-st-dot.doing   { border-color: var(--doing);   background: var(--doing); }
.wl-st-dot.pending { border-color: var(--pending); background: var(--pending); }

/* Row-end buttons — always VISIBLE but faint, and clear on hover.
   Not opacity:0 + hover: touch screens have no hover, so the button would be
   permanently invisible, and even on desktop an invisible button forces the user
   to guess it exists at all. Faint is still readable and still clickable. */
.wl-row-acts { display: flex; gap: 1px; justify-content: flex-end; }
.wl-act {
  border: 0; background: transparent; cursor: pointer;
  color: var(--ink-4); font-size: 12px; line-height: 1;
  padding: 4px 4px; border-radius: var(--r);
  opacity: .45; transition: opacity .1s, background .1s, color .1s;
}
.wl-table tbody tr:hover .wl-act, .wl-act:focus-visible { opacity: 1; }
.wl-act:hover { background: var(--rule); color: var(--ink); opacity: 1; }
.wl-act.del:hover { background: var(--danger); color: #fff; opacity: 1; }

.wl-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 8px 12px;
  font-size: 12px;
  color: var(--ink-3);
  border-top: 1px solid var(--rule);
  background: var(--bg);
  flex-wrap: wrap;
}
.wl-foot strong { color: var(--ink); font-weight: 600; font-family: var(--mono); }
.wl-foot-hint { font-size: 11.5px; color: var(--ink-4); }

/* ============================================================
   The Week Plan tab (its own screen since 17/08/2026)
   ------------------------------------------------------------
   It began folded under the entry card, where it got whatever height was left
   and could not page forward. Given a screen of its own the columns are tall
   enough to hold a real week, and a task no longer has to fit in 16 characters.
   ============================================================ */
.pl-page { display: flex; flex-direction: column; gap: 12px; }
.pl-bar {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  background: var(--card); border: 1px solid var(--rule); border-radius: var(--r);
  padding: 12px 16px;
}
.pl-stats { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.pl-stat { font-size: var(--fs-body); color: var(--ink-3); white-space: nowrap; }
.pl-stat b {
  font-family: var(--mono); font-size: 16px; font-weight: 700; color: var(--ink);
  font-variant-numeric: tabular-nums; margin-right: 5px;
}
.pl-stat.done b   { color: var(--done); }
.pl-stat.logged b { color: var(--brand2); }
.pl-tools { display: flex; align-items: center; gap: 12px; margin-left: auto; }
.pl-hide { font-size: var(--fs-meta); color: var(--ink-3); display: flex; align-items: center; gap: 4px; cursor: pointer; }
.pl-lock { font-size: var(--fs-meta); color: var(--ink-4); font-style: italic; }
/* Export the week. Quiet by default — it is used once a week, next to a tick
   that is used all day — and only outlined on hover, like "This week" beside it. */
.pl-md {
  font-size: var(--fs-meta); padding: 3px 12px; white-space: nowrap;
  border: 1px dashed var(--rule-2); border-radius: 999px;
  background: transparent; color: var(--ink-3); cursor: pointer; font-family: inherit;
}
.pl-md:hover { border-style: solid; border-color: var(--ink-4); color: var(--ink-2); }
.wl-week-today {
  font-size: var(--fs-meta); padding: 3px 12px; margin-left: 6px;
  border: 1px dashed var(--rule-2); border-radius: 999px;
  background: transparent; color: var(--ink-3); cursor: pointer; white-space: nowrap;
}
.wl-week-today:hover { border-style: solid; border-color: var(--ink-4); color: var(--ink-2); }

/* Planned earlier and never logged. Named at the top of the board rather than
   left to age out of its week quietly — that is exactly the work that gets
   forgotten. */
.wl-pl-carry {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-bottom: 10px; padding: 8px 8px;
  background: var(--doing-bg); border-radius: var(--r);
}
.wl-pl-carry-lbl { font-size: 11.5px; color: var(--doing); font-weight: 600; }
.wl-pl-carry-chip, .wl-pl-carry-all {
  font-size: 11.5px; padding: 2px 8px; border-radius: 999px;
  border: 1px solid var(--rule-2); background: var(--card); color: var(--ink-2);
  cursor: pointer; max-width: 280px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wl-pl-carry-chip:hover, .wl-pl-carry-all:hover { border-color: var(--accent); color: var(--accent); }
.wl-pl-carry-all { margin-left: auto; font-weight: 600; }

/* ============================================================
   One DAY PER ROW, not five columns (Dat, 17/08/2026)
   ------------------------------------------------------------
   Five columns spent 340px of height each to hold one or two items, and squeezed
   the task into 240px of width — the two things a plan needs, room to read the
   sentence and no wasted space, were both on the wrong axis. A day is now a
   full-width band with its items listed under it: the same shape the timesheet
   table already uses for its days, so it is one thing to learn, not two. A week
   with three items is now ~250px instead of ~380px, and a task has the whole
   width of the screen to be legible in.
   ============================================================ */
.wl-pl-grid { display: flex; flex-direction: column; gap: 8px; }
.wl-pl-col {
  border: 1px solid var(--rule); border-radius: var(--r);
  background: var(--card);
  display: flex; flex-direction: column;
  transition: border-color .12s, background .12s;
}
.wl-pl-col.today { border-color: var(--accent); }
/* Drop target while dragging an item across days. Dashed: it reads as "a space
   waiting for something", which a solid tint does not. */
.wl-pl-col.drop {
  border-color: var(--accent); border-style: dashed; background: var(--accent-soft);
}
/* The day band. Same job as the day separator row in the timesheet table, and
   deliberately the same look: a tinted strip carrying the date and the day's
   figures, with its rows underneath. */
.wl-pl-colhead {
  display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  padding: 8px 12px; background: var(--head); border-bottom: 1px solid var(--rule);
}
.wl-pl-col.today .wl-pl-colhead { background: var(--accent-soft); }
/* There WAS a red band here for a day planned past 8.5h. Dropped 19/08/2026:
   several people share a day on this board, work is front-loaded on purpose,
   and anything carried forward lands on a day that already has work — so the
   red was on most days most of the time, and a warning that is always on is not
   a warning. The timesheet still measures its days, where an over-target figure
   really does mean somebody typed 70 instead of 7. */
.wl-pl-dow {
  font-family: var(--mono); font-size: var(--fs-body); font-weight: 700;
  color: var(--ink); letter-spacing: .02em;
}
.wl-pl-col.today .wl-pl-dow { color: var(--brand); }
.wl-pl-planned {
  font-family: var(--mono); font-size: var(--fs-meta); color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.wl-pl-logged { font-family: var(--mono); font-size: var(--fs-label); color: var(--done); }
.wl-pl-add {
  margin-left: auto; border: 0; background: transparent; cursor: pointer;
  color: var(--ink-4); font-size: 14px; line-height: 1; padding: 2px 4px; border-radius: var(--r);
}
.wl-pl-add:hover { background: var(--rule); color: var(--brand); }
.wl-pl-items { display: flex; flex-direction: column; }
.wl-pl-empty {
  margin: 0; padding: 8px 12px; font-size: var(--fs-meta); color: var(--ink-4); font-style: italic;
}
/* A permanent "add" at the foot of every column: on a screen this tall, an empty
   column should invite a line rather than announce that it is empty. */
.wl-pl-add-foot {
  margin: 8px 12px 8px; padding: 4px 8px; width: calc(100% - 20px);
  border: 1px dashed var(--rule-2); border-radius: var(--r);
  background: transparent; color: var(--ink-3); cursor: pointer;
  font-family: var(--font); font-size: var(--fs-meta); text-align: left;
}
.wl-pl-add-foot:hover { border-color: var(--brand); color: var(--brand); background: var(--accent-soft); }

/* One line per item: tick · task (takes the width) · person · project · hours ·
   delete, with the right-hand fields at fixed widths so they line up down the
   day like columns in a table. */
.wl-pl-item {
  display: flex; align-items: center; gap: 12px;
  border: 0; border-top: 1px solid var(--rule); border-radius: 0;
  background: transparent; padding: 8px 12px;
  cursor: grab;
}
.wl-pl-item:hover { background: var(--hover); }
.wl-pl-items > .wl-pl-item:first-child { border-top: 0; }
.wl-pl-item:active { cursor: grabbing; }
.wl-pl-item.dragging { opacity: .4; }
/* A ticked item is quiet, not illegible: at opacity .62 with --ink-4 the text
   measured 3.57:1 in dark mode. The strikethrough already says "done"; the
   contrast does not have to say it a second time. */
.wl-pl-item.done { opacity: .72; }
.wl-pl-item.done .wl-pl-task { text-decoration: line-through; color: var(--ink-3); }
/* ONE task several people are on: a heading, then a line each. Each of those
   lines is a real row of its own — that is what makes the tick honest, three
   people means three worklog rows — so the block reads as one task with three
   people under it rather than the same sentence written out three times. */
.wl-pl-group {
  border-top: 1px solid var(--rule);
  padding: 8px 12px;
  cursor: grab;
}
.wl-pl-items > .wl-pl-group:first-child { border-top: 0; }
.wl-pl-group:hover { background: var(--hover); }
.wl-pl-group:active { cursor: grabbing; }
.wl-pl-group.dragging { opacity: .4; }
.wl-pl-group.done { opacity: .72; }
.wl-pl-group.done .wl-pl-task { text-decoration: line-through; color: var(--ink-3); }
/* The heading is built from the SAME two halves as a one-person row — .wl-pl-line
   takes the width, .wl-pl-meta is fixed — so the person, project and hours
   columns land on the same x whether a task has one person on it or four. */
.wl-pl-ghead { display: flex; align-items: center; gap: 12px; }
/* Shut by default, and the caret is the only thing that opens it: a real button
   at the TICK'S width, so the task text starts on the same x on every row. */
.wl-pl-gcaret {
  /* 30px and a 21px glyph — half again on both, and the biggest control on the
     row, because opening a shared task is the one thing you do to it most.
     The negative margin is the point of the whole rule: it pulls the outer box
     back to 20px, the tick's width, so the button is half again bigger to the
     eye and the hand while the task text still starts on the same x as every
     one-person row in the day. Grow the box for real and the sentence on a
     shared task sits 10px right of its neighbours. */
  flex: none; width: 30px; height: 30px; margin: -5px; padding: 0;
  border: 1px solid transparent; background: transparent; color: var(--ink-3);
  font-size: 21px; line-height: 1; cursor: pointer; border-radius: 50%;
  display: grid; place-items: center;
}
.wl-pl-gcaret:hover { border-color: var(--rule-2); background: var(--card); color: var(--ink-2); }
/* The person column. min-width rather than width: one chip sits exactly where a
   one-person row's picker sits, and a fourth name grows the block LEFTWARDS —
   so the boundary with the project column never moves, on any row of the week. */
.wl-pl-gwho {
  display: flex; align-items: center; justify-content: flex-end; gap: 4px;
  flex-wrap: wrap; min-width: 76px; flex: none;
}
.wl-pl-gchip {
  font-family: var(--mono); font-size: var(--fs-label); font-weight: 600;
  color: var(--oc); border: 1px solid var(--oc); border-radius: 999px;
  padding: 0 7px; line-height: 17px; white-space: nowrap;
}
/* Finished is struck through, the same signal a ticked line carries when the
   task is open — so folding it away never hides who is already done. */
.wl-pl-gchip.done { text-decoration: line-through; opacity: .6; }
/* How many are finished, at the head of the person column rather than in front
   of the task, where it would push the sentence out of line with its neighbours. */
.wl-pl-gn {
  /* Nudged up with the caret: 10.5px beside a 14px glyph read as an afterthought
     rather than the state of the row. */
  flex: none; font-family: var(--mono); font-size: var(--fs-meta); font-weight: 700;
  color: var(--ink-3); font-variant-numeric: tabular-nums; margin-right: 1px;
}
.wl-pl-group.done .wl-pl-gn { color: var(--done); }
/* Sits in the hours column, and reads as a total rather than a box to type in. */
.wl-pl-gsum {
  display: inline-block; color: var(--ink-4); border: 1px solid transparent;
  background: transparent; padding: 1px 3px;
}
/* The people list hangs off its button, so the button needs to be the origin. */
.wl-pl-pwrap { position: relative; display: inline-flex; flex: none; }
.wl-pl-people {
  border: 1px solid transparent; border-radius: var(--r);
  background: transparent; color: var(--ink-4);
  /* Big enough to read as a control rather than a smudge, and a 24px target
     rather than the 17px it was — this is the only way to add somebody to a
     task, so it should not need aiming at. */
  font-size: 14px; line-height: 1; padding: 4px 5px; cursor: pointer;
}
.wl-pl-item:hover .wl-pl-people,
.wl-pl-group:hover .wl-pl-people { border-color: var(--rule); color: var(--ink-2); }
.wl-pl-people:hover { border-color: var(--brand) !important; }
.wl-pl-pmenu { right: 0; left: auto; }
.wl-pl-ghead .wl-pl-task { flex: 1; min-width: 0; }
/* The pill version of .wl-pl-gn that used to live here is gone. It was written
   when the count sat in front of the task, and it stayed behind when the count
   moved into the person column — sitting LATER in the file, it quietly won over
   the rule that replaced it, so every size change made up there did nothing. */
/* Indented to where the task text starts (the caret's 20px plus the 8px gap), so
   the people hang under the sentence they belong to. */
.wl-pl-subs { display: flex; flex-direction: column; margin: 4px 0 0 28px; }
.wl-pl-sub { display: flex; align-items: center; gap: 8px; padding: 3px 0; }
.wl-pl-sub.done { opacity: .72; }
.wl-pl-sub .wl-pl-h { margin-left: auto; }

/* Who the next item is for — the tick-list beside the add box. */
.wl-pl-addbox { position: relative; }
.wl-pl-own { position: relative; margin-top: 6px; }
.wl-pl-ownbtn {
  border: 1px solid var(--rule); border-radius: var(--r);
  background: var(--card-solid); color: var(--ink-2);
  font: inherit; font-size: var(--fs-label); padding: 3px 8px; cursor: pointer;
}
.wl-pl-ownbtn:hover { border-color: var(--brand); }
/* More than one person picked: this is about to write several rows, and that is
   worth saying before Enter rather than after. */
.wl-pl-ownbtn.many { border-color: var(--brand); color: var(--brand); font-weight: 700; }
.wl-pl-ownmenu {
  position: absolute; z-index: 20; top: calc(100% + 4px); left: 0; min-width: 190px;
  background: var(--card-solid); border: 1px solid var(--rule-2); border-radius: var(--r);
  box-shadow: 0 12px 32px -12px var(--glass-shadow); padding: 4px;
}
.wl-pl-ownrow {
  display: flex; align-items: center; gap: 8px;
  padding: 5px 7px; border-radius: var(--r); cursor: pointer; font-size: var(--fs-meta);
}
.wl-pl-ownrow:hover { background: var(--hover); }
.wl-pl-ownname { color: var(--oc); font-weight: 600; }
.wl-pl-ownfoot {
  font-size: var(--fs-label); color: var(--ink-4);
  padding: 6px 7px 3px; border-top: 1px solid var(--rule); margin-top: 4px;
}

.wl-pl-line { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }
.wl-pl-tick {
  width: 20px; height: 20px; flex: none;
  border: 1px solid var(--rule-2); background: var(--card);
  border-radius: 50%; cursor: pointer; color: var(--ink-4);
  font-size: 11px; line-height: 1; display: grid; place-items: center;
  transition: border-color .1s, background .1s, color .1s;
}
.wl-pl-tick:hover { border-color: var(--done); background: var(--done-bg); color: var(--done); }
/* The task at rest: TEXT, not an <input> — the input cut "Check drawing SHP1
   tower B" off at "Check drawing SH", and a board you cannot read is not a plan.
   With a full-width row it needs one line and no clamping. Click to edit, the
   same rule the timesheet cells follow. */
.wl-pl-task {
  flex: 1; min-width: 0; cursor: text;
  font-size: var(--fs-body); line-height: 1.4; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  border-radius: var(--r); padding: 2px 4px; margin: 0 -4px;
}
.wl-pl-task:hover { background: var(--hover); }
.wl-pl-task:focus-visible { outline: 2px solid var(--brand2); outline-offset: -1px; }
.wl-pl-task-e {
  flex: 1; min-width: 0; font-family: var(--font); font-size: var(--fs-body);
  padding: 1px 4px; border: 1px solid var(--accent); border-radius: var(--r);
  background: var(--card-solid); color: var(--ink); outline: none;
}
.wl-pl-meta { display: flex; align-items: center; gap: 8px; flex: none; }
/* The person is a SELECT, not a label — work gets handed over mid-week. It keeps
   the owner-coloured chip look: `appearance: none` drops the native arrow, which
   does not fit beside a name in this width, and the hover tint is what says it
   can be changed (the same affordance the project and hours cells use). */
.wl-pl-who {
  width: 76px; text-align: center;
  font-family: var(--mono); font-size: var(--fs-label); font-weight: 600;
  color: var(--oc); border: 1px solid var(--oc); border-radius: var(--r);
  padding: 1px 4px; flex: none; overflow: hidden; white-space: nowrap;
  appearance: none; -webkit-appearance: none;
  background: transparent; cursor: pointer;
}
.wl-pl-item:hover .wl-pl-who { background: var(--card-solid); }
.wl-pl-who:focus { border-color: var(--accent); background: var(--card-solid); outline: none; }
/* The options themselves are drawn by the OS menu, which does not inherit --oc —
   left unset they can come out white-on-white in dark mode. */
.wl-pl-who option { color: var(--ink); background: var(--card-solid); }
.wl-pl-proj, .wl-pl-h {
  border: 1px solid transparent; border-radius: var(--r);
  padding: 1px 3px; background: transparent;
  font-size: var(--fs-meta); color: var(--ink-3);
}
.wl-pl-proj { width: 132px; flex: none; font-family: var(--mono); }
.wl-pl-h {
  width: 48px; flex: none; font-family: var(--mono); text-align: right;
  font-variant-numeric: tabular-nums;
}
.wl-pl-item:hover .wl-pl-proj,
.wl-pl-item:hover .wl-pl-h { border-color: var(--rule); background: var(--bg); }
.wl-pl-proj:focus, .wl-pl-h:focus {
  border-color: var(--accent); background: var(--card-solid); outline: none;
}
.wl-pl-x {
  border: 0; background: transparent; cursor: pointer;
  color: var(--ink-4); padding: 2px 4px; border-radius: var(--r); font-size: 10px;
  opacity: .4; transition: opacity .1s, background .1s;
}
.wl-pl-item:hover .wl-pl-x, .wl-pl-x:focus-visible { opacity: 1; }
.wl-pl-x:hover { background: var(--danger); color: #fff; opacity: 1; }

.wl-pl-addbox { padding: 8px 12px 8px; }
.wl-pl-input {
  width: 100%; padding: 8px 8px; font-size: var(--fs-body); font-family: var(--font);
  border: 1px solid var(--accent); border-radius: var(--r);
  background: var(--card-solid); color: var(--ink); outline: none;
}
.wl-pl-hint { font-size: var(--fs-meta); color: var(--ink-3); }
.wl-pl-hint b { font-family: var(--mono); color: var(--ink-3); font-weight: 600; }

@media (max-width: 900px) {
  .pl-bar { gap: 12px; }
  .pl-tools { margin-left: 0; }
}
@media (max-width: 560px) {
  /* The fixed right-hand fields stop fitting beside the task — let the row wrap
     and give the meta group its own line under the task. */
  .wl-pl-item { flex-wrap: wrap; gap: 8px; }
  .wl-pl-line { flex: 1 0 100%; }
  .wl-pl-meta { margin-left: 29px; }
  .wl-pl-proj { width: 108px; }
}

/* The planned items for the day being logged, right above the input — the payoff
   for having written the plan. Marked with the accent: it is the one chip row
   left in the card, and it is meant to be read first. */
.wl-plans {
  display: flex; gap: 5px; flex-wrap: wrap; align-items: center;
  margin-top: 9px; padding-top: 9px; border-top: 1px solid var(--rule);
}
.wl-plan-chip {
  font-size: 12px; padding: 3px 10px; border-radius: 999px;
  border: 1px solid var(--accent); background: var(--accent-soft); color: var(--accent);
  cursor: pointer; white-space: nowrap; max-width: 300px; overflow: hidden; text-overflow: ellipsis;
}
.wl-plan-chip:hover { background: var(--accent); color: var(--accent-fg); }
.wl-plan-chip-m { font-family: var(--mono); font-size: 11px; opacity: .75; margin-left: 5px; }

/* A planned task inside the autocomplete list */
.wl-ac-item.plan .wl-ac-meta { color: var(--accent); font-weight: 600; }



/* ===== Empty states ===== */

.empty-state {
  text-align: center;
  padding: 44px 20px;
  color: var(--ink-3);
  font-size: 13.5px;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--r);
}
.empty-icon { font-size: 26px; margin-bottom: 8px; opacity: .5; }

/* ===== Toast ===== */

#toast {
  position: fixed; left: 50%; bottom: 24px;
  transform: translateX(-50%) translateY(16px);
  background: #1E252B; color: #fff;
  padding: 10px 15px; border-radius: var(--r);
  font-size: 13px; display: flex; align-items: center; gap: 12px;
  opacity: 0; pointer-events: none;
  transition: opacity .16s, transform .16s;
  z-index: 999;
  box-shadow: 0 6px 24px rgba(0,0,0,.22);
  max-width: calc(100vw / var(--ui-zoom) - 32px);
}
#toast.show { opacity: 1; transform: translateX(-50%) translateY(0); pointer-events: auto; }
#toast.warn { background: #8A3E10; }
#toast button {
  background: rgba(255,255,255,.16); color: #fff; border: 0;
  padding: 4px 10px; border-radius: var(--r); cursor: pointer; font-size: 12px; font-weight: 600;
}
#toast button:hover { background: rgba(255,255,255,.26); }

/* ===== The "done" popup =====
   Ticking something off the plan is the one moment on this screen worth marking,
   and it used to get the same 3-second corner toast as "row deleted". It comes
   down from the top, where the eye already is after clicking a tick near the top
   of a day, and it carries the one thing a toast has no room for: how much of
   the day is left. */
#donepop {
  position: fixed; left: 50%; top: 0; z-index: 1000;
  transform: translateX(-50%) translateY(-14px);
  opacity: 0; pointer-events: none;
  transition: opacity .18s ease, transform .18s cubic-bezier(.2,.9,.3,1.1);
  max-width: calc(100vw / var(--ui-zoom) - 24px);
}
#donepop.show {
  opacity: 1; pointer-events: auto;
  transform: translateX(-50%) translateY(calc(var(--tlc-top-h, 57px) + 12px));
}
.dp-card {
  display: flex; align-items: flex-start; gap: 12px;
  min-width: 320px; max-width: 460px;
  padding: 12px 14px;
  background: var(--card-solid); color: var(--ink);
  border: 1px solid var(--rule-2); border-left: 3px solid var(--done);
  border-radius: var(--r);
  box-shadow: 0 18px 48px -16px var(--glass-shadow), 0 3px 10px -6px var(--glass-shadow);
}
.dp-tick {
  flex: none; width: 26px; height: 26px; border-radius: 50%;
  background: var(--done); color: #fff;
  display: grid; place-items: center; font-size: 14px; line-height: 1;
}
.dp-body { flex: 1; min-width: 0; }
.dp-task {
  font-size: var(--fs-lead); font-weight: 700; line-height: 1.25;
  word-break: break-word;
}
.dp-meta { font-size: var(--fs-meta); color: var(--ink-2); margin-top: 3px; }
.dp-warn { color: var(--doing); }
/* The line this popup exists for: what is LEFT. */
.dp-prog {
  display: flex; align-items: center; gap: 8px;
  font-size: var(--fs-meta); color: var(--ink-2); margin-top: 8px;
}
.dp-prog.all { color: var(--done); font-weight: 700; }
.dp-bar {
  flex: none; width: 84px; height: 5px; border-radius: 2px;
  background: var(--rule); overflow: hidden;
}
.dp-bar > i { display: block; height: 100%; background: var(--done); border-radius: 2px; }
.dp-acts { display: flex; align-items: center; gap: 4px; flex: none; }
.dp-undo {
  border: 1px solid var(--rule-2); background: var(--card); color: var(--ink-2);
  font: inherit; font-size: var(--fs-label); font-weight: 700;
  padding: 4px 10px; border-radius: var(--r); cursor: pointer;
}
.dp-undo:hover { border-color: var(--brand); color: var(--brand); }
.dp-x {
  border: 0; background: transparent; color: var(--ink-4);
  font-size: 12px; line-height: 1; padding: 4px 5px; border-radius: var(--r); cursor: pointer;
}
.dp-x:hover { background: var(--hover); color: var(--ink-2); }
/* The app's second animation, and held to the same terms as the first: one short
   move, played once, and gone entirely when the machine asks for less motion. */
@media (prefers-reduced-motion: reduce) {
  #donepop { transition: none; }
}
@media (max-width: 560px) {
  .dp-card { min-width: 0; }
  #donepop { left: 12px; right: 12px; transform: none; max-width: none; }
  #donepop.show { transform: translateY(calc(var(--tlc-top-h, 57px) + 12px)); }
}

/* ===== Time Sheet: the project status panel on the left =====
   A narrow column beside the sheet, so "where is KGH up to" is answered while
   you are logging work against it rather than on another screen. It STICKS: the
   table below it is long, and a status panel that scrolls away has stopped
   being a status panel. */
/* Wider than the app's 1180px column, because the panel's quarter came to about
   290px inside it — four card columns of 60px, and the project code rendered as
   one letter. But NOT the whole window: edge to edge on a 27" monitor the sheet
   read as a wall, the same objection as on the Week Plan (Dat, 09/09/2026). So
   the same cap and the same centring as that tab, and the panel sits at the
   left of the COLUMN with white space outside it rather than against the glass.

   Done with :has() rather than a class toggled in render(): the rule belongs to
   the layout, and a class set by JS on a shared element is one more thing to
   remember to take off again when the tab changes. */
.tlc-body:has(> #view > .wl-split) { max-width: 1600px; }
/* A quarter of the window to the panel, the rest to the sheet. Proportional
   rather than a fixed width so the ratio holds on a laptop and on a 27" monitor
   alike; the 250px floor stops the four columns collapsing into slivers on the
   narrow end, and the 460px ceiling stops the panel sprawling on a wide one —
   past that it is just a board with too much air in it. */
.wl-split {
  display: grid;
  grid-template-columns: clamp(250px, 25%, 460px) minmax(0, 1fr);
  gap: 16px; align-items: start;
}
/* Shut, the panel is a strip about 30px wide and the sheet has the rest. */
.wl-split.ps-shut { grid-template-columns: auto minmax(0, 1fr); gap: 10px; }
.wl-main { min-width: 0; padding-right: 4px; }
/* A card again, with all four borders. It lost its left edge while it was docked
   against the glass, where a border would have been a line drawn down the side
   of the screen; inside a centred column that same missing edge just looks like
   a card someone forgot to finish. */
.ps-panel {
  position: sticky; top: calc(var(--tlc-top-h, 57px) + 10px);
  background: var(--card); border: 1px solid var(--rule); border-radius: var(--r);
  padding: 11px;
}
.ps-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 6px;
  font-weight: 700; font-size: var(--fs-lead);
}
/* Putting the board away. Quiet — it sits next to a heading, not in a toolbar —
   and it stays out of the tab order's way by being the last thing in the head. */
.ps-hide {
  flex: none; border: 1px solid transparent; background: transparent;
  color: var(--ink-4); font-size: 12px; line-height: 1;
  padding: 3px 6px; border-radius: var(--r); cursor: pointer;
}
.ps-hide:hover { border-color: var(--rule-2); color: var(--ink-2); background: var(--card-solid); }
/* And bringing it back: a strip down the left of the column, written the long
   way so it costs about 30px instead of 300. Fully bordered now, like the panel
   it stands in for. */
.ps-tab {
  position: sticky; top: calc(var(--tlc-top-h, 57px) + 10px);
  writing-mode: vertical-rl; transform: rotate(180deg);
  padding: 12px 7px; cursor: pointer;
  border: 1px solid var(--rule); border-radius: var(--r);
  background: var(--card); color: var(--ink-3);
  font: inherit; font-size: var(--fs-label); font-weight: 700; letter-spacing: .04em;
}
.ps-tab:hover { color: var(--brand); border-color: var(--brand); }
/* Something is on fire and the board is put away — say so on the strip. */
.ps-tab.hot { color: var(--prio-high); border-color: color-mix(in srgb, var(--prio-high) 45%, var(--rule)); }
.ps-sub { display: block; font-weight: 400; font-size: var(--fs-label); color: var(--ink-3); margin-top: 2px; }
/* The year filter. This year and last are on when the panel opens; the older
   ones are here, off, one click from coming back — so the default view is what
   the team is working on rather than everything since 2024. */
.ps-years { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 9px; }
.ps-yr {
  display: inline-flex; align-items: center; gap: 5px;
  font-family: var(--mono); font-size: var(--fs-label); font-weight: 700;
  padding: 3px 8px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--rule-2); background: transparent; color: var(--ink-4);
}
.ps-yr:hover { border-color: var(--brand); color: var(--ink-2); }
.ps-yr.on { border-color: var(--brand); background: var(--accent-soft); color: var(--brand); }
.ps-yrn { font-weight: 400; opacity: .75; font-variant-numeric: tabular-nums; }
/* The year on a card. Borderless until touched — it is a value, not a form
   field — and faint when it was worked out from the worklog rather than typed,
   so a guess never reads as something somebody stated. */
.ps-year {
  display: block; width: 100%; text-align: left;
  font-family: var(--mono); font-size: var(--fs-label); font-weight: 700;
  border: 1px solid transparent; border-radius: var(--r);
  background: transparent; color: var(--ink-2); padding: 0 2px;
  -moz-appearance: textfield;
}
.ps-year::-webkit-outer-spin-button,
.ps-year::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.ps-year.auto { color: var(--ink-4); font-weight: 400; font-style: italic; }
.ps-item:hover .ps-year { border-color: var(--rule-2); background: var(--card); }
.ps-year:focus { border-color: var(--accent); background: var(--card-solid); color: var(--ink); outline: none; }
/* Done · Pending · Running · Urgent — so where a project stands is answered by
   WHICH COLUMN it is in, before any colour or label is read. Archive is the
   fifth, and it spans the row underneath instead of taking a fifth of the width:
   it holds the projects nobody opens, and it must not shrink the four that are
   read every day in order to show them. */
.ps-cols { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 5px; margin-top: 10px; }
.ps-col { display: flex; flex-direction: column; gap: 7px; min-width: 0; }
.ps-col.ps-wide { grid-column: 1 / -1; margin-top: 5px; }
/* Open, the archive lays its cards out across the row rather than in one long
   file — it is the column that grows for ever, and forty projects stacked would
   push the legend off the bottom of the panel. */
.ps-drop.ps-wrap {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(118px, 1fr));
  align-content: start;
}
.ps-drop.ps-wrap.shut { display: block; min-height: 0; }
.ps-colhead {
  display: flex; align-items: center; justify-content: space-between; gap: 5px;
  font-size: var(--fs-label); font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-3);
  padding-bottom: 5px; border-bottom: 2px solid var(--rule-2);
}
/* Urgent is the only column that gets a colour of its own. Pending and Running
   are ordinary states; a board where all three shout has nothing left to say
   when one of them matters. */
.ps-col.s-urgent .ps-colhead { color: var(--prio-high); border-bottom-color: var(--prio-high); }
.ps-n {
  font-family: var(--mono); font-weight: 700; color: var(--ink-4);
  font-variant-numeric: tabular-nums;
}
.ps-col.s-urgent .ps-n { color: var(--prio-high); }
/* Done is finished work: present, checkable, and quiet. It is the column that
   will grow longest over the years, so it must not compete with the three that
   are asking for something. Dimmed as a whole rather than struck through —
   these are projects, not ticked-off tasks. */
.ps-col.s-done .ps-colhead { color: var(--done); border-bottom-color: var(--done); }
.ps-col.s-done .ps-n { color: var(--done); }
.ps-item.s-done { opacity: .62; background: transparent; }
.ps-item.s-done:hover,
.ps-item.s-done:focus-within { opacity: 1; background: var(--card-solid); }
/* Archive: quieter still, and dashed rather than solid — these are not projects
   in a state, they are projects that left. Dimmed as a whole, never struck
   through: the work happened, it just stopped. */
.ps-col.s-archive .ps-colhead { color: var(--ink-4); border-bottom-style: dashed; }
.ps-item.s-archive { opacity: .55; background: transparent; border-style: dashed; }
.ps-item.s-archive:hover,
.ps-item.s-archive:focus-within { opacity: 1; background: var(--card-solid); border-style: solid; }
.ps-item.s-archive .ps-track { display: none; }
/* The archive heading is a button, and has to stop looking like one. */
.ps-fold {
  width: 100%; font: inherit; font-size: var(--fs-label); font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase;
  background: transparent; border: 0; border-bottom: 2px dashed var(--rule-2);
  cursor: pointer; text-align: left;
}
.ps-fold:hover { color: var(--ink-2); border-bottom-color: var(--brand); }
.ps-caret { font-size: 10px; margin-right: 5px; color: var(--ink-4); }
.ps-empty { font-size: var(--fs-label); color: var(--ink-4); font-style: italic; padding: 4px 0; }
.ps-foldbtn {
  display: block; width: 100%; text-align: left;
  font-family: inherit; background: transparent; border: 0; cursor: pointer;
}
.ps-foldbtn:hover { color: var(--ink-2); }
/* The drop zone is the column BODY, and it keeps a minimum height so an empty
   column is still a target you can hit. */
.ps-drop {
  display: flex; flex-direction: column; gap: 7px;
  min-height: 54px; border-radius: var(--r); padding: 2px;
  border: 1px dashed transparent;
}
.ps-drop.over { border-color: var(--accent); background: var(--accent-soft); }
.ps-item { cursor: grab; }
.ps-item:active { cursor: grabbing; }
.ps-item.dragging { opacity: .4; }
/* Where it will land, drawn on the card it will go IN FRONT OF — a column that
   only lights up says it will take the card, not where the card is going. */
.ps-item.ins { box-shadow: 0 -3px 0 -1px var(--accent); }
.ps-item {
  border: 1px solid var(--rule); border-radius: var(--r);
  background: var(--card-solid); padding: 6px 6px 5px;
}
/* On the CARD rather than on the column, so it survives being dragged, being
   read after the heading has scrolled away, and the narrow layout where the
   columns stack. */
.ps-item.s-urgent { border-color: color-mix(in srgb, var(--prio-high) 45%, var(--rule)); }
/* The word itself. Small, but the one red thing on a panel that is otherwise all
   greys — which only works because nothing else here shouts. */
.ps-flag {
  margin: 5px 0 0; padding: 1px 5px; border-radius: var(--r);
  font-size: var(--fs-label); font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; text-align: center;
  color: var(--prio-high);
  background: color-mix(in srgb, var(--prio-high) 13%, transparent);
  border: 1px solid color-mix(in srgb, var(--prio-high) 35%, transparent);
}
/* And in the mover below it, so the word there reads as the state the project is
   in rather than only as somewhere it could be sent. */
.ps-item.s-urgent .ps-move { color: var(--prio-high); font-weight: 700; }
/* The code gets a LINE, not the space left over.
   Side by side with the year it lost: a card in a four-column panel is about
   83px wide inside its padding, the year input took a fixed 46 of them, and
   'KGH1' came out as 'K'. Horizontal room is the scarce thing here and vertical
   room is not — the cards are short and the panel has the sheet's full height
   beside it — so the two stack. Nothing else on the card matters if the project
   cannot be named. */
.ps-top { display: block; }
.ps-code {
  display: block;
  font-family: var(--mono); font-weight: 700; font-size: var(--fs-meta);
  line-height: 1.25;
  /* Wrapped rather than clipped: a long code takes a second line and is still
     READ. `anywhere` because these are codes, not prose — there is no space in
     'WALFRAME-2' to break at. */
  white-space: normal; overflow-wrap: anywhere;
}
/* The phase IN WORDS, above the track. The track is the second cue, never the
   only one — three steps of colour cannot be told apart at a glance and must not
   have to be. */
.ps-phase { font-size: var(--fs-label); color: var(--ink-2); text-align: right; }
.ps-item.unset .ps-phase { color: var(--ink-4); font-style: italic; }
.ps-track { display: flex; gap: 3px; margin: 6px 0 5px; }
.ps-track > i { flex: 1; height: 5px; border-radius: 2px; background: var(--rule); }
.ps-track > i.on { background: var(--brand2); }
/* The step it is ON, rather than merely past: the filled run alone says "at
   least here", and the question is where it stopped. */
.ps-track > i.here { background: var(--brand); box-shadow: 0 0 0 2px var(--accent-soft); }
/* Priority: a stripe down the left of the item, in the SAME two hues the
   long-term checklist uses. 'Normal' gets none — 64 projects each wearing a
   badge is 64 badges saying nothing, and the point is that a handful stand out.
   The stripe is on every item so nothing shifts when a ranking changes. */
/* The column-mover. Quiet by default — you set it and forget it — and it is the
   second control on a card that is only 100px wide, so it earns its space by
   being small rather than by being loud. */
.ps-move { margin-top: 3px; color: var(--ink-4); }
/* Drawn by the OS menu, which inherits none of the above. */
.ps-set option { color: var(--ink); background: var(--card-solid); }

.ps-set {
  width: 100%; min-width: 0; font: inherit; font-size: var(--fs-label);
  padding: 3px 5px; border-radius: var(--r);
  border: 1px solid transparent; background: transparent; color: var(--ink-3); cursor: pointer;
}
.ps-item:hover .ps-set { border-color: var(--rule-2); background: var(--card-solid); }
.ps-set:focus { border-color: var(--accent); background: var(--card-solid); outline: none; }
.ps-legend {
  display: flex; gap: 10px; margin-top: 11px; padding-top: 9px;
  border-top: 1px solid var(--rule); font-size: var(--fs-label); color: var(--ink-4);
}
.ps-legend span { display: inline-flex; align-items: center; gap: 4px; }
.ps-dot { width: 7px; height: 7px; border-radius: 2px; background: var(--rule); display: inline-block; }
.ps-dot.s0, .ps-dot.s1 { background: var(--brand2); }
.ps-dot.s2 { background: var(--brand); }
/* Narrow: the panel goes ABOVE the sheet rather than squeezing the table into a
   column too thin to read. It stops sticking there — two sticky blocks on a
   phone leave nothing to scroll. */
@media (max-width: 1240px) {
  /* Stacked, so the wider column has nothing left to buy — back to the app's
     own 1180px. The panel's borders need no repair here any more: it stopped
     being docked against the glass and carries all four at every width. */
  .tlc-body:has(> #view > .wl-split) { max-width: 1180px; }
  .wl-split, .wl-split.ps-shut { grid-template-columns: 1fr; }
  .ps-panel { position: static; }
  /* Above the sheet there is no left edge to run down, so the strip lies flat
     and takes the width instead of the height. */
  .ps-tab {
    position: static; writing-mode: horizontal-tb; transform: none;
    width: 100%; padding: 8px 12px; text-align: left;
  }
}
/* Four abreast stops fitting well before the page does: two rows of two keeps a
   project code readable, and the grouping — not the row of four — is the point. */
@media (max-width: 820px) {
  .ps-cols { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
}
@media (max-width: 460px) {
  .ps-cols { grid-template-columns: 1fr; }
}

/* ===== KPI =====
   One row a person, two measures side by side, each with a bar scaled to the
   biggest in the table — the question is who carried more of it, and a shared
   scale is the only thing that answers that. */
/* The two measure ticks. Beside the project picker rather than up with the date
   presets: the presets say WHEN, these say WHAT, and mixing the two rows made
   both harder to find. */
.kpi-tick {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12.5px; font-weight: 600; color: var(--ink-2);
  padding: 5px 10px; border: 1px solid var(--rule-2); border-radius: var(--r);
  background: var(--card); cursor: pointer; white-space: nowrap;
}
.kpi-tick:hover { border-color: var(--brand); color: var(--ink); }
.kpi-tick input { cursor: pointer; }
/* The unit, in the header, because the two columns are counted differently and
   that is the single most misread thing on this screen. */
.kpi-unit {
  font-weight: 400; font-size: var(--fs-label); color: var(--ink-4);
  text-transform: uppercase; letter-spacing: .06em; margin-left: 5px;
}
.kpi-proj {
  padding: 6px 10px; border-radius: var(--r);
  border: 1px solid var(--rule-2); background: var(--card); color: var(--ink);
  font-size: 13px; font-weight: 600; cursor: pointer;
}
.kpi-table td, .kpi-table th { vertical-align: middle; }
.kpi-table tbody tr.kpi-row { cursor: pointer; }
.kpi-table tbody tr.kpi-row:hover { background: var(--hover); }
.kpi-table tbody tr.kpi-row.open { background: var(--accent-soft); }
.kpi-who { font-weight: 700; white-space: nowrap; }
.kpi-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; margin-right: 8px; vertical-align: 0; }
.kpi-num { font-family: var(--mono); font-variant-numeric: tabular-nums; white-space: nowrap; }
.kpi-num b { font-size: 14px; }
/* The second figure of the pair — the hours behind the count, or the count
   behind the hours. Quiet: it answers the follow-up, not the question. */
.kpi-sub { display: block; font-size: var(--fs-label); color: var(--ink-4); }
.kpi-bar { width: 22%; min-width: 60px; }
.kpi-bar > i { display: block; height: 8px; border-radius: 2px; min-width: 2px; }
/* A figure you can open. The affordance is on the number itself rather than the
   row, because the row already does something else — it shows the rest of the
   person's time. */
.kpi-click { cursor: pointer; border-radius: var(--r); }
.kpi-click:hover { background: var(--hover); box-shadow: inset 0 -2px 0 var(--brand); }
.kpi-click.on { background: var(--accent-soft); box-shadow: inset 0 -2px 0 var(--brand); }
.kpi-who { cursor: pointer; }

/* The opened rows are rows of THIS table — same columns, so the list reads as
   what is behind the figure above it rather than as a box parked underneath. A
   left edge in the person's own colour ties the run of them to whose they are. */
.kpi-detail td { background: var(--bg); }
.kpi-dhead td {
  font-size: var(--fs-meta); color: var(--ink-2);
  padding-top: 8px; border-bottom: 1px solid var(--rule-2);
}
.kpi-drow td {
  background: var(--bg); font-size: var(--fs-meta);
  padding: 4px 8px; border-bottom: 1px solid var(--rule);
}
.kpi-drow:hover td { background: var(--hover); }
.kpi-dd { font-family: var(--mono); color: var(--ink-3); white-space: nowrap; width: 1%; }
.kpi-dp { font-family: var(--mono); color: var(--ink-3); white-space: nowrap; width: 1%; }
.kpi-dt { color: var(--ink); }
/* The project under the date, for the narrow layout where the two share a cell. */
.kpi-dp2 { display: block; font-size: var(--fs-label); color: var(--ink-4); }
.kpi-dh2 {
  font-family: var(--mono); text-align: right; white-space: nowrap;
  width: 1%; color: var(--ink-2); font-variant-numeric: tabular-nums;
}
.kpi-kinds { display: flex; flex-wrap: wrap; gap: 6px; }
.kpi-kind {
  font-size: var(--fs-label); color: var(--ink-2);
  border: 1px solid var(--rule); border-radius: 999px; padding: 2px 9px; background: var(--card);
}
@media (max-width: 720px) {
  /* The bars are the first thing to go: the figures beside them say it exactly,
     and a 30px bar says nothing at all. */
  .kpi-bar { display: none; }
}

/* ===== Clash — statistics ===== */

.cl-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 16px;
}
.cl-filter { display: flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--ink-3); }
.cl-filter select {
  padding: 6px 10px; border-radius: var(--r);
  border: 1px solid var(--rule-2); background: var(--card); color: var(--ink);
  font-size: 13px; font-weight: 600; cursor: pointer;
}
.cl-toolbar .btn-primary { margin-left: auto; }

.cl-kpis { display: flex; gap: 10px; margin-bottom: 16px; flex-wrap: wrap; }
.cl-kpi {
  background: var(--card); border: 1px solid var(--rule);
  border-radius: var(--r); padding: 12px 20px; min-width: 96px;
}
.cl-kpi-n { font-size: 26px; font-weight: 700; font-family: var(--mono); line-height: 1; letter-spacing: -0.02em; }
.cl-kpi-l {
  font-size: 10.5px; color: var(--ink-3); font-family: var(--mono);
  letter-spacing: 0.08em; text-transform: uppercase; margin-top: 4px;
}

.cl-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 10px;
  margin-bottom: 10px;
  /* start rather than stretch: a card with little content keeps its own height
     instead of being stretched to match a long one and left with a blank patch. */
  align-items: start;
}
.cl-card {
  background: var(--card); border: 1px solid var(--rule);
  border-radius: var(--r); padding: 12px 14px;
}
/* A card holding a single status line — don't let a title plus empty space eat 90px */
.cl-card-slim { padding-bottom: 12px; }
.cl-card-slim .cl-card-h { margin-bottom: 6px; }
/* A card standing alone in the grid (e.g. only "Not free" remains because nothing
   is free yet): don't stretch to the full 1130px — the package row would spread
   out with the name at one end and the Rev/clash count at the other, forcing the
   eye to sweep the whole screen. */
.cl-grid > .cl-card:only-child { max-width: 660px; }
.cl-card-wide { margin-bottom: 12px; }
.cl-card-h {
  font-size: 12px; font-weight: 700; color: var(--ink-2);
  margin-bottom: 12px; display: flex; align-items: center; gap: 8px;
}
.cl-card-sub {
  font-family: var(--mono); font-size: 11px; font-weight: 600;
  background: var(--rule); color: var(--ink-2); padding: 1px 7px; border-radius: 999px;
}

.cl-rows { display: flex; flex-direction: column; gap: 8px; }
.cl-row {
  display: grid;
  grid-template-columns: minmax(90px, 150px) 1fr 40px;
  align-items: center; gap: 10px;
  width: 100%;
}
.cl-row-btn { border: 0; background: transparent; cursor: pointer; text-align: left; padding: 2px 0; border-radius: var(--r); }
.cl-row-btn:hover { background: var(--hover); }
.cl-row-lbl {
  font-size: 12.5px; color: var(--ink-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cl-row-n { font-family: var(--mono); font-size: 13px; font-weight: 600; text-align: right; }
/* The proportion bar: thin and lightly rounded — 25 rows of thick, fully rounded
   bars make the page look like an advertisement, when this is a table of numbers
   to be looked up. */
.cl-bar { height: 6px; background: var(--rule); border-radius: 2px; overflow: hidden; }
.cl-bar-fill { height: 100%; background: var(--accent); border-radius: 2px; opacity: .85; }
.cl-bar-fill.warm { background: var(--doing); }

/* Progression across Revs */
.cl-rev { padding: 8px 0; border-bottom: 1px solid var(--rule); }
.cl-rev:last-of-type { border-bottom: 0; }
.cl-rev-item { font-size: 12.5px; font-weight: 600; color: var(--ink-2); margin-bottom: 6px; }
.cl-rev-line { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.cl-rev-pt {
  display: inline-flex; align-items: baseline; gap: 6px;
  background: var(--bg); border: 1px solid var(--rule);
  padding: 4px 10px; border-radius: var(--r);
}
.cl-rev-pt b { font-size: 11px; color: var(--ink-3); font-family: var(--mono); }
.cl-rev-n { font-family: var(--mono); font-size: 15px; font-weight: 700; }
.cl-rev-d { font-size: 10.5px; color: var(--ink-4); font-family: var(--mono); }
/* The "flow" connector between Revs — a drifting dash drawn with
   background-position. Coloured by the target state: amber while clashes remain,
   green once it reaches free. It reuses the existing colour variables, so it fits
   light and dark by itself. */
.cl-rev-flow {
  position: relative; width: 40px; height: 3px; flex: none; align-self: center;
  border-radius: var(--r); --fc: var(--doing);
  background: repeating-linear-gradient(90deg, var(--fc) 0 6px, transparent 6px 12px);
  animation: revflow .8s linear infinite;
  filter: drop-shadow(0 0 2px var(--fc));
}
.cl-rev-flow.done { --fc: var(--done); }
.cl-rev-flow::after {          /* a small arrow showing direction */
  content: ""; position: absolute; right: -3px; top: 50%; transform: translateY(-50%);
  border-left: 6px solid var(--fc);
  border-top: 4px solid transparent; border-bottom: 4px solid transparent;
}
@keyframes revflow { to { background-position: 12px 0; } }
/* The ONE animation in the app. Ticking a planned item makes a row appear
   somewhere in a table of 40 — this says where it landed, then gets out of the
   way. 900ms, one property, and off entirely under prefers-reduced-motion. */
@keyframes wl-landed {
  from { background: var(--accent-soft); box-shadow: inset 3px 0 0 var(--brand); }
  to   { background: transparent; box-shadow: inset 3px 0 0 transparent; }
}
.wl-table tbody tr.wl-landed td { animation: wl-landed .9s ease-out; }

@media (prefers-reduced-motion: reduce) { .cl-rev-flow { animation: none; } }
.cl-note {
  margin-top: 12px; padding: 10px 12px;
  background: var(--doing-bg); border-radius: var(--r);
  font-size: 12px; color: var(--doing); line-height: 1.5;
}

/* Report table */
.cl-tw { overflow-x: auto; }
.cl-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.cl-table th {
  text-align: left; font-family: var(--mono); font-size: 10px;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-3);
  font-weight: 600; padding: 6px 10px; border-bottom: 1px solid var(--rule); white-space: nowrap;
}
.cl-table td { padding: 6px 10px; border-bottom: 1px solid var(--rule); vertical-align: middle; }
/* Vertical rules, to match the Time Sheet table */
.cl-table th:not(:last-child),
.cl-table td:not(:last-child) { border-right: 1px solid var(--rule); }
.cl-table tr:last-child td { border-bottom: 0; }
.cl-table tbody tr:hover td { background: var(--hover); }
.cl-table .mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.cl-table .muted { color: var(--ink-3); }
.cl-file { max-width: 220px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cl-del {
  border: 0; background: transparent; cursor: pointer;
  color: var(--ink-4); padding: 3px 6px; border-radius: var(--r); font-size: 12px; opacity: .5;
}
.cl-table tr:hover .cl-del { opacity: 1; }
.cl-del:hover { background: var(--danger); color: #fff; }

/* Empty state + drop zone */
.cl-empty {
  border: 2px dashed var(--rule-2);
  border-radius: var(--r);
  padding: 50px 24px;
  text-align: center;
  color: var(--ink-3);
  transition: border-color .12s, background .12s;
}
.cl-empty.drag { border-color: var(--accent); background: var(--accent-soft); }
.cl-empty-title { font-size: 15px; font-weight: 600; color: var(--ink-2); margin: 4px 0 6px; }
.cl-empty p { font-size: 13px; margin: 0; }

/* Import preview modal */
.cl-modal {
  position: fixed; inset: 0; z-index: 100;
  background: rgba(10, 15, 20, .5);
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
}
.cl-modal-box {
  background: var(--card); border-radius: var(--r);
  width: 100%; max-width: 680px; max-height: calc(86vh / var(--ui-zoom));
  display: flex; flex-direction: column;
  box-shadow: 0 12px 48px rgba(0,0,0,.3);
  overflow: hidden;
}
.cl-modal-h {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 18px; border-bottom: 1px solid var(--rule);
  font-weight: 700; font-size: 14px;
}
.cl-modal-x {
  border: 0; background: transparent; cursor: pointer;
  color: var(--ink-3); font-size: 16px; padding: 2px 6px; border-radius: var(--r);
}
.cl-modal-x:hover { background: var(--hover); color: var(--ink); }
.cl-modal-body { padding: 10px 18px; overflow-y: auto; flex: 1; }
.cl-modal-foot {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 18px; border-top: 1px solid var(--rule); gap: 12px;
}
.cl-modal-foot > div { display: flex; gap: 8px; }

.cl-imp-row {
  display: grid; grid-template-columns: 28px 1fr; gap: 10px;
  padding: 12px 0; border-bottom: 1px solid var(--rule);
}
.cl-imp-row:last-child { border-bottom: 0; }
.cl-imp-row.bad { opacity: .7; }
/* A row that failed before parsing has no checkbox, so it has three children
   rather than the usual two — in a `28px 1fr` grid the folder name and the error
   land in the 28px column and wrap one character per line. It gets one column. */
.cl-imp-row.err { grid-template-columns: 1fr; gap: 0; }
.cl-imp-pick { display: flex; align-items: flex-start; padding-top: 2px; }
.cl-imp-ck { width: 16px; height: 16px; cursor: pointer; }
.cl-imp-main { min-width: 0; }
.cl-imp-name { font-size: 13px; font-weight: 600; word-break: break-word; }
.cl-imp-meta { font-size: 12px; color: var(--ink-3); margin: 3px 0; display: flex; gap: 5px; flex-wrap: wrap; }

/* The "Scan folder" button: it is the DELIVERY FOLDER's name that determines the
   package and rev (file names are often copied from an old report and never
   corrected) -> so it goes above the file name. */
.cl-imp-folder {
  font-family: var(--mono); font-size: 11px; color: var(--ink-3);
  word-break: break-all; margin-bottom: 2px;
}
/* Where the folder-name rules overrode what the parser read from the file name.
   It has to be shown: discovering after the import that a package changed leaves
   no way to work out why. */
.cl-imp-notes {
  margin-top: 5px; font-size: 11.5px; color: var(--ink-3);
  display: flex; flex-direction: column; gap: 2px;
}
.cl-imp-scan-sum {
  padding: 8px 18px; font-size: 12px; color: var(--ink-3);
  background: var(--hover); border-bottom: 1px solid var(--rule);
}
.cl-scan-wait { padding: 22px 4px; text-align: center; }
.cl-scan-l1 { font-size: 13px; font-weight: 600; }
.cl-scan-l2 {
  margin-top: 6px; font-family: var(--mono); font-size: 11px;
  color: var(--ink-3); word-break: break-all;
}

/* The check package as read from the file name — shows whoever is importing
   IMMEDIATELY what the system made of the file name, before anything is written to
   the statistics. A wrong file name can then be corrected and re-dropped, instead
   of the misfiled block surfacing after the import. */
/* The imported file's project — ALWAYS editable, because the parser is only GUESSING from the file name */
.cl-imp-proj { display: flex; align-items: center; gap: 7px; margin: 5px 0; }
.cl-imp-proj > span { font-size: 11px; color: var(--ink-4); }
.cl-imp-proj select { font-size: 12px; padding: 2px 6px; }
/* An unknown project -> a warning border until it is corrected. Not colour alone:
   the "⚠ ... not in the system" text above is what actually says what to do. */
.cl-imp-proj.need select { border-color: var(--doing); background: var(--doing-bg); }
.cl-imp-badproj { font-size: 11.5px; color: var(--doing); margin: 5px 0 2px; }

.cl-imp-pkg { display: flex; gap: 5px; flex-wrap: wrap; margin: 5px 0; }
.cl-tag {
  font-size: 10.5px;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 999px;
  background: rgba(120, 144, 180, .14);
  color: var(--ink-3);
  white-space: nowrap;
}
.cl-tag.blk { background: var(--brand-bg, rgba(232, 84, 30, .12)); color: var(--brand); }
.cl-tag.sys { background: var(--doing-bg); color: var(--doing); }

.cl-field-hint { display: block; font-size: 11px; color: var(--ink-4); margin-top: 4px; font-weight: 400; }
/* The hint box changes with the selected package — empty, it shouldn't take up space */
.cl-field-hint:empty { display: none; }

/* Long package names ('Block A GF L1_1BED, 2BED-Wall Frame') — truncated, hover for the rest */
.cl-pkg-cell { max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cl-imp-layout {
  font-family: var(--mono); font-size: 10px; background: var(--rule);
  padding: 0 5px; border-radius: var(--r); color: var(--ink-2);
}
.cl-imp-count { font-size: 12.5px; color: var(--ink-2); }
.cl-imp-count b { font-family: var(--mono); }
.cl-imp-probs { margin-top: 6px; font-size: 11.5px; color: var(--doing); display: flex; flex-direction: column; gap: 2px; }
.cl-imp-probs .hard { color: var(--danger); font-weight: 600; }
.cl-imp-probs .good { color: var(--done); font-weight: 600; }
.cl-imp-msg { font-size: 12px; color: var(--danger); }

/* The "✓ clean" badge — a version that was checked and has no clashes left */
.cl-free {
  display: inline-block;
  font-size: 10.5px; font-weight: 700;
  background: var(--done-bg); color: var(--done);
  padding: 2px 8px; border-radius: 999px; white-space: nowrap;
}
.cl-rev-pt.free { border-color: var(--done); background: var(--done-bg); }
.cl-rev-pt.free .cl-rev-n { color: var(--done); }

/* The mark-as-free form */
.cl-modal-sm { max-width: 420px; }
.cl-free-hint { font-size: 12.5px; color: var(--ink-3); margin: 4px 0 14px; line-height: 1.55; }
.cl-form { display: flex; flex-direction: column; gap: 12px; }
.cl-form label {
  display: flex; flex-direction: column; gap: 4px;
  font-size: 12px; color: var(--ink-3); font-weight: 600;
}
.cl-form input, .cl-form select {
  padding: 8px 10px; border-radius: var(--r);
  border: 1px solid var(--rule-2); background: var(--bg);
  font-size: 13.5px; font-weight: 400; color: var(--ink);
}
.cl-form input:focus, .cl-form select:focus { background: var(--card); }
.cl-form-row { display: grid; grid-template-columns: 90px 1fr; gap: 12px; }

/* ===== SPREADSHEET skin — flat, thin borders (Dat decided 21/07/2026) =====
   Replaces the old glass skin (blur + colour blobs + 20px radius). Why the change:
   this is a tool for reading numbers every day, not a landing page — the glass
   effect smeared colour behind the text, the large corner radius ate horizontal
   space, and the drop shadows made cards "float" when what was needed was to read
   the table quickly.
   Placed at the END of the file so it overrides the declarations above. Changing
   the skin means editing only this block. */

/* Background colour blobs: removed entirely. The selectors stay so the old HTML needs no edits. */
.blob { display: none; }

/* Cards -> flat blocks, thin border, no shadow */
.wl-add, .wl-table-wrap, .wl-hero, .pl-bar, .wl-pl-col,
.cl-card, .cl-kpi, .cl-empty,
.login-box, .empty-state {
  background: var(--card);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border: 1px solid var(--rule);
  border-radius: var(--r);
  box-shadow: none;
}
/* …except the entry card. It is STICKY — it floats over the week plan and the
   table while the page scrolls — and --card is 64% white with the blur switched
   off two lines up, so the rows underneath read straight through it: two sets of
   text on top of each other (Dat, 17/08/2026). This block is last in the file, so
   the override has to be here as well as at the .wl-add rule itself. */
.wl-add { background: var(--card-solid); }
/* Modals still need a shadow: they float ABOVE the page and must separate from what is behind */
.cl-modal-box {
  background: var(--card);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border: 1px solid var(--rule-2);
  border-radius: var(--r);
  box-shadow: 0 16px 48px rgba(16, 20, 30, .28);
}
.tlc-top {
  background: var(--card);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-bottom: 1px solid var(--rule-2);
}
/* Table headers: a light grey background to separate them from the data region,
   spreadsheet style.
   Do NOT use position:sticky — the table sits inside .wl-table-wrap / .cl-tw, which
   already have overflow, so sticky takes that container as its scroll frame and the
   header drifts away instead of sticking. The day header bands are enough of a
   landmark while scrolling. */
.wl-table thead th, .cl-table thead th { background: var(--head); }
.wl-day-sep td { background: var(--head) !important; }
tr[data-wl-dayhead]:hover td { background: var(--rule) !important; }
.wl-foot { background: var(--head); }

/* The "BIM TEAM" text beside the logo: no gradient, a solid colour for legibility */
.tlc-brand { font-weight: 800; }
.tlc-brand-name { color: var(--brand); }
.tlc-tab { border-radius: var(--r); }
.tlc-tab.active {
  background: transparent;
  color: var(--ink);
  box-shadow: inset 0 -2px 0 var(--brand);
  border-radius: 0;
}
.btn { border-radius: var(--r); }
.btn-primary {
  background: var(--accent);
  border: 1px solid var(--accent);
  box-shadow: none;
}

/* KPIs: compact figure tiles that don't scale up on hover (spreadsheets don't bounce) */
.cl-kpi { padding: 11px 16px; min-width: 88px; }
.cl-kpi-n { font-size: 23px; font-weight: 700; color: var(--ink); font-family: var(--font); letter-spacing: -.02em; }
.cl-kpi-sub { font-size: 13px; font-weight: 600; color: var(--ink-3); }
.cl-kpi.all-free .cl-kpi-n { color: var(--done); }
.cl-kpis { gap: 8px; margin-bottom: 12px; }

/* ===== "Tell at a glance" KPIs — traffic-light colours ===== */
/* The "Packages freed" hero: a large number + % + a green progress bar */
.cl-kpi-hero { min-width: 150px; }
.cl-kpi-pct { font-size: 15px; font-weight: 700; color: var(--done); margin-left: 6px; }
.cl-bar {
  display: block; height: 6px; border-radius: 999px;
  background: rgba(120, 144, 180, .22); overflow: hidden; margin-top: 8px;
}
.cl-bar-fill {
  display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, var(--done), #34C084);
  transition: width .45s ease;
}
/* The "Outstanding" tile: amber-orange while there is debt, green when clean. Both
   the background and the border are tinted, so it stands out from the neutral
   figure tiles beside it. */
.cl-kpi-open { background: var(--doing-bg); border-color: var(--doing); }
.cl-kpi-open .cl-kpi-n, .cl-kpi-open .cl-kpi-l { color: var(--doing); }
.cl-kpi-clean { background: var(--done-bg); border-color: var(--done); }
.cl-kpi-clean .cl-kpi-n, .cl-kpi-clean .cl-kpi-l { color: var(--done); }
/* The cumulative figure (clashes handled) — correct, but NOT the work remaining,
   so it is dimmed to stop the eye reading it as a backlog. */
.cl-kpi-muted { opacity: .68; }
.cl-kpi-muted .cl-kpi-n { color: var(--ink-3); font-size: 19px; }

/* ===== Per-project progress bands ===== */
.cl-rollup-list { display: flex; flex-direction: column; gap: 2px; }
.cl-rollup-row {
  display: grid;
  grid-template-columns: 72px minmax(120px, 1fr) 90px 96px;
  align-items: center; gap: 12px;
  padding: 8px; border: 0; background: none; width: 100%;
  text-align: left; font: inherit; color: inherit; border-radius: var(--r); cursor: pointer;
}
.cl-rollup-row:hover { background: var(--hover); }
.cl-rollup-name {
  font-family: var(--mono); font-weight: 700; font-size: 12.5px; color: var(--brand);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cl-bar-lg { height: 9px; margin-top: 0; }
.cl-rollup-ratio { font-family: var(--mono); font-size: 11.5px; color: var(--ink-3); font-weight: 600; }
.cl-rollup-open {
  font-family: var(--mono); font-size: 12px; font-weight: 700;
  text-align: right; color: var(--doing);
}
.cl-rollup-open.done { color: var(--done); }

/* The "How far checked" bands — the same shape as the per-project ones, differing
   in three ways: a wider name column (a project code is 3-4 characters, a major
   package is 'Core Frame'), an extra column counting the projects involved, and
   NOT clickable (a group is not a filter the way a project is), so both the hand
   cursor and the hover background are dropped — something that looks clickable and
   does nothing is worse than something that looks unclickable. */
.cl-major-roll {
  grid-template-columns: 108px minmax(100px, 1fr) 90px 82px 62px;
  cursor: default;
}
.cl-major-roll:hover { background: none; }
.cl-major-roll .cl-rollup-name { color: var(--ink); text-transform: uppercase; letter-spacing: .02em; }
.cl-major-roll-proj { font-family: var(--mono); font-size: 11px; color: var(--ink-4); text-align: right; }
/* The "Other" group has to speak up in this band too, in the same language as the band inside a project card. */
.cl-major-roll.is-khac { border-left: 3px dashed var(--doing); padding-left: 5px; }
.cl-major-roll.is-khac .cl-rollup-name { color: var(--doing); }

@media (max-width: 720px) {
  /* Drop the ratio text column on narrow screens, keep the name + bar + remaining count */
  .cl-rollup-row { grid-template-columns: 56px 1fr 76px; gap: 8px; }
  .cl-rollup-ratio { display: none; }
  /* Major package names are NOT clipped to 56px: 'Wall Frame' and 'Wall Frame
     Update' truncate to exactly the same thing. Better to drop the project-count
     column. */
  .cl-major-roll { grid-template-columns: 96px 1fr 76px; }
  .cl-major-roll-proj { display: none; }
}

/* ===== Trend within the period (the Activity block) ===== */
.cl-trend {
  font-family: var(--mono); font-size: 11px; font-weight: 700;
  display: inline-flex; gap: 8px; align-items: center;
  padding: 2px 10px; border-radius: 999px;
  background: rgba(120, 144, 180, .12);
}
.cl-trend-good { color: var(--done); }
.cl-trend-bad { color: var(--doing); }
.cl-trend-flat { color: var(--ink-4); font-weight: 600; }

/* ===== "Stale" — packages that are not free and have not moved ===== */
.cl-age-in { color: var(--danger); font-weight: 700; }

/* ===== Filtered screen: packages (left) + charts (right) ===== */
.cl-split {
  display: grid;
  grid-template-columns: minmax(320px, 440px) 1fr;
  gap: 10px; align-items: start; margin-bottom: 10px;
}
.cl-split-r { display: flex; flex-direction: column; gap: 10px; }
.cl-split-r > .cl-card { margin: 0; }
@media (max-width: 860px) { .cl-split { grid-template-columns: 1fr; } }

/* Clamping the package list — about 5 packages then a fade, click to expand. The
   button sits OUTSIDE the clipped region so overflow doesn't swallow it. */
.cl-pkg-body.cl-clamp {
  max-height: 300px; overflow: hidden;
  -webkit-mask-image: linear-gradient(#000 72%, transparent);
  mask-image: linear-gradient(#000 72%, transparent);
}
.cl-pkg-body.cl-clamp.is-open {
  max-height: none;
  -webkit-mask-image: none; mask-image: none;
}
.cl-pkg-more { margin-top: 6px; }

/* ===== Package overview donut ===== */
.cl-donut-wrap { display: flex; align-items: center; gap: 20px; padding: 6px 4px 2px; }
.cl-donut {
  width: 128px; height: 128px; border-radius: 50%; flex: none;
  background: conic-gradient(var(--done) calc(var(--pct) * 1%), var(--doing) 0);
  display: grid; place-items: center;
}
.cl-donut-hole {
  width: 82px; height: 82px; border-radius: 50%; background: var(--card-solid);
  display: grid; place-items: center; align-content: center; text-align: center;
}
.cl-donut-hole b { font-size: 22px; font-weight: 800; color: var(--done); line-height: 1; font-family: var(--mono); }
.cl-donut-hole span { font-size: 10px; color: var(--ink-4); text-transform: uppercase; letter-spacing: .06em; margin-top: 2px; }
.cl-donut-leg { display: flex; flex-direction: column; gap: 8px; font-size: 12.5px; color: var(--ink-2); }
.cl-donut-leg > div { display: flex; align-items: center; gap: 7px; }
.cl-donut-leg b { font-family: var(--mono); font-weight: 700; }
.cl-donut-sub { color: var(--doing); font-family: var(--mono); font-size: 11.5px; margin-top: 2px; }
.cl-dot { width: 10px; height: 10px; border-radius: var(--r); display: inline-block; flex: none; }

/* ============================================================
   LIQUID GLASS — a frosted surface laid over the main panels.
   The page background (--bg-grad) carries colour blobs for backdrop-filter to blur
   into something glass-like.
   Only border-color is set (never the shorthand) so the border widths and the
   accent borders survive (e.g. the border-left of the "Awaiting a later stage"
   card).
   ============================================================ */
.tlc-top, .cl-card, .cl-kpi, .cl-ppill, .btn, .login-box {
  backdrop-filter: blur(16px) saturate(185%);
  -webkit-backdrop-filter: blur(16px) saturate(185%);
}
/* The top-lit sheen layer sits ON TOP of the glass background -> it reads as glass
   rather than flat. Only background-image is set, so background-color survives
   (keeping the status KPI tile colours). Transparent from ~46% down so the lower
   half stays clear and the blurred background shows through. */
.cl-card, .cl-kpi, .login-box, .cl-ppill {
  background-image: linear-gradient(180deg, var(--glass-sheen), transparent 46%);
}
/* A bright edge + layered raised shadows = depth. No border is applied to .cl-kpi,
   so the coloured borders of the "Outstanding"/"clean" tiles survive. */
.cl-card, .login-box {
  border-color: var(--glass-brd);
  border-radius: var(--r);
}
.cl-card, .cl-kpi, .login-box {
  box-shadow:
    0 16px 44px -16px var(--glass-shadow),
    0 3px 10px -6px var(--glass-shadow),
    inset 0 1px 0 var(--glass-hi);
}
.cl-kpi { border-radius: var(--r); }
.tlc-top {
  border-bottom-color: var(--glass-brd);
  box-shadow: 0 10px 30px -20px var(--glass-shadow), inset 0 1px 0 var(--glass-hi);
}
.cl-ppill { border-color: var(--glass-brd); }
/* Modals: blur the PAGE behind, but keep the modal box SOLID so its table stays readable */
.cl-modal { backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); }
.cl-modal-box {
  background: var(--card-solid);
  border: 1px solid var(--glass-brd);
  border-radius: var(--r);
  box-shadow: 0 28px 70px -20px var(--glass-shadow), inset 0 1px 0 var(--glass-hi);
}
/* Less blur / more solid fills on weaker machines, to avoid jank (respecting the OS setting) */
@media (prefers-reduced-transparency: reduce) {
  .tlc-top, .cl-card, .cl-kpi, .cl-ppill, .btn, .cl-modal {
    backdrop-filter: none; -webkit-backdrop-filter: none;
  }
}

/* ===== Project filter pills (replacing a dropdown) ===== */
.cl-toolbar { flex-wrap: wrap; }
.cl-proj-pills { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; flex: 1; min-width: 0; }
.cl-ppill {
  font-size: 12.5px;
  font-weight: 600;
  padding: 4px 12px;
  border-radius: var(--r);
  border: 1px solid var(--rule-2);
  background: var(--card);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  color: var(--ink-2);
  cursor: pointer;
  transition: background .12s, border-color .12s;
}
.cl-ppill:hover { border-color: var(--ink-4); background: var(--hover); }
.cl-ppill.active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-fg);
  box-shadow: none;
}
.cl-toolbar-btns { display: flex; gap: 8px; margin-left: auto; }

/* ===== The "All" dashboard — activity / not free / freed ===== */
/* The period selector for the Activity block. It lives inside .cl-card-h, so it has
   to separate itself from .cl-card-sub with margin-right:auto, or the heading
   bunches up in one spot. */
.cl-period { display: flex; gap: 2px; margin-right: auto; }
.cl-pbtn {
  border: 0;
  background: transparent;
  color: var(--ink-4);
  font-size: 11.5px;
  font-weight: 600;
  padding: 3px 9px;
  border-radius: 999px;
  cursor: pointer;
  white-space: nowrap;
}
.cl-pbtn:hover { background: var(--hover); color: var(--ink-2); }
.cl-pbtn.active { background: var(--accent-soft); color: var(--accent); }
@media (max-width: 720px) {
  .cl-period { margin-right: 0; overflow-x: auto; scrollbar-width: none; }
  .cl-period::-webkit-scrollbar { display: none; }
  .cl-pbtn { flex: none; }
}

.cl-db-list { display: flex; flex-direction: column; }
.cl-db-row {
  display: grid;
  grid-template-columns: 54px minmax(0, 1fr) auto auto auto;
  align-items: center;
  gap: 10px;
  padding: 7px 8px;
  border-radius: var(--r);
  border: 0;
  background: none;
  width: 100%;
  text-align: left;
  font: inherit;
  color: inherit;
}
.cl-db-btn { cursor: pointer; }
.cl-db-btn:hover { background: rgba(120, 144, 180, .1); }
.cl-db-btn:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.cl-db-proj {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 700;
  color: var(--brand);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Long Package names — truncated with an ellipsis HERE (unlike the detail card,
   which wraps): the dashboard is a list to be skimmed, and every row has to be
   exactly one line high for the eye to scan the status column on the right. Hover
   gives the full name as a tooltip. */
.cl-db-name {
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cl-db-step {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 600;
  color: var(--ink-3);
  white-space: nowrap;
}
.cl-db-date { font-family: var(--mono); font-size: 10.5px; color: var(--ink-4); white-space: nowrap; }
.cl-db-n {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 700;
  color: var(--doing);
  min-width: 46px;
  text-align: right;
}
.cl-db-empty { display: block; padding: 6px 2px 0; font-size: 12.5px; color: var(--ink-4); }

/* The part of "Freed" beyond the clamp threshold — hidden until "Show more" is
   pressed. It has its own class rather than [hidden], because .cl-db-list has the
   same specificity and would override [hidden] into uselessness. */
.cl-db-extra { display: none; flex-direction: column; }
.cl-db-extra.is-open { display: flex; }
.cl-more-btn {
  margin-top: 4px;
  width: 100%;
  border: 0;
  background: none;
  color: var(--accent);
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  padding: 6px;
  border-radius: var(--r);
  cursor: pointer;
}
.cl-more-btn:hover { background: var(--hover); }

/* Phones have NO hover -> a title="" is unreachable. Truncating the name with an
   ellipsis here would hide the information outright, with no way to get it back. So
   on narrow screens it wraps and restacks into 2 rows — better taller than missing
   text. */
@media (max-width: 720px) {
  .cl-db-row {
    grid-template-columns: 46px minmax(0, 1fr) auto;
    row-gap: 2px;
    padding: 9px 6px;
  }
  .cl-db-name { white-space: normal; overflow: visible; overflow-wrap: anywhere; line-height: 1.35; }
  .cl-db-proj { align-self: start; }
  /* The Rev step + date drop to the next line, indented to align with the name */
  .cl-db-step, .cl-db-date { grid-column: 2; }
  .cl-pkg-st, .cl-db-n { grid-column: 3; grid-row: 1; align-self: start; }
}

/* ===== Check packages by project -> block -> frame type ===== */
/* 250px -> 320px: each row now carries the frame type + the scope (GF, L1 · 1BED,
   2BED) + Rev + status, and the old narrow column truncated the scope entirely. */
.cl-pkg-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 14px;
}
.cl-pkg-proj {
  background: rgba(120, 144, 180, .07);
  border: 1px solid var(--rule);
  border-radius: var(--r);
  padding: 12px 14px;
}
.cl-pkg-proj-h {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 8px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--rule);
}
.cl-pkg-proj-name { font-size: 14px; font-weight: 800; color: var(--brand); }
/* "＋ check package" — names a new major package for the project. It sits right
   after the project name (margin-right:auto pushes the ratio back to the right edge
   as before) because this is a project-level action, not a per-package one. One
   step fainter than the project name: it is a secondary button and must not compete
   with the name. */
.cl-pkg-add-major {
  margin-right: auto;
  border: 1px dashed var(--rule, var(--line));
  background: transparent;
  color: var(--ink-3, var(--muted));
  font-size: 11px;
  font-weight: 600;
  padding: 1px 8px;
  border-radius: 999px;
  cursor: pointer;
}
.cl-pkg-add-major:hover { color: var(--accent); border-color: var(--accent); border-style: solid; }
.cl-pkg-ratio {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  color: var(--doing);
  background: var(--doing-bg);
  padding: 2px 9px;
  border-radius: 999px;
}
.cl-pkg-ratio.done { color: var(--done); background: var(--done-bg); }
/* Block groups within one project */
.cl-pkg-blk { margin-bottom: 10px; }
.cl-pkg-blk:last-child { margin-bottom: 0; }
/* The MAJOR-PACKAGE group header — a background band + a coloured rule on the left.
   It used to be 12px grey text with a thin line, lost among the package list right
   below it: a glance at the card did not show which part of the project was stuck,
   which is exactly the question the card exists to answer. Now each major package
   is its own band, so the eye catches the group level first and the package name
   second.
   The left rule and the ratio change colour with the state, but colour NEVER stands
   alone: the x/y figure and "N clashes left" always accompany it — readable by
   someone who is colour-blind. */
.cl-pkg-blk-h {
  display: flex;
  align-items: center;
  flex-wrap: wrap;                 /* the "Other" group's prompt wraps to the next line */
  gap: 7px;
  margin-bottom: 4px;
  padding: 5px 9px;
  border-radius: var(--r);
  border-left: 3px solid var(--doing);
  background: rgba(120, 144, 180, .16);
}
.cl-pkg-blk-h:hover { background: rgba(120, 144, 180, .24); }
.cl-pkg-blk-h.done { border-left-color: var(--done); }
/* The fold button fills the remaining space -> clicking anywhere on the band
   collapses it, except on the ✎ button itself. It is a separate <button> rather
   than making the whole band one: with ✎ inside it that would be a button nested in
   a button, and Firefox swallows the ✎ click entirely. */
.cl-pkg-fold {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
  border: 0;
  background: transparent;
  padding: 0;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}
/* The "Other" group — where the rules gave up and a person is needed. A DASHED rule
   (not a different colour): dashed and solid remain distinguishable to someone who
   is colour-blind. The warning stays even when the group is entirely free — free
   but unclassified still leaves a hole in the "how far has this project been
   checked" question. */
.cl-pkg-blk-h.is-khac {
  border-left-style: dashed;
  border-left-color: var(--doing);
  background: var(--doing-bg);
}
.cl-pkg-khac-hint { flex-basis: 100%; font-size: 10.5px; color: var(--doing); }
/* Inside the Other group the selector is shown CLEARLY without waiting for hover:
   this is exactly where the user has to act, and hiding it would make the prompt
   above it empty words. */
.cl-pkg-blk-h.is-khac ~ .cl-pkg-row .cl-major-sel {
  opacity: 1;
  border-color: var(--rule, var(--line));
  background: var(--card-solid, var(--card));
}
/* The rename / delete button for a custom major package. */
.cl-pkg-rename {
  border: 0;
  background: transparent;
  color: var(--ink-4);
  font-size: 12px;
  line-height: 1;
  padding: 2px 4px;
  border-radius: var(--r);
  cursor: pointer;
}
.cl-pkg-rename:hover { color: var(--accent); background: var(--hover, rgba(0,0,0,.05)); }
/* The expand/collapse arrow. Small and faint: it is only a sign that something is
   clickable, not something to read — the group name is what the eye should catch
   first. */
.cl-pkg-fold-i { font-size: 11px; color: var(--ink-3, var(--muted)); flex: none; width: 9px; line-height: 1; }
.cl-pkg-blk-name {
  font-size: 12.5px;
  font-weight: 800;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--ink);
}
/* The member ratio "freed / total" — a coloured pill matching the whole project's
   ratio at the top of the card, so both levels read the same way. */
.cl-pkg-blk-ratio {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 700;
  color: var(--doing);
  background: var(--doing-bg);
  padding: 1px 7px;
  border-radius: 999px;
}
.cl-pkg-blk-h.done .cl-pkg-blk-ratio { color: var(--done); background: var(--done-bg); }
/* The group's remaining debt, pushed to the right edge to line up with the status column below. */
.cl-pkg-blk-open {
  margin-left: auto;
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 600;
  color: var(--doing);
}
/* Package names can wrap, so they align to the TOP of the line rather than centre —
   centred, the Rev/status would drift to the middle of a two-line block of text. */
.cl-pkg-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto auto;
  align-items: start;
  gap: 4px 8px;
  padding: 6px 0;
  padding-left: 10px;
}
.cl-pkg-row .cl-pkg-nrev, .cl-pkg-row .cl-pkg-meta, .cl-pkg-row .cl-pkg-st { margin-top: 1px; }

/* How many versions the package has been through (Rev00 -> ... -> Free). Hover for
   the whole journey. Neutral grey, NOT a status colour: this is "how many rounds of
   fixing", not "finished or not" — colouring it would steal attention from the
   FREE/clash tile beside it. */
.cl-pkg-nrev {
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 600;
  color: var(--ink-4);
  background: rgba(120, 144, 180, .14);
  padding: 1px 7px;
  border-radius: 999px;
  white-space: nowrap;
  cursor: help;
}
/* The full Package name: 'Block A GF L1_1BED, 2BED-Wall Frame'.
   It WRAPS rather than being cut with an ellipsis — truncated, '…2BED-Wall Frame'
   and '…2BED-Core Frame' look identical, losing exactly the distinction that
   matters. */
.cl-pkg-name {
  font-size: 13px;
  font-weight: 600;
  line-height: 1.35;
  overflow-wrap: anywhere;
}
.cl-pkg-meta { font-family: var(--mono); font-size: 10.5px; color: var(--ink-4); white-space: nowrap; }
.cl-pkg-st {
  font-size: 10.5px;
  font-weight: 700;
  padding: 2px 9px;
  border-radius: 999px;
  white-space: nowrap;
}
.cl-pkg-st.free { background: var(--done-bg); color: var(--done); }
/* Uses the doing palette rather than the brand orange: #E8541E on a pale orange
   background only reaches 3.22 contrast — below the 4.5 required for small text.
   Doing reaches 4.58. */
.cl-pkg-st.busy { background: var(--doing-bg); color: var(--doing); }

/* ===== Deferred to a later stage (Dat decided 21/07/2026) =====
   Free WITH debt carried forward: still green (this stage is finished and it counts
   as free in the KPI) but with a dashed border — visibly different from "completely
   clean", without going amber and being confused with a package that still has
   clashes to handle now.
   A border rather than merely a different shade: still distinguishable to someone
   who is colour-blind. */
.cl-pkg-st.free.has-defer {
  border: 1px dashed var(--done);
  padding: 1px 8px;
}
/* The secondary "N deferred" label beside a package that STILL has clashes — kept
   away from the status colours, because this is supplementary information rather
   than the package's state. */
.cl-pkg-st.defer {
  background: rgba(120, 144, 180, .16);
  color: var(--ink-3);
  margin-left: 4px;
  font-weight: 600;
}
/* The ⏭ label in the report table and the import screen */
.cl-defer-tag {
  display: inline-block;
  font-family: var(--mono);
  font-size: 10.5px;
  font-weight: 700;
  background: rgba(120, 144, 180, .16);
  color: var(--ink-3);
  padding: 1px 7px;
  border-radius: 999px;
  margin-left: 6px;
  white-space: nowrap;
}
/* The supplementary note inside the "Packages freed" KPI tile */
.cl-kpi-note {
  font-size: 10.5px;
  font-family: var(--mono);
  color: var(--doing);
  margin-top: 3px;
}
.cl-kpi-defer .cl-kpi-n { color: var(--ink-2); }

/* The "Awaiting a later stage" card — the next phase's work queue */
.cl-defer-card { border-left: 3px solid var(--ink-4); }
.cl-defer-hint {
  font-size: 11.5px;
  font-weight: 400;
  color: var(--ink-3);
  margin-left: auto;
  text-align: right;
  max-width: 46ch;
  line-height: 1.4;
}
.cl-defer-note {
  max-width: 260px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--ink-2);
}
.cl-imp-probs .defer { color: var(--ink-2); font-weight: 600; }
/* A hand-declared deferral row: a number only, with no per-spot detail */
.cl-defer-manual td:nth-child(3) { color: var(--ink-4); font-style: italic; }

@media (max-width: 720px) {
  .cl-defer-hint { margin-left: 0; text-align: left; max-width: none; }
}

/* ===== Narrow screens =====
   The table used to be forced to min-width 620px and scrolled sideways — on a phone
   that was both unreadable and untappable (30px rows, a 12px ✕ button). Now: the
   table becomes CARDS by day, and the entry block STICKS TO THE BOTTOM of the
   screen (within thumb reach). */

@media (max-width: 720px) {
  .tlc-body { padding: 14px 12px 60px; }
  .tlc-top { padding: 10px 12px; }
  .wl-add-row { flex-wrap: wrap; }
  .wl-input { flex-basis: 100%; }
  .wl-foot-hint { display: none; }

  /* --- The entry block moves to the BOTTOM and sticks to the viewport --- */
  body[data-tab="worklog"] #view { display: flex; flex-direction: column; }
  body[data-tab="worklog"] .wl-add {
    order: 99;                       /* the other blocks keep DOM order (order 0) */
    position: sticky;
    bottom: max(10px, env(safe-area-inset-bottom));
    z-index: 30;
    margin: 12px 0 0;
  }
  /* The chip rows inside the entry block: ONE horizontally scrolling line — so the
     bar stuck to the bottom doesn't grow to half the screen. */
  .wl-add-projects, .wl-days, .wl-sugs {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .wl-add-projects::-webkit-scrollbar, .wl-days::-webkit-scrollbar, .wl-sugs::-webkit-scrollbar { display: none; }
  .wl-add-projects > *, .wl-days > *, .wl-sugs > * { flex: none; }
  .wl-today { margin-left: 6px; }
  .wl-copy { margin-left: 6px; width: auto; }
  /* The input sits at the bottom -> the suggestion box opens UPWARDS, since opening down would fall off the screen */
  .wl-ac { top: auto; bottom: calc(100% + 6px); }

  /* --- The table becomes cards --- */
  .wl-table-wrap {
    background: transparent;
    border: 0;
    box-shadow: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    overflow: visible;
    border-radius: 0;
  }
  .wl-table, .wl-table tbody { display: block; width: 100%; }
  .wl-table thead { display: none; }
  .wl-table tbody tr {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    column-gap: 10px;
    row-gap: 3px;
    padding: 9px 11px;
    margin-bottom: 6px;
    background: var(--card);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    border: 1px solid var(--rule);
    border-radius: var(--r);
    box-shadow: none;
  }
  /* Cards in the person's colour: the td background is removed (rule below), so the
     tint moves onto the <tr> card itself, laying the light wash OVER the card
     background to match desktop. */
  .wl-table tbody tr.wl-tint {
    background-color: var(--card);
    background-image: linear-gradient(var(--oc-bg), var(--oc-bg));
  }
  /* Mobile cards have no columns -> drop the desktop table's vertical rules too */
  .wl-table td { display: block; border: 0 !important; height: auto; padding: 0; background: none !important; }
  /* Row 1: description (wide) + hours (right). Row 2: project · status · person · buttons. */
  td.c-task { flex: 1 1 calc(100% - 78px); order: 1; min-width: 0; }
  td.c-task .wl-v { white-space: normal; font-size: 13.5px; font-weight: 600; line-height: 1.4; padding: 2px 0; margin: 0; }
  td.c-task[style] { padding-left: 8px; }   /* leave room for the person's colour stripe */
  td.c-h { order: 2; margin-left: auto; flex: none; }
  td.c-h .wl-v { font-size: 15px; }
  .wl-h-cell::before { display: none; }     /* the proportion bar is drawn against a table cell; drop it on cards */
  td.c-proj { order: 3; flex: none; }
  td.c-proj .wl-v { font-size: 11.5px; padding: 2px 0; margin: 0; }
  td.c-st { order: 4; flex: none; }
  td.c-who { order: 5; flex: none; }
  td.c-who .wl-v { font-size: 11.5px; padding: 2px 0; margin: 0; }
  td.c-acts { order: 6; margin-left: auto; flex: none; }

  /* The day header row: drop the card frame, make it a group label */
  .wl-table tbody tr.wl-day-sep {
    background: none;
    border: 0;
    box-shadow: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    padding: 8px 4px 2px;
    margin-bottom: 2px;
  }
  .wl-day-sep td { display: flex; align-items: center; width: 100%; background: none !important; }
  .wl-foot { border-top: 0; }

  /* A finger is bigger than a mouse pointer */
  .wl-act { opacity: .7; font-size: 14px; padding: 8px 10px; }
  /* An 11px dot is a 44px target on a phone: grow the hit area, not the dot */
  .wl-st-dot { width: 14px; height: 14px; margin: 0; }
  .wl-pl-tick { width: 26px; height: 26px; }
  /* Adjust hours with − / + instead of the browser's tiny spinner */
  .wl-hstep-btn { display: grid; }
  td.c-h .wl-hstep .wl-e { width: 52px; flex: none; }
}

/* The ONE animation in the app. Ticking a planned item makes a row appear
   somewhere in a table of 40 — this says where it landed, then gets out of the
   way. 900ms, one property, and off entirely under prefers-reduced-motion. */
@keyframes wl-landed {
  from { background: var(--accent-soft); box-shadow: inset 3px 0 0 var(--brand); }
  to   { background: transparent; box-shadow: inset 3px 0 0 transparent; }
}
.wl-table tbody tr.wl-landed td { animation: wl-landed .9s ease-out; }

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* ============================================================
   Model Score — Model Health per discipline, and the trend
   ============================================================
   Same furniture as the clash screen (.cl-toolbar / .cl-kpis / .cl-card), so
   only what is new to this screen lives here: the grade colours, the trend
   chart, and the per-model table.

   Grade bands are the dashboard's own — ≥90 Excellent · ≥75 Good · ≥60 Fair ·
   ≥40 Poor · below Critical. Colour NEVER carries the meaning alone: every
   score has its number beside it and every card names its grade in words. */

:root {
  --ms-good: var(--done);
  --ms-fair: var(--doing);
  --ms-poor: #C2410C;
  --ms-crit: var(--danger);
}

.ms-good { color: var(--ms-good); }
.ms-fair { color: var(--ms-fair); }
.ms-poor { color: var(--ms-poor); }
.ms-crit { color: var(--ms-crit); }

.cl-kpi.ms-k-good .cl-kpi-n { color: var(--ms-good); }
.cl-kpi.ms-k-good .cl-bar-fill { background: var(--ms-good); }
.cl-kpi.ms-k-fair .cl-kpi-n { color: var(--ms-fair); }
.cl-kpi.ms-k-fair .cl-bar-fill { background: var(--ms-fair); }
.cl-kpi.ms-k-poor .cl-kpi-n { color: var(--ms-poor); }
.cl-kpi.ms-k-poor .cl-bar-fill { background: var(--ms-poor); }
.cl-kpi.ms-k-crit .cl-kpi-n { color: var(--ms-crit); }
.cl-kpi.ms-k-crit .cl-bar-fill { background: var(--ms-crit); }

/* The move since the audit before. An arrow AND a number: an arrow alone says
   nothing about whether it moved by one point or twenty. */
.ms-d { font-family: var(--mono); font-size: 12px; font-weight: 700; white-space: nowrap; }
.ms-d-up { color: var(--ms-up); }
.ms-d-dn { color: var(--ms-dn); }
.ms-d-flat { color: var(--ink-4); }
.ms-d-na { color: var(--ink-4); cursor: help; }

/* Three discipline cards */
.ms-discs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 10px;
  margin-bottom: 12px;
}
.ms-disc-h {
  display: flex; align-items: center; gap: 7px;
  font-size: 12px; font-weight: 700; color: var(--ink-2);
  letter-spacing: .06em;
}
.ms-disc-h i { width: 9px; height: 9px; border-radius: 2px; flex: none; }
.ms-disc-n {
  margin-left: auto; font-family: var(--mono); font-size: 11px; font-weight: 600;
  color: var(--ink-3); letter-spacing: 0;
}
.ms-disc-score {
  display: flex; align-items: baseline; gap: 8px;
  font-family: var(--mono); font-size: 30px; font-weight: 700;
  line-height: 1; letter-spacing: -.02em; margin: 10px 0 8px;
}
.ms-disc-score small { font-size: 13px; font-weight: 600; color: var(--ink-3); }
.ms-disc.ms-good .ms-disc-score { color: var(--ms-good); }
.ms-disc.ms-fair .ms-disc-score { color: var(--ms-fair); }
.ms-disc.ms-poor .ms-disc-score { color: var(--ms-poor); }
.ms-disc.ms-crit .ms-disc-score { color: var(--ms-crit); }
.ms-disc.ms-good .cl-bar-fill { background: var(--ms-good); }
.ms-disc.ms-fair .cl-bar-fill { background: var(--ms-fair); }
.ms-disc.ms-poor .cl-bar-fill { background: var(--ms-poor); }
.ms-disc.ms-crit .cl-bar-fill { background: var(--ms-crit); }
/* The grade word, beside the number it grades rather than buried in a sentence
   under the bar. It carries its own colour, so the grade survives a printout and
   a colour-blind reader alike — the word IS the cue, the colour only repeats it. */
.ms-grade {
  font-family: var(--font); font-size: var(--fs-label); font-weight: 700;
  letter-spacing: var(--ls-label); text-transform: uppercase;
  padding: 2px 7px; border-radius: 999px; align-self: center;
}
.ms-g-good { background: var(--done-bg);    color: var(--done); }
.ms-g-fair { background: var(--doing-bg);   color: var(--doing); }
.ms-g-poor { background: var(--pending-bg); color: var(--danger); }
/* Critical is the only solid one. --card-solid, not #fff: in dark mode --danger
   is the LIGHT red #F0796B, and white on it measures ~2.2:1. */
.ms-g-crit { background: var(--danger);     color: var(--card-solid); }

.ms-disc-f { font-size: var(--fs-meta); color: var(--ink-3); margin-top: 8px; }
/* Warnings are the one thing on this card somebody can act on — 91 of them on
   STR is not a footnote. Amber ON its own tint, not on the card: the frosted
   card sits over a colour-mesh background, and #B45309 measured 3.62:1 against
   whatever happened to be behind it. On --doing-bg the surface is known. */
.ms-disc-f.ms-warn {
  display: inline-block; color: var(--doing); background: var(--doing-bg);
  padding: 3px 8px; border-radius: var(--r);
}
.ms-disc-f.ms-warn b { font-family: var(--mono); font-size: var(--fs-body); font-weight: 700; }

/* The quiet line that replaced six KPI tiles */
.ms-meta {
  display: flex; flex-wrap: wrap; gap: 4px 16px; margin-top: 8px;
  font-size: var(--fs-meta); color: var(--ink-3);
}
.ms-meta b { font-family: var(--mono); font-size: var(--fs-body); font-weight: 700; color: var(--ink-2); }
.ms-meta small { font-size: var(--fs-label); color: var(--ink-4); }
.ms-disc-empty { opacity: .6; }
.ms-disc-na { font-size: 12.5px; color: var(--ink-4); margin-top: 12px; }


/* Both of these are .cl-card as well, so they keep the glass surface and the
   14px radius the rest of the screen uses — only the accent edge is new. */
.ms-note {
  font-size: 12.5px; color: var(--ink-2);
  border-left: 3px solid var(--ms-crit);
  padding: 10px 14px; margin-bottom: 12px;
}

/* Everything the scan could not deal with. Deliberately loud and on the page:
   a project code that is not in the system means a model is MISSING from the
   trend, and that must not hide inside a toast that vanishes. */
.ms-problems { border-left: 3px solid var(--ms-fair); }
.ms-problems ul { margin: 0; padding-left: 18px; }
.ms-problems li { font-size: 12.5px; color: var(--ink-2); margin-bottom: 4px; line-height: 1.45; }

/* The per-model table */
.ms-tbl-wrap { overflow-x: auto; }
.ms-tbl { width: 100%; border-collapse: collapse; font-size: 13px; }
.ms-tbl th {
  text-align: left; font-family: var(--mono); font-size: 10px; font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3);
  padding: 0 10px 7px; border-bottom: 1px solid var(--rule); white-space: nowrap;
}
.ms-tbl th.r, .ms-tbl td.r { text-align: right; }
.ms-tbl td { padding: 7px 10px; border-bottom: 1px solid var(--rule); vertical-align: middle; }
.ms-tbl tbody tr:last-child td { border-bottom: 0; }
.ms-tbl tbody tr:hover { background: var(--hover); }
.ms-model { font-size: 12.5px; color: var(--ink); font-weight: 600; }
.ms-model small {
  display: block; font-family: var(--mono); font-size: 10.5px;
  font-weight: 600; color: var(--ink-3);
}
.ms-chip {
  display: inline-block; padding: 1px 7px; border-radius: 999px;
  font-family: var(--mono); font-size: 10px; font-weight: 700;
  color: #fff; letter-spacing: .04em;
}
.ms-score { font-family: var(--mono); font-size: 15px; font-weight: 700; }
.ms-cov-low { color: var(--ms-fair); font-weight: 600; cursor: help; }
.ms-when { font-family: var(--mono); font-size: 11.5px; color: var(--ink-3); white-space: nowrap; }
.ms-when sup { font-size: 8.5px; margin-left: 2px; cursor: help; }

@media (max-width: 720px) {
  /* The table has eight columns and will not fit — let it scroll sideways
     inside its own card rather than pushing the whole page wide. */
  .ms-tbl { min-width: 660px; }
  .ms-discs { grid-template-columns: 1fr; }
  .ms-disc-score { font-size: 26px; }
}

/* An amber-edged note: something the reader has to know before trusting the
   figures above it (models left out of the averages, and why). */
.ms-note-warn { border-left-color: var(--ms-fair); }
.ms-note sup { font-size: 9px; }

/* The audit-by-audit report: one row per date, one column per discipline. */
.ms-day-tbl td { vertical-align: middle; }
.ms-day-d { font-family: var(--mono); font-size: 13px; font-weight: 600; white-space: nowrap; }
.ms-day-d small { color: var(--ink-4); font-weight: 400; margin-left: 4px; font-size: 10.5px; }
.ms-day-h { display: inline-flex; align-items: center; gap: 5px; }
.ms-day-h i { width: 8px; height: 8px; border-radius: 2px; }
/* Score and move sit on one line; the model count drops below so a 3-model cell
   is not twice as wide as a 1-model one. */
.ms-day-cell { display: inline-flex; flex-direction: column; align-items: flex-end; gap: 1px; cursor: help; }
.ms-day-cell > .ms-score + .ms-d { margin-left: 6px; }
.ms-day-cell .ms-score, .ms-day-cell .ms-d { display: inline; }
.ms-day-cell small { font-size: 10px; color: var(--ink-4); font-family: var(--mono); }
.ms-day-na { color: var(--ink-4); }
.ms-day-who { font-size: 11.5px; color: var(--ink-3); white-space: nowrap; cursor: help; }
@media (max-width: 720px) { .ms-day-tbl { min-width: 460px; } }

/* ============================================================
   Model Score — reading it in thirty seconds
   ============================================================
   This screen goes in front of management, so DIRECTION is the headline and the
   absolute score is context. Colour therefore encodes exactly one thing: which
   way it went. The grade (Good/Fair/Poor) is carried by the word and the bar, so
   a red number never has to mean "low score" and "fell" at once.

   --ms-up / --ms-dn are NOT the app's --done/--danger. Measured with the dataviz
   palette validator, those two sit at ΔE 4.3 under deuteranopia in dark mode —
   the same colour to a red-green colourblind reader. These two are stepped apart
   in LIGHTNESS as well as hue (ΔE 16.4 light / 24.5 dark, both PASS), and hue is
   only ever the third cue: every up/down is also an arrow, a number and a word. */
:root {
  --ms-up: #12A150;
  --ms-dn: #9B1C15;
  --ms-up-bg: color-mix(in srgb, var(--ms-up) 11%, transparent);
  --ms-dn-bg: color-mix(in srgb, var(--ms-dn) 11%, transparent);
}
@media (prefers-color-scheme: dark) {
  :root { --ms-up: #4ADE80; --ms-dn: #C0392B; }
}
:root[data-theme="dark"] { --ms-up: #4ADE80; --ms-dn: #C0392B; }
:root[data-theme="light"] { --ms-up: #12A150; --ms-dn: #9B1C15; }

/* The one line to read. Big enough to land before anything else on the page. */
.ms-headline { margin: 2px 0 14px; }
.ms-hl-txt {
  font-size: 21px; font-weight: 700; letter-spacing: -0.01em; line-height: 1.35;
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px;
}
.ms-hl-txt b { font-weight: 800; }
.ms-hl-up { color: var(--ms-up); }
.ms-hl-dn { color: var(--ms-dn); }
.ms-hl-flat { color: var(--ink-3); }
.ms-hl-sep { color: var(--ink-4); font-weight: 400; }
.ms-hl-sub { font-size: 12px; color: var(--ink-3); margin-top: 3px; }

/* The discipline tiles carry the answer: score, then which way it moved. */
.ms-disc-row { display: flex; align-items: flex-end; justify-content: space-between; gap: 10px; margin: 10px 0 8px; }
.ms-disc-move { display: flex; flex-direction: column; align-items: flex-end; line-height: 1.1; }
.ms-move-n { font-family: var(--mono); font-size: 21px; font-weight: 800; letter-spacing: -.02em; }
.ms-move-w { font-size: 10.5px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; }
.ms-disc.ms-dir-up   { border-color: color-mix(in srgb, var(--ms-up) 45%, var(--glass-brd)); background-color: var(--ms-up-bg); }
.ms-disc.ms-dir-dn   { border-color: color-mix(in srgb, var(--ms-dn) 45%, var(--glass-brd)); background-color: var(--ms-dn-bg); }
.ms-disc.ms-dir-up   .ms-move-n, .ms-disc.ms-dir-up .ms-move-w { color: var(--ms-up); }
.ms-disc.ms-dir-dn   .ms-move-n, .ms-disc.ms-dir-dn .ms-move-w { color: var(--ms-dn); }
.ms-disc.ms-dir-flat .ms-move-n, .ms-disc.ms-dir-flat .ms-move-w,
.ms-disc.ms-dir-none .ms-move-n, .ms-disc.ms-dir-none .ms-move-w { color: var(--ink-4); }
.ms-disc.ms-dir-up   .cl-bar-fill { background: var(--ms-up); }
.ms-disc.ms-dir-dn   .cl-bar-fill { background: var(--ms-dn); }
/* The score stays in ink: colour on this screen means direction, nothing else. */
.ms-disc .ms-disc-score { color: var(--ink); margin: 0; }

/* The audit table tinted by direction — the column reads as a pattern, while the
   arrow and the number still carry it for anyone the colour does not reach. */
.ms-dc-up { background: var(--ms-up-bg); }
.ms-dc-dn { background: var(--ms-dn-bg); }
.ms-dc-up .ms-d-up { color: var(--ms-up); }
.ms-dc-dn .ms-d-dn { color: var(--ms-dn); }

@media (max-width: 720px) {
  .ms-hl-txt { font-size: 17px; }
  .ms-disc-score { font-size: 24px; }
  .ms-move-n { font-size: 18px; }
}

/* ===== Best models + where the points are ===== */
.ms-two { grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); margin-bottom: 12px; }

.ms-rank {
  display: grid; grid-template-columns: 22px 1fr auto;
  align-items: center; gap: 10px;
  padding: 7px 0; border-bottom: 1px solid var(--rule);
}
.ms-rank:last-of-type { border-bottom: 0; }
.ms-rank-n {
  font-family: var(--mono); font-size: 12px; font-weight: 700; color: var(--ink-4);
  text-align: center;
}
.ms-rank-1 .ms-rank-n { color: var(--accent); }
.ms-rank-body { min-width: 0; }
.ms-rank-name {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  font-size: 12.5px; font-weight: 600; color: var(--ink);
}
.ms-rank-name small { font-family: var(--mono); font-size: 10.5px; font-weight: 600; color: var(--ink-3); }
.ms-rank-next { display: block; font-size: 11.5px; color: var(--ink-3); margin-top: 2px; }
.ms-rank-next b { color: var(--ink-2); }
.ms-rank-score { font-family: var(--mono); font-size: 19px; font-weight: 700; }

/* Points recoverable: the bar is the SIZE OF THE PRIZE, not the score — a long
   bar means "most to gain here", which is the question the block answers. */
.ms-gap { display: grid; grid-template-columns: minmax(110px, 1fr) 90px 42px; align-items: center; gap: 10px; padding: 5px 0; cursor: help; }
.ms-gap-l { font-size: 12.5px; color: var(--ink-2); min-width: 0; }
.ms-gap-l small { display: block; font-family: var(--mono); font-size: 10.5px; color: var(--ink-4); }
.ms-gap-bar { height: 7px; }
.ms-gap .cl-bar-fill { background: var(--accent); }
.ms-gap:first-of-type .cl-bar-fill { background: var(--orange); }
.ms-gap-n { font-family: var(--mono); font-size: 13px; font-weight: 700; text-align: right; color: var(--ink-2); }
.ms-gap:first-of-type .ms-gap-n { color: var(--orange); }
.ms-gap-foot { font-size: 11px; color: var(--ink-4); line-height: 1.5; margin-top: 9px; border-top: 1px solid var(--rule); padding-top: 8px; }

@media (max-width: 720px) {
  .ms-gap { grid-template-columns: 1fr 60px 38px; }
}

/* ============================================================================
   THE LONG-TERM CHECKLIST — beside the Mon–Fri board (Dat, 18/08/2026)
   The board is five day columns stacked one per row, so the space to its right
   was empty at every width above a laptop. The checklist takes it: standing
   work is READ while this week is being planned, which is the only moment
   anybody decides to pull a piece of it forward.
   Under 1100px the panel drops below the board rather than squeezing the days.
   ========================================================================= */
.pl-body { display: flex; gap: 12px; align-items: flex-start; }
.pl-body > .wl-pl-grid { flex: 1 1 auto; min-width: 0; }
.pl-side {
  flex: 0 0 300px; align-self: stretch;
  border: 1px solid var(--rule); border-radius: var(--r);
  background: var(--card-solid);
  display: flex; flex-direction: column; overflow: hidden;
}
/* align-items:stretch matters here: the row layout uses flex-start so the panel
   does not grow to the height of five day columns, and left alone that same
   rule makes both children shrink to their content width once the axis turns
   vertical — the board came out 471px wide inside an 837px page. */
@media (max-width: 1100px) {
  .pl-body { flex-direction: column; align-items: stretch; }
  .pl-side { flex: 1 1 auto; width: 100%; }
}

.pl-side-h {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 10px; border-bottom: 1px solid var(--rule);
  background: var(--bg);
}
.pl-side-t { font-weight: 700; font-size: var(--fs-body); }
.pl-side-n { font-size: var(--fs-label); color: var(--ink-3); margin-right: auto; }
.pl-side-add {
  border: 1px solid var(--rule); background: var(--card-solid); color: var(--ink-2);
  border-radius: var(--r); width: 24px; height: 24px; line-height: 1; cursor: pointer; font-size: 14px;
}
.pl-side-add:hover { border-color: var(--brand); color: var(--brand); }

.pl-lt-addbox { padding: 8px 10px; border-bottom: 1px solid var(--rule); }
/* A textarea since 05/10/2026 (it was an <input>), so a wish can be written on
   more than one line — Enter still adds it, Shift+Enter breaks the line. */
.pl-lt-addbox textarea {
  width: 100%; padding: 6px 8px; border: 1px solid var(--rule); border-radius: var(--r);
  background: var(--card-solid); color: var(--ink); font: inherit; font-size: var(--fs-body);
  line-height: 1.4; resize: vertical; display: block;
}
.pl-lt-hint { font-size: var(--fs-label); color: var(--ink-3); margin-top: 4px; line-height: 1.45; }

.pl-lt-list { display: flex; flex-direction: column; }
.pl-lt-item {
  display: flex; gap: 8px; align-items: flex-start;
  padding: 8px 10px; border-bottom: 1px solid var(--rule);
}
.pl-lt-item:last-child { border-bottom: 0; }
.pl-lt-item:hover { background: var(--bg); }
.pl-lt-tick {
  flex: 0 0 auto; width: 17px; height: 17px; margin-top: 1px;
  border: 1.5px solid var(--rule); border-radius: 4px;
  background: var(--card-solid); color: #fff; cursor: pointer; line-height: 1; font-size: 11px;
}
.pl-lt-tick:hover { border-color: var(--ok); }
.pl-lt-item.done .pl-lt-tick { background: var(--ok); border-color: var(--ok); }
.pl-lt-body { flex: 1 1 auto; min-width: 0; }
/* The padding, the radius and the bleed are on EVERY task, tinted or not, so
   changing the ranking changes only the colour — the sentence never shifts under
   the pointer while you are reading it. */
.pl-lt-task {
  display: block; font-size: var(--fs-body); line-height: 1.4; cursor: text; word-break: break-word;
  padding: 2px 6px; margin: 0 -6px; border-radius: var(--r); background: transparent;
  /* The line breaks somebody typed are shown. Without this the markup holds them
     and HTML collapses them, so the panel silently reflows a three-line wish
     into one — see .pl-nt-text, which has had this since it was written. */
  white-space: pre-wrap;
}
/* A wash behind the task, not a highlighter: 10% leaves the text at full
   contrast, so the tint is read while READING the line — the stripe down the
   left is for scanning the list, and these two answer different questions.
   The same two hues as the stripe; nothing new enters the palette. */
.pl-lt-item.prio-high .pl-lt-task { background: color-mix(in srgb, var(--prio-high) 10%, transparent); }
.pl-lt-item.prio-low  .pl-lt-task { background: color-mix(in srgb, var(--prio-low)  10%, transparent); }
/* Finished work keeps neither cue, for the reason the stripe does not: a tinted,
   struck-through line still takes the eye first, and its urgency is history. */
.pl-lt-item.done .pl-lt-task { background: transparent; }
/* Done is struck through and dimmed to --ink-3: --ink-2 under a line still
   reads as live work, and this list is read at a glance. */
.pl-lt-item.done .pl-lt-task { text-decoration: line-through; color: var(--ink-3); }
/* A textarea since 05/10/2026, so a wish can be written on more than one line.
   `resize: vertical` and a line-height to match the text it replaces, or the box
   jumps a pixel or two as it opens and the whole row twitches. */
.pl-lt-task-e {
  width: 100%; padding: 3px 6px; border: 1px solid var(--brand); border-radius: var(--r);
  background: var(--card-solid); color: var(--ink); font: inherit; font-size: var(--fs-body);
  line-height: 1.4; resize: vertical; min-height: 3.2em; display: block;
}
/* Priority on the shelf (19/08/2026). Red and blue, NOT red and amber: the same
   pair, and the same reason, as PRIORITY_COLORS in tools/issue-board.mjs — red
   and amber sit ΔE 5.4 apart under deuteranopia, which is two colours nobody can
   separate. Low is not a paler emergency; it is a different KIND of item, so it
   gets a different hue rather than a weaker one.
   'Normal' has NO colour and NO stripe: it is the default on every item written
   before today, and a stripe on everything is a stripe on nothing. */
:root { --prio-high: #BE2A16; --prio-low: #4F6FD9; }
@media (prefers-color-scheme: dark) { :root { --prio-high: #E4614B; --prio-low: #6E82DE; } }
:root[data-theme="dark"]  { --prio-high: #E4614B; --prio-low: #6E82DE; }
:root[data-theme="light"] { --prio-high: #BE2A16; --prio-low: #4F6FD9; }

/* The stripe is on every row so the text never shifts when the ranking changes. */
.pl-lt-item { border-left: 3px solid transparent; }
.pl-lt-item.prio-high { border-left-color: var(--prio-high); }
.pl-lt-item.prio-low  { border-left-color: var(--prio-low); }
/* A finished item is finished — its urgency is history, and a red stripe down a
   struck-through line still pulls the eye first. */
.pl-lt-item.done { border-left-color: transparent; }

.pl-lt-prio {
  border: 1px solid var(--rule); border-radius: var(--r);
  background: var(--card-solid); color: var(--ink-3);
  font: inherit; font-size: var(--fs-label); padding: 1px 4px; cursor: pointer;
}
.pl-lt-item.prio-high .pl-lt-prio { color: var(--prio-high); border-color: var(--prio-high); font-weight: 700; }
.pl-lt-item.prio-low  .pl-lt-prio { color: var(--prio-low);  border-color: var(--prio-low); }
.pl-lt-item.done .pl-lt-prio { color: var(--ink-4); border-color: var(--rule); font-weight: 400; }
/* Drawn by the OS menu, which inherits none of the above — left unset the
   options can come out white-on-white in dark mode. */
.pl-lt-prio option { color: var(--ink); background: var(--card-solid); }

.pl-lt-meta { display: flex; align-items: center; gap: 5px; margin-top: 5px; flex-wrap: wrap; }
.pl-lt-proj, .pl-lt-by {
  border: 1px solid var(--rule); border-radius: var(--r);
  background: var(--card-solid); color: var(--ink-2);
  font: inherit; font-size: var(--fs-label); padding: 1px 4px;
}
.pl-lt-by { color: var(--ink-3); }
/* Wanted BY a date already gone. Not an error — a standing item outliving its
   target is ordinary — so it is amber, not red, and nothing else changes. */
.pl-lt-by.late { color: var(--warn); border-color: var(--warn); }
.pl-lt-who {
  font-size: var(--fs-label); font-weight: 700; padding: 1px 5px; border-radius: 999px;
  background: color-mix(in srgb, var(--oc) 18%, transparent); color: var(--oc);
}
.pl-lt-acts { display: flex; gap: 2px; flex: 0 0 auto; }
.pl-lt-sched, .pl-lt-x {
  border: 0; background: transparent; color: var(--ink-3);
  cursor: pointer; padding: 1px 4px; border-radius: var(--r); font-size: 12px; line-height: 1.4;
}
.pl-lt-sched:hover { color: var(--brand); background: color-mix(in srgb, var(--brand) 12%, transparent); }
.pl-lt-x:hover { color: var(--danger); background: var(--danger-bg); }
.pl-lt-empty { padding: 18px 12px; text-align: center; color: var(--ink-3); font-size: var(--fs-meta); }
.pl-lt-empty small { display: block; margin-top: 6px; font-size: var(--fs-label); line-height: 1.5; }
.pl-lt-showall {
  border: 0; background: transparent; color: var(--brand); cursor: pointer;
  font: inherit; font-size: var(--fs-label); text-decoration: underline; padding: 0;
}

/* =========================================================================
   The side of the Week Plan — three panels, two columns
   =========================================================================
   Left column: Long-term over Concerns, both a few short rows. Right column:
   Notes, on its own, because it is the only one holding pictures and stacked
   under the other two it started every screenshot below the fold.

   The 300px belongs to the WRAPPERS, and each panel sizes to its own content.
   Without the override the `flex: 0 0 300px` written for a single panel in a
   ROW becomes a 300px HEIGHT apiece once the axis turns vertical — identical
   boxes, mostly empty, whatever is in them. */
.pl-body > .pl-aside {
  flex: 0 0 auto; align-self: stretch; min-width: 0;
  display: flex; gap: 12px; align-items: flex-start;
}
/* This one FIRST, and the widths after it. .pl-pnotes carries .pl-side too, so
   the two rules match the same element at the same specificity (0,2,0) and the
   later one wins outright — written the other way round, `flex: 0 0 auto` beat
   the 300px and the Notes panel sized itself to its widest project name
   instead. Source order is the whole of the rule here; nothing about the
   selectors says which is meant to win. */
.pl-aside .pl-side { flex: 0 0 auto; align-self: auto; }
.pl-aside-col {
  flex: 0 0 300px; width: 300px; min-width: 0;
  display: flex; flex-direction: column; gap: 12px;
}
/* The same 300px as the column beside it. It was wider to give screenshots room,
   which stopped being the right trade once the thumbnails were capped: the
   picture is opened full size to be read, so the panel only has to be wide
   enough for the words.

   width AND max-width alongside the flex basis, because the panel holds two
   <select>s: a select is sized by its longest OPTION, and "TLC Standard R&D"
   in a list of sixty projects is enough to push a flex item past its basis. */
.pl-aside > .pl-pnotes {
  flex: 0 0 300px; width: 300px; max-width: 300px; min-width: 0;
}
/* The Week Plan needs more than the app's 1180px — five day columns plus two
   300px side columns — but it is NOT given the whole window. Edge to edge on a
   27" monitor it read as a wall (Dat, 09/09/2026): the eye has nothing to stop
   at, and a board is easier to scan when the page has a margin round it.
   So: a wider column, still centred, still with white space either side.

   1600 rather than a round 1500 or 1800 because of what has to fit inside it —
   1552px of content, less 612px of side panels and their gap, leaves about
   185px a day column, which is where a task title stops wrapping to three
   lines. Below a 1500px WINDOW the panels stack and this cap stops mattering. */
.tlc-body:has(> #view > .pl-page) { max-width: 1600px; }
/* Not wide enough for two side columns: Notes goes back under the other two
   rather than squeezing the week into slivers. The board is the screen. */
@media (max-width: 1500px) {
  .pl-body > .pl-aside { flex-direction: column; flex: 0 0 300px; align-items: stretch; }
  .pl-aside-col { flex: 0 0 auto; }
  .pl-aside > .pl-pnotes { flex: 0 0 auto; }
}
@media (max-width: 1100px) {
  .tlc-body:has(> #view > .pl-page) { max-width: 1180px; }
  .pl-body > .pl-aside { flex: 1 1 auto; width: 100%; }
  /* Stacked under the board there is no column to match any more, so the fixed
     300px comes off — otherwise the panels sit in a narrow strip on the left of
     a full-width page with nothing beside them. */
  .pl-aside-col, .pl-aside > .pl-pnotes { width: auto; max-width: none; }
}

.pl-nt-addbox { padding: 8px 10px; border-bottom: 1px solid var(--rule); }
/* A textarea, not an input: a concern is a sentence or two — "the ARC and STR
   drawings disagree on the parapet height at L17" — and a one-line box that
   scrolls sideways is how it gets typed as four words instead. */
.pl-nt-addbox textarea, .pl-nt-text-e, .pl-nt-ans-e {
  width: 100%; padding: 6px 8px; border: 1px solid var(--rule); border-radius: var(--r);
  background: var(--card-solid); color: var(--ink); font: inherit; font-size: var(--fs-body);
  resize: vertical;
}
.pl-nt-hint { font-size: var(--fs-label); color: var(--ink-3); margin-top: 4px; line-height: 1.45; }
/* The count of concerns with nobody named to answer. Said out loud at the top
   of the panel because that is the failure this list exists to stop: one nobody
   owns reads exactly like one that is under control. */
.pl-nt-warn {
  padding: 5px 10px; font-size: var(--fs-label);
  color: var(--warn); background: color-mix(in srgb, var(--warn) 10%, transparent);
  border-bottom: 1px solid var(--rule);
}

.pl-nt-list { display: flex; flex-direction: column; }
.pl-nt-item {
  display: flex; gap: 8px; align-items: flex-start;
  padding: 8px 10px; border-bottom: 1px solid var(--rule);
  border-left: 3px solid transparent;
}
.pl-nt-item:last-child { border-bottom: 0; }
.pl-nt-item:hover { background: var(--bg); }
/* Open a week or more. Not red — nothing is wrong yet — but no longer silent:
   the whole point of the age being on the row is that it can start to shout. */
.pl-nt-item.stale { border-left-color: var(--warn); }
.pl-nt-item.done { border-left-color: transparent; }

/* The tick reads '?' while it is open and '✓' once answered, so the button says
   which of the two states the row is in before any colour is read. */
.pl-nt-tick {
  flex: 0 0 auto; width: 20px; height: 20px; margin-top: 1px;
  border: 1px solid var(--rule-2); border-radius: 50%;
  background: var(--card-solid); color: var(--ink-4);
  font-size: 11px; font-weight: 700; line-height: 1; cursor: pointer;
}
.pl-nt-tick:hover { border-color: var(--ok); color: var(--ok); }
.pl-nt-item.done .pl-nt-tick { background: var(--ok); border-color: var(--ok); color: #fff; }

.pl-nt-body { flex: 1 1 auto; min-width: 0; }
.pl-nt-text {
  display: block; font-size: var(--fs-body); line-height: 1.45; cursor: text;
  border-radius: var(--r); padding: 1px 3px; margin: -1px -3px;
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.pl-nt-text:hover { background: var(--hover); }
/* Struck through only the QUESTION, never the answer — the answer is the part
   worth reading afterwards, and it is the reason the row is kept at all. */
.pl-nt-item.done .pl-nt-text { text-decoration: line-through; color: var(--ink-3); }
.pl-nt-ans {
  margin-top: 5px; padding: 5px 7px; border-radius: var(--r);
  background: color-mix(in srgb, var(--ok) 9%, transparent);
  border-left: 2px solid var(--ok);
  font-size: var(--fs-meta); line-height: 1.45; color: var(--ink-2);
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.pl-nt-ans b { color: var(--ok); margin-right: 3px; }
.pl-nt-ansbox { margin-top: 6px; }
.pl-nt-ansacts { display: flex; gap: 5px; margin-top: 5px; }
.pl-nt-save {
  border: 1px solid var(--ok); background: var(--ok); color: #fff;
  border-radius: var(--r); padding: 4px 9px; cursor: pointer;
  font: inherit; font-size: var(--fs-label); font-weight: 700;
}
.pl-nt-cancel {
  border: 1px solid var(--rule); background: var(--card-solid); color: var(--ink-3);
  border-radius: var(--r); padding: 4px 9px; cursor: pointer;
  font: inherit; font-size: var(--fs-label);
}
.pl-nt-cancel:hover { border-color: var(--rule-2); color: var(--ink-2); }

.pl-nt-meta { display: flex; align-items: center; gap: 5px; margin-top: 5px; flex-wrap: wrap; }
.pl-nt-proj, .pl-nt-of {
  font: inherit; font-size: var(--fs-label); color: var(--ink-2);
  border: 1px solid var(--rule); border-radius: var(--r);
  background: transparent; padding: 1px 3px; max-width: 120px; cursor: pointer;
}
.pl-nt-proj option, .pl-nt-of option { color: var(--ink); background: var(--card-solid); }
/* Nobody named to answer. Dashed rather than coloured: it is a gap, not an
   error — but a gap that has to look like one. */
.pl-nt-of.none { border-style: dashed; color: var(--ink-4); }
.pl-nt-of:not(.none) { border-color: var(--brand); color: var(--brand); font-weight: 700; }
.pl-nt-by {
  font-size: var(--fs-label); color: var(--oc, var(--ink-3));
  border-left: 2px solid var(--oc, var(--rule)); padding-left: 5px;
}
/* How long it has been open, in days. Tabular so a column of them lines up. */
.pl-nt-age {
  margin-left: auto; font-family: var(--mono); font-size: var(--fs-label);
  color: var(--ink-4); font-variant-numeric: tabular-nums;
}
.pl-nt-item.stale .pl-nt-age { color: var(--warn); font-weight: 700; }

.pl-nt-acts { display: flex; gap: 2px; flex: 0 0 auto; }
.pl-nt-x {
  border: 0; background: transparent; color: var(--ink-4); cursor: pointer;
  font-size: 12px; line-height: 1; padding: 3px 5px; border-radius: var(--r);
}
.pl-nt-x:hover { color: var(--danger); background: var(--danger-bg); }
/* The "show what is folded away" strip at the foot of a side panel. Shared by
   Concerns (settled) and the Wish List (done) — same gesture, same place. */
.pl-nt-fold, .pl-lt-fold {
  border: 0; border-top: 1px solid var(--rule); background: transparent;
  color: var(--ink-3); cursor: pointer; font: inherit; font-size: var(--fs-label);
  padding: 6px 10px; text-align: left; width: 100%;
}
.pl-nt-fold:hover, .pl-lt-fold:hover { color: var(--brand); background: var(--bg); }

/* =========================================================================
   Project notes — the fourth panel, the one with the pictures in it
   ========================================================================= */
.pn-pick { padding: 7px 10px; border-bottom: 1px solid var(--rule); }
.pn-proj {
  width: 100%; font: inherit; font-size: var(--fs-label);
  padding: 4px 6px; border: 1px solid var(--rule); border-radius: var(--r);
  background: var(--card-solid); color: var(--ink); cursor: pointer;
}
.pn-proj:focus { border-color: var(--accent); outline: none; }
.pn-addbox { padding: 8px 10px; border-bottom: 1px solid var(--rule); }
.pn-addbox textarea, .pn-text-e {
  width: 100%; padding: 6px 8px; border: 1px solid var(--rule); border-radius: var(--r);
  background: var(--card-solid); color: var(--ink); font: inherit; font-size: var(--fs-body);
  resize: vertical;
}
.pn-addbox textarea { border-color: var(--accent); }
.pn-hint { font-size: var(--fs-label); color: var(--ink-3); margin-top: 4px; line-height: 1.45; }
/* Re-encoding half a megabyte takes a moment somebody can notice, so it says so
   rather than looking as if the paste did nothing. */
.pn-busy {
  padding: 6px 10px; font-size: var(--fs-label); color: var(--brand);
  background: var(--accent-soft); border-bottom: 1px solid var(--rule);
}

.pn-list { display: flex; flex-direction: column; }
.pn-item { padding: 8px 10px; border-bottom: 1px solid var(--rule); }
.pn-item:last-child { border-bottom: 0; }
.pn-item:hover { background: var(--bg); }
/* Wraps rather than widens: date, author, project picker and ✕ on one line when
   they fit, two when they do not. The panel's width is fixed, so something in
   here has to give and it must not be the panel. */
.pn-top {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  min-width: 0; font-size: var(--fs-label);
}
.pn-when { color: var(--ink-4); font-family: var(--mono); font-variant-numeric: tabular-nums; }
.pn-who { color: var(--oc, var(--ink-3)); border-left: 2px solid var(--oc, var(--rule)); padding-left: 5px; }
/* The project a note belongs to — a picker on every card, so one filed against
   the wrong project can be put right where it is seen to be wrong. */
.pn-tag, .pn-newproj {
  font: inherit; font-family: var(--mono); font-size: var(--fs-label); font-weight: 700;
  color: var(--brand); background: transparent; cursor: pointer;
  border: 1px solid var(--rule); border-radius: var(--r); padding: 0 3px;
  max-width: 110px; min-width: 0;
}
.pn-tag option, .pn-newproj option { color: var(--ink); background: var(--card-solid); font-family: var(--mono); }
.pn-tag:hover, .pn-newproj:hover { border-color: var(--brand); }
.pn-tag:focus, .pn-newproj:focus { border-color: var(--accent); outline: none; }
/* Belongs to nothing: dashed and grey, so an unfiled note reads as a gap rather
   than as tidy. */
.pn-tag.none, .pn-newproj.none {
  border-style: dashed; color: var(--ink-4); font-weight: 400;
}
/* Where a NEW note will be filed, on screen while it is being written.
   min-width: 0 on both — a <select> is sized by its longest OPTION, and a flex
   item will not shrink below that intrinsic width without being told it may.
   Sixty project codes in the list would otherwise widen the whole panel. */
.pn-filed { display: flex; align-items: center; gap: 6px; margin-top: 6px; min-width: 0; }
.pn-filed-l { font-size: var(--fs-label); color: var(--ink-3); flex: none; }
.pn-newproj { flex: 1 1 auto; min-width: 0; max-width: none; }
.pn-x {
  margin-left: auto; border: 0; background: transparent; color: var(--ink-4);
  cursor: pointer; font-size: 12px; line-height: 1; padding: 2px 4px; border-radius: var(--r);
}
.pn-x:hover { color: var(--danger); background: var(--danger-bg); }
.pn-text {
  margin-top: 4px; font-size: var(--fs-body); line-height: 1.45; cursor: text;
  border-radius: var(--r); padding: 2px 3px; margin-left: -3px;
  /* Notes are typed with line breaks in them and pasted from elsewhere; both
     have to survive, and a long path or URL must wrap rather than push the
     panel sideways. */
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.pn-text:hover { background: var(--hover); }
.pn-text.empty { color: var(--ink-4); font-style: italic; }

/* Thumbnails of a FIXED size, not the picture itself.
   They were full width with height:auto, so the note took the shape of whatever
   was pasted into it: one tall screenshot made a card four hundred pixels
   deep and pushed every note under it off the screen. A thumbnail is a handle,
   not the picture — it is clicked to open full size, and that is where a clash
   is actually read. So they are a fixed 4:3 tile, several to a row, and a note
   with five images is one short strip rather than five full-width pictures. */
.pn-imgs {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(78px, 1fr));
  gap: 5px; margin-top: 6px;
}
.pn-img { position: relative; margin: 0; line-height: 0; }
.pn-img img {
  width: 100%; height: auto; aspect-ratio: 4 / 3; display: block;
  /* cover, anchored top-left: a screenshot's subject is almost never in the
     bottom-right, and a letterboxed 78px tile shows less of it than a cropped
     one. Nothing is lost — the whole image is one click away. */
  object-fit: cover; object-position: top left;
  border: 1px solid var(--rule); border-radius: var(--r);
  background: var(--bg); cursor: zoom-in;
}
.pn-img img:hover { border-color: var(--brand); }
/* Small, because the tile it sits on is now 78px: at the old size it covered a
   quarter of the picture the moment the pointer arrived. */
.pn-img-x {
  position: absolute; top: 2px; right: 2px;
  border: 0; border-radius: var(--r); cursor: pointer;
  background: rgba(0, 0, 0, .6); color: #fff;
  font-size: 9px; line-height: 1; padding: 2px 4px;
  opacity: 0; transition: opacity .12s;
}
.pn-img:hover .pn-img-x, .pn-img-x:focus { opacity: 1; }
.pn-img-x:hover { background: var(--danger); }

/* Full size, over everything. Click anywhere or press Esc to shut it — there is
   nothing to do in here but look. */
.pn-lightbox {
  position: fixed; inset: 0; z-index: 9000;
  display: flex; align-items: center; justify-content: center;
  background: rgba(12, 16, 24, .82); cursor: zoom-out; padding: 24px;
}
.pn-lightbox img {
  max-width: 100%; max-height: 100%;
  border-radius: var(--r); box-shadow: 0 18px 60px rgba(0, 0, 0, .5);
  background: #fff;
}
.pn-lb-x {
  position: absolute; top: 14px; right: 18px;
  border: 0; background: rgba(255, 255, 255, .14); color: #fff;
  border-radius: var(--r); cursor: pointer; font-size: 16px; line-height: 1; padding: 7px 10px;
}
.pn-lb-x:hover { background: rgba(255, 255, 255, .28); }
@media (prefers-reduced-motion: reduce) { .pn-img-x { transition: none; } }

/* ===================================================================
   Diary Clash Check — rewritten 08/09/2026

   Its OWN prefix, .dcc-. The .cl-* classes look like this tab's property but
   are not: Model Score, Issue Report, KPI and Reports borrow .cl-card,
   .cl-kpi, .cl-row, .cl-table, .cl-grid, .cl-bar, .cl-ppill and .cl-empty in
   33 places between them. Restyling one to suit this screen would silently
   restyle four other tabs, so nothing above this line is touched.

   Colours come from the variables only, so dark mode follows with no second
   set of rules.
   =================================================================== */

/* ---- the two filter rows ---- */
.dcc-filters { display: flex; flex-direction: column; gap: 8px; margin-bottom: 14px; }
.dcc-frow { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.dcc-flabel {
  font-family: var(--mono); font-size: var(--fs-label); letter-spacing: var(--ls-label);
  text-transform: uppercase; color: var(--ink-3); min-width: 52px;
}
.dcc-sel {
  padding: 6px 10px; border-radius: var(--r);
  border: 1px solid var(--rule-2); background: var(--card); color: var(--ink);
  font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
  max-width: 220px;
}
.dcc-sel:disabled { opacity: .45; cursor: default; }
.dcc-sel-month { min-width: 140px; }
.dcc-sel-pkg { max-width: 300px; }
.dcc-clear {
  border: 0; background: transparent; color: var(--ink-4); cursor: pointer;
  font-size: 13px; line-height: 1; padding: 5px 6px; border-radius: var(--r);
}
.dcc-clear:hover { background: var(--hover); color: var(--ink); }
.dcc-actions { display: flex; gap: 8px; margin-left: auto; }

.dcc-scan-wrap { position: relative; display: inline-block; }
.dcc-scan-menu {
  position: absolute; top: calc(100% + 4px); right: 0; z-index: 50;
  background: var(--card-solid); border: 1px solid var(--rule);
  border-radius: var(--r); box-shadow: 0 10px 28px var(--glass-shadow);
  min-width: 236px; padding: 4px;
}
.dcc-menu-item {
  display: flex; flex-direction: column; align-items: flex-start; gap: 1px;
  width: 100%; text-align: left; background: transparent; border: 0; padding: 8px 10px;
  border-radius: var(--r); cursor: pointer; color: var(--ink); font: inherit;
  font-weight: 600; font-size: 13px;
}
.dcc-menu-item small { color: var(--ink-3); font-weight: 400; font-size: var(--fs-label); }
.dcc-menu-item:hover { background: var(--hover); }

/* ---- the KPI strip: three figures, all counting PACKAGES ---- */
.dcc-kpis { display: flex; gap: 10px; margin-bottom: 14px; flex-wrap: wrap; }
.dcc-kpi {
  background: var(--card); border: 1px solid var(--rule); border-radius: var(--r);
  padding: 10px 18px; min-width: 96px;
  display: flex; flex-direction: column; gap: 2px;
}
.dcc-kpi b { font-size: 26px; font-weight: 700; font-family: var(--mono); line-height: 1; }
.dcc-kpi span {
  font-size: var(--fs-label); letter-spacing: var(--ls-label);
  text-transform: uppercase; color: var(--ink-3); font-family: var(--mono);
}
.dcc-kpi-doing b { color: var(--doing); }
.dcc-kpi-stale b { color: var(--danger); }
.dcc-kpi-free b { color: var(--done); }

/* ---- cards ---- */
.dcc-card {
  background: var(--card); border: 1px solid var(--rule);
  border-radius: var(--r); padding: 12px 14px; margin-bottom: 12px;
}
.dcc-card-h {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  font-weight: 700; font-size: 14px; margin-bottom: 10px;
}
.dcc-card-sub { font-weight: 400; font-size: var(--fs-meta); color: var(--ink-3); }
.dcc-pct { font-family: var(--mono); color: var(--brand2); }
.dcc-mx-actions { margin-left: auto; display: flex; gap: 6px; }
.dcc-mini { padding: 4px 10px; font-size: var(--fs-meta); }
.dcc-note {
  margin-top: 10px; padding-top: 9px; border-top: 1px solid var(--rule);
  font-size: var(--fs-meta); color: var(--ink-3); line-height: 1.55;
}
.dcc-empty-line { padding: 14px 4px; color: var(--ink-3); font-size: var(--fs-meta); }

/* ---- step 1: the project list ---- */
.dcc-plist { display: flex; flex-direction: column; gap: 2px; }
.dcc-prow {
  display: grid; grid-template-columns: 90px minmax(120px, 1fr) 72px minmax(180px, 260px);
  align-items: center; gap: 12px; padding: 7px 8px; border-radius: var(--r);
  border: 0; background: none; width: 100%; text-align: left; font: inherit; color: inherit;
}
.dcc-prow-btn { cursor: pointer; }
.dcc-prow-btn:hover { background: var(--hover); }
.dcc-phead {
  font-family: var(--mono); font-size: var(--fs-label); letter-spacing: var(--ls-label);
  text-transform: uppercase; color: var(--ink-4); padding-bottom: 2px;
}
.dcc-pname {
  font-family: var(--mono); font-weight: 700; font-size: 12.5px; color: var(--brand);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
:root[data-theme="dark"] .dcc-pname { color: var(--brand2); }
.dcc-bar {
  position: relative; display: block; height: 9px; border-radius: 999px;
  background: var(--rule);
}
.dcc-bar-fill { display: block; height: 100%; border-radius: 999px; background: var(--brand2); }
.dcc-bar-fill.done { background: var(--done); }
.dcc-bar i {
  position: absolute; right: -34px; top: -4px;
  font-style: normal; font-family: var(--mono); font-size: 11px; color: var(--ink-3);
}
.dcc-num { font-family: var(--mono); font-size: 12px; color: var(--ink-2); text-align: right; }
.dcc-pstatus { display: flex; gap: 5px; flex-wrap: wrap; justify-content: flex-end; }

.dcc-tag {
  font-family: var(--mono); font-size: 10.5px; font-weight: 700;
  padding: 2px 7px; border-radius: 999px; white-space: nowrap;
}
.dcc-tag.free  { background: var(--done-bg);     color: var(--done); }
.dcc-tag.defer { background: var(--accent-soft); color: var(--brand2); }
.dcc-tag.doing { background: var(--doing-bg);    color: var(--doing); }
.dcc-tag.stale { background: var(--danger-bg);   color: var(--danger); }
.dcc-tag.manual { background: var(--pending-bg); color: var(--pending); }

/* ---- step 2: the Block x Type matrix ---- */
.dcc-legend {
  display: flex; gap: 12px; flex-wrap: wrap; align-items: center;
  margin-bottom: 8px; font-size: var(--fs-label); color: var(--ink-3);
}
.dcc-lg-hint { margin-left: auto; font-style: italic; }
/* The matrix is the one thing on this screen that may need to scroll sideways.
   The page body must never do that, so the overflow lives on this wrapper. */
.dcc-mx-wrap { overflow-x: auto; }
.dcc-mx { border-collapse: separate; border-spacing: 2px; width: 100%; }
.dcc-mx th, .dcc-mx td { padding: 0; }
.dcc-colh {
  font-family: var(--mono); font-size: var(--fs-label); font-weight: 700;
  color: var(--ink-2); text-transform: uppercase; letter-spacing: .04em;
  vertical-align: bottom; padding: 0 4px 6px; min-width: 74px; max-width: 96px;
}
.dcc-colh span { display: block; line-height: 1.25; overflow-wrap: anywhere; }
.dcc-colh.is-none { color: var(--doing); }
/* The corner above the row labels names the row axis (Dat, 10/09/2026): the
   columns were headed by their types and the rows had no heading at all. Styled
   as a column header, because that is what it is; it keeps .dcc-rowh's sticky
   position and solid background, and sits one layer above the row labels so the
   block names scrolling under it never show through. */
.dcc-mx-corner {
  font-size: var(--fs-label); color: var(--ink-2); text-transform: uppercase;
  letter-spacing: .04em; vertical-align: bottom; padding-bottom: 6px; z-index: 3;
}
/* Sticky, so the block name stays put while the type columns scroll under it. */
.dcc-rowh {
  position: sticky; left: 0; z-index: 2; background: var(--card-solid);
  font-family: var(--mono); font-size: 12px; font-weight: 700; color: var(--ink);
  text-align: left; padding: 0 10px 0 6px; white-space: nowrap;
}
.dcc-cell {
  height: 42px; min-width: 74px; border-radius: var(--r); cursor: pointer;
  text-align: center; vertical-align: middle; border: 1px solid transparent;
  font-family: var(--mono); font-size: 11.5px; line-height: 1.2;
}
.dcc-cell-top { display: block; font-weight: 700; }
.dcc-cell-sub { display: block; font-size: 10px; opacity: .8; }
.dcc-more { font-style: normal; font-size: 9.5px; opacity: .75; margin-left: 3px; }
.dcc-cell.free  { background: var(--done-bg);     color: var(--done); }
.dcc-cell.defer { background: var(--accent-soft); color: var(--brand2); }
.dcc-cell.doing { background: var(--doing-bg);    color: var(--doing); }
.dcc-cell.stale { background: var(--danger-bg);   color: var(--danger); }
/* Never checked. Deliberately the emptiest thing on the screen — the gaps ARE
   the report, so they have to read as holes rather than as another colour. */
.dcc-cell.todo  { background: transparent; border-style: dashed; border-color: var(--rule-2); }
.dcc-cell.na    { background: transparent; color: var(--ink-4); cursor: default; opacity: .5; }
.dcc-cell.open  { outline: 2px solid var(--brand2); outline-offset: -1px; }
.dcc-cell:hover:not(.na) { filter: brightness(.97); }
.dcc-tot {
  font-family: var(--mono); font-size: 11px; color: var(--ink-3);
  text-align: center; padding: 4px 6px 0; white-space: nowrap;
}
.dcc-tot-all { font-weight: 700; color: var(--ink); }

/* ===== Visual polish (Dat, 10/09/2026: "tối ưu lại giao diện, đẹp mắt hơn") =====
   ONE block laid over the rules above instead of edited into them, so the whole
   pass comes back out by deleting it. Tokens only — dark and light follow.
   Checked against a headless screenshot of the real tab, before and after. */

/* Air between the cells. At 2px they touched, and a grid of touching boxes reads
   as one striped slab rather than as cells. */
.dcc-mx { border-spacing: 5px; }
.dcc-cell {
  height: 46px; border-radius: 8px;
  transition: transform .12s ease, box-shadow .12s ease, background .12s ease;
}

/* Never checked: still a hole, but a quiet one. A dashed outline round every
   empty cell was the loudest thing on the table — 72 of BNH1's 81 cells. A faint
   flat tint keeps each gap visible without drawing a box round it. */
.dcc-cell.todo {
  border: 1px solid transparent;
  background: color-mix(in srgb, var(--ink) 4%, transparent);
}
.dcc-cell.todo:hover { background: color-mix(in srgb, var(--ink) 9%, transparent); filter: none; }

/* Checked: a status edge down the left and a small lift on hover, so a coloured
   cell reads as something to open rather than as paint. */
.dcc-cell.free, .dcc-cell.defer, .dcc-cell.doing, .dcc-cell.stale {
  box-shadow: inset 3px 0 0 currentColor;
}
.dcc-cell.free:hover, .dcc-cell.defer:hover, .dcc-cell.doing:hover, .dcc-cell.stale:hover {
  filter: none; transform: translateY(-1px);
  box-shadow: inset 3px 0 0 currentColor, 0 6px 16px var(--glass-shadow);
}
.dcc-cell-top { font-size: 13px; letter-spacing: .02em; }
.dcc-cell-sub { margin-top: 2px; opacity: .72; }
.dcc-cell.open { outline: 2px solid var(--brand2); outline-offset: 1px; }

/* The block names: a hairline between them and the grid, and a touch more room,
   so the label column reads as a column rather than as a darker strip. */
.dcc-rowh { padding-right: 14px; }
.dcc-mx tbody .dcc-rowh, .dcc-mx tfoot .dcc-rowh { box-shadow: inset -1px 0 0 var(--rule); }
/* ONE typeface for both axes (Dat, 10/09/2026: "ô block và ô type nhìn không đồng
   bộ font, hàng bị lệch, text còn rất nhỏ"). The type heads were 10.5px in ink-2
   with wide tracking, the block names 12px in ink with none, and the corner took
   after the columns while standing on top of the rows: three treatments for one
   role, the label of a row or a column. One size, weight, tracking and case now;
   only the corner — the NAME of an axis, not a value on it — sits a step quieter. */
.dcc-colh, .dcc-rowh, .dcc-mx-corner {
  font-family: var(--mono); font-size: 12.5px; font-weight: 700; line-height: 1.3;
  letter-spacing: .03em; text-transform: uppercase; color: var(--ink);
}
.dcc-colh { padding: 0 6px 8px; }
.dcc-mx-corner { vertical-align: bottom; padding-bottom: 8px; }

/* ONE ink and ONE weight for every label on the table (Dat, 10/09/2026: "các text
   có độ đậm mờ khác nhau"). Three things were quieter than their neighbours and
   read as greyed-out rather than as different: the combined-type heads (ink-3 at
   600, from an older rule further down the file that outranked the one here), the
   corner, and the totals. The '+' in a combined head already says what it is.
   Written with .dcc-mx in front so it wins over that older rule whatever the order.
   The '(no type)' head keeps its colour — orange there means "needs renaming",
   which is a signal, not a fade. */
.dcc-mx .dcc-colh span, .dcc-mx .dcc-colh.is-multi span { font-weight: 700; }
.dcc-mx .dcc-colh:not(.is-none) span, .dcc-mx .dcc-mx-corner { color: var(--ink); }
.dcc-mx .dcc-tot { color: var(--ink); font-weight: 700; }

/* Every label on its row's centre line. The totals had a top padding that rode
   '2/2' a few pixels below the block name it belongs to — the misaligned rows. */
.dcc-mx tbody th, .dcc-mx tbody td { vertical-align: middle; }
.dcc-tot { padding: 0 8px; font-size: 12.5px; }
.dcc-mx tfoot th, .dcc-mx tfoot td { vertical-align: top; padding-top: 8px; }

/* Larger figures inside the cells: the check and the date were 13px and 10px. */
.dcc-cell { height: 52px; }
.dcc-cell-top { font-size: 15px; }
/* The date a touch under the check, not faded out beside it: at .72 it read as a
   different, greyed shade of the same colour — the same complaint as the labels. */
.dcc-cell-sub { font-size: 11.5px; opacity: .9; }

/* ===== Colour and emphasis (Dat, 11/09/2026: "vẫn còn hơi đơn điệu, làm cho bắt
   mắt và dễ nhìn hơn") =====
   Still inside the polish layer, so it comes out with it. Every colour is a
   status token the tab already uses — nothing new to learn, just used louder. */

/* KPI tiles: four identical grey boxes become four different things. Each carries
   its status colour three ways — a rule across the top, a tinted glyph badge, and
   the figure — so the eye sorts them before reading them. */
.dcc-kpi {
  position: relative; overflow: hidden; min-width: 150px;
  padding: 14px 18px 12px 14px;
  display: grid; grid-template-columns: auto 1fr; column-gap: 12px; row-gap: 1px;
  /* Packed to the TOP, not centred: the Free tile carries an extra row (its bar),
     so centring put its figure a few pixels higher than the other three and the
     four numbers stopped lining up. */
  align-items: center; align-content: start;
  box-shadow: 0 10px 24px -22px var(--kpi, var(--brand2));
}
.dcc-kpi::before {
  content: ''; position: absolute; inset: 0 0 auto 0; height: 3px;
  background: var(--kpi, var(--brand2));
}
.dcc-kpi-ico {
  grid-row: 1 / span 2; font-style: normal; font-size: 17px; line-height: 1;
  width: 40px; height: 40px; border-radius: 11px; display: grid; place-items: center;
  color: var(--kpi, var(--brand2));
  background: color-mix(in srgb, var(--kpi, var(--brand2)) 16%, transparent);
}
.dcc-kpi b { font-size: 28px; color: var(--kpi, var(--ink)); }
.dcc-kpi-all   { --kpi: var(--brand2); }
.dcc-kpi-all b { color: var(--ink); }
.dcc-kpi-doing { --kpi: var(--doing); }
.dcc-kpi-stale { --kpi: var(--danger); }
.dcc-kpi-free  { --kpi: var(--done); }
.dcc-kpi-foot { grid-column: 1 / -1; display: flex; align-items: center; gap: 8px; margin-top: 9px; }
.dcc-kpi-bar {
  flex: 1; display: block; height: 5px; border-radius: 999px; overflow: hidden;
  background: color-mix(in srgb, var(--done) 18%, transparent);
}
.dcc-kpi-bar i { display: block; height: 100%; border-radius: inherit; background: var(--done); }
.dcc-kpi-pct { font-family: var(--mono); font-size: 11.5px; font-weight: 700; color: var(--done); }

/* The matrix card: a soft lift off the page, and a progress rail under the title
   so "88%" is seen as a length before it is read as a number. */
.dcc-card { box-shadow: inset 0 1px 0 var(--glass-hi), 0 18px 40px -26px var(--glass-shadow); }
.dcc-pct { color: var(--done); }
.dcc-prog {
  height: 6px; border-radius: 999px; margin: -2px 0 14px; overflow: hidden;
  background: color-mix(in srgb, var(--done) 15%, transparent);
}
.dcc-prog i {
  display: block; height: 100%; border-radius: inherit;
  background: linear-gradient(90deg, var(--brand2), var(--done));
}

/* The legend as chips, so it reads as a key rather than as a line of small print. */
.dcc-legend { gap: 6px; }
.dcc-lg {
  padding: 3px 10px; border-radius: 999px;
  background: color-mix(in srgb, var(--ink) 5%, transparent);
  border: 1px solid color-mix(in srgb, var(--ink) 8%, transparent);
}

/* Depth on the filled cells: a light fall from the status colour into its ground,
   instead of one flat tone. */
.dcc-cell.free  { background: linear-gradient(180deg, color-mix(in srgb, var(--done) 24%, var(--done-bg)), var(--done-bg)); }
.dcc-cell.doing { background: linear-gradient(180deg, color-mix(in srgb, var(--doing) 24%, var(--doing-bg)), var(--doing-bg)); }
.dcc-cell.stale { background: linear-gradient(180deg, color-mix(in srgb, var(--danger) 24%, var(--danger-bg)), var(--danger-bg)); }
.dcc-cell.defer { background: linear-gradient(180deg, color-mix(in srgb, var(--brand2) 26%, var(--accent-soft)), var(--accent-soft)); }

/* The type heads sit on a rule, so the head row reads as a header. */
.dcc-mx thead .dcc-colh { border-bottom: 2px solid var(--rule-2); }

/* Following a row across a wide table: pointing at it lights its label and its
   empty cells, so the eye does not slip onto the row below. */
.dcc-mx tbody tr:hover .dcc-rowh { color: var(--brand); }
.dcc-mx tbody tr:hover .dcc-cell.todo { background: color-mix(in srgb, var(--brand2) 10%, transparent); }

/* Taking an empty row back off the matrix. It replaces the row total, which on
   an empty row is only a dash — so the column keeps its width and nothing
   shifts. Deliberately quiet until the pointer is on it: a delete control at
   the end of every empty row would read as the loudest thing on the table. */
.dcc-rowdel {
  border: 0; background: none; cursor: pointer; padding: 2px 6px;
  border-radius: var(--r); line-height: 1;
  font-size: var(--fs-label); color: var(--ink-4);
  opacity: .45; transition: opacity .12s, color .12s, background .12s;
}
tr:hover .dcc-rowdel { opacity: 1; }
.dcc-rowdel:hover { color: var(--danger); background: var(--danger-bg); opacity: 1; }
.dcc-rowdel:disabled { opacity: .3; cursor: default; }

/* ---- one cell opened ---- */
.dcc-detail {
  margin-top: 12px; padding: 10px 12px;
  border: 1px solid var(--rule-2); border-radius: var(--r); background: var(--head);
}
.dcc-detail-h { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; font-size: 13px; }
.dcc-detail-h .dcc-clear { margin-left: auto; }
.dcc-pkg { padding: 8px 0; border-top: 1px solid var(--rule); }
.dcc-pkg:first-of-type { border-top: 0; }
.dcc-pkg-h { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.dcc-pkg-name { font-size: var(--fs-meta); color: var(--ink-2); overflow-wrap: anywhere; }
.dcc-chain { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin: 7px 0; }
.dcc-step {
  display: inline-flex; flex-direction: column; gap: 1px; padding: 4px 9px;
  border: 1px solid var(--rule-2); border-radius: var(--r);
  font-family: var(--mono); font-size: 11px; background: var(--card);
}
.dcc-step.done { border-color: var(--done); color: var(--done); }
.dcc-step i { font-style: normal; opacity: .85; }
.dcc-step u { text-decoration: none; font-size: 10px; opacity: .7; }
.dcc-arrow { color: var(--ink-4); }
.dcc-types { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 4px; }
.dcc-types-l {
  font-family: var(--mono); font-size: var(--fs-label); letter-spacing: var(--ls-label);
  text-transform: uppercase; color: var(--ink-3);
}
.dcc-chk {
  display: inline-flex; align-items: center; gap: 4px; cursor: pointer;
  padding: 2px 8px; border-radius: 999px; border: 1px solid var(--rule-2);
  font-size: 11.5px; background: var(--card);
}
.dcc-chk.on { border-color: var(--brand2); color: var(--brand2); font-weight: 600; }
.dcc-chk input { margin: 0; }
.dcc-mini-link {
  border: 0; background: transparent; color: var(--brand2); cursor: pointer;
  font: inherit; font-size: var(--fs-label); text-decoration: underline; padding: 0 4px;
}

/* ---- the admin drawer ---- */
.dcc-admin {
  background: var(--card); border: 1px solid var(--rule);
  border-radius: var(--r); padding: 8px 12px; margin-bottom: 12px;
}
.dcc-admin > summary { cursor: pointer; font-weight: 700; font-size: 13px; }
.dcc-tw { overflow-x: auto; margin-top: 8px; }
.dcc-table { width: 100%; border-collapse: collapse; font-size: var(--fs-meta); }
.dcc-table th {
  text-align: left; padding: 6px 8px; border-bottom: 1px solid var(--rule);
  font-family: var(--mono); font-size: var(--fs-label); letter-spacing: var(--ls-label);
  text-transform: uppercase; color: var(--ink-3); white-space: nowrap;
}
.dcc-table td { padding: 5px 8px; border-bottom: 1px solid var(--rule); }
.dcc-cellname, .dcc-file {
  max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dcc-del {
  border: 0; background: transparent; color: var(--ink-4); cursor: pointer;
  font-size: 12px; padding: 2px 6px; border-radius: var(--r);
}
.dcc-del:hover { background: var(--danger-bg); color: var(--danger); }

/* ---- empty state ---- */
.dcc-empty {
  border: 2px dashed var(--rule-2); border-radius: var(--r);
  padding: 40px 20px; text-align: center; color: var(--ink-3);
}
.dcc-empty.drag { border-color: var(--brand2); background: var(--accent-soft); }
.dcc-empty-title { font-weight: 700; font-size: 15px; color: var(--ink); margin: 6px 0; }
.dcc-retry { margin-top: 12px; }

/* ---- this tab's own modal ----
   A separate ELEMENT from #cl-modal, which four other dialogs share. Same look,
   its own backdrop listener, bound once. */
.dcc-modal {
  position: fixed; inset: 0; z-index: 100;
  background: rgba(10, 15, 20, .5);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  display: flex; align-items: center; justify-content: center; padding: 20px;
}
.dcc-modal[hidden] { display: none; }
.dcc-modal-box {
  background: var(--card-solid); border: 1px solid var(--glass-brd);
  border-radius: var(--r); width: 100%; max-width: 520px;
  max-height: calc(86vh / var(--ui-zoom));
  display: flex; flex-direction: column; overflow: hidden;
  box-shadow: 0 28px 70px -20px var(--glass-shadow);
}
.dcc-modal-h {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 18px; border-bottom: 1px solid var(--rule);
  font-weight: 700; font-size: 14px;
}
.dcc-modal-x { border: 0; background: transparent; cursor: pointer; color: var(--ink-3); font-size: 15px; }
.dcc-modal-body { padding: 16px 18px; overflow-y: auto; }
.dcc-modal-foot {
  display: flex; justify-content: flex-end; gap: 8px;
  padding: 12px 18px; border-top: 1px solid var(--rule);
}
.dcc-field {
  display: flex; flex-direction: column; gap: 4px; margin-bottom: 14px;
  font-size: var(--fs-meta); color: var(--ink-2);
}
.dcc-field input, .dcc-field select {
  padding: 7px 10px; border-radius: var(--r); border: 1px solid var(--rule-2);
  background: var(--card); color: var(--ink); font: inherit; font-size: 13px;
}
.dcc-field-hint { font-size: var(--fs-label); color: var(--ink-3); line-height: 1.55; }
.dcc-hint { font-size: var(--fs-meta); color: var(--ink-3); line-height: 1.6; margin: 0 0 14px; }
.dcc-opt { color: var(--ink-4); font-weight: 400; }

@media (max-width: 900px) {
  .dcc-prow { grid-template-columns: 72px 1fr 62px; }
  .dcc-pstatus { display: none; }
  .dcc-actions { margin-left: 0; }
}

/* Project and Block inside the cell detail. Marked apart from the Type row on
   purpose: ticking a Type changes what the screen shows, while changing one of
   these MOVES the reports themselves. The tint and the ⚠ in the label are the
   only warning before the confirm dialog. */
.dcc-moves { padding: 4px 6px; border-radius: var(--r); background: var(--doing-bg); }
.dcc-moves .dcc-types-l { color: var(--doing); }
.dcc-moves .dcc-field-hint { margin-left: 2px; }
.dcc-sel-inline { padding: 3px 8px; font-size: 12px; max-width: 160px; }

/* ---- the optional Unit level, stepped under its block ----
   A block nobody has subdivided stays one flush-left row, exactly as before the
   level existed: most projects never use it and must not pay for it in either
   rows or indentation. */
.dcc-rowh-group {
  color: var(--ink-2); font-weight: 700;
  border-bottom: 1px solid var(--rule-2);
}
.dcc-groupfill { border-bottom: 1px solid var(--rule-2); }
.dcc-rowh-unit { padding-left: 20px; font-weight: 600; color: var(--ink-2); }
.dcc-rowh-unit::before { content: '└ '; color: var(--ink-4); }
/* Something in the block still has no unit. Called out rather than hidden — it is
   the row that needs a person. */
.dcc-rowh-orphan { padding-left: 20px; font-weight: 400; color: var(--ink-4); font-style: italic; }
.dcc-rowh-orphan::before { content: '└ '; font-style: normal; }
.dcc-sel-unit { max-width: 160px; }

/* ---- one Rev in the journey, opened ----
   Every step is a button now: the chain is where somebody works out why a package
   seems to reach 'Free' more than once, and the answer is always in the file name.
   A package checked in two rounds carries two names — 'Block A-Wall Frame' in June,
   'Block A GF L1_1BED, 2BED-Wall Frame' in July — and both end in a Free Clash. */
.dcc-step { cursor: pointer; font: inherit; text-align: left; }
.dcc-step:hover { border-color: var(--ink-4); }
.dcc-step.open { border-color: var(--brand2); box-shadow: inset 0 0 0 1px var(--brand2); }
/* Named 'Free Clash' yet clashes are still open — usually the same file imported
   twice, once with the flag on. */
.dcc-step.odd { border-color: var(--danger); color: var(--danger); }
.dcc-step-detail {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 2px 0 8px; padding: 7px 10px;
  border: 1px solid var(--brand2); border-radius: var(--r); background: var(--card);
  font-size: var(--fs-meta);
}
.dcc-step-l {
  font-family: var(--mono); font-size: var(--fs-label); letter-spacing: var(--ls-label);
  text-transform: uppercase; color: var(--brand2); white-space: nowrap;
}
.dcc-step-detail code {
  font-family: var(--mono); font-size: 11px; color: var(--ink-2);
  background: var(--head); padding: 2px 7px; border-radius: var(--r);
  overflow-wrap: anywhere;
}
.dcc-step-who { color: var(--ink-3); white-space: nowrap; }
.dcc-step-detail .dcc-clear { margin-left: auto; }
/* A column that is a COMBINATION of types ('Wall Frame + Full Package'). Marked so
   it does not read as a single stage of work that the eye then looks for elsewhere. */
.dcc-colh.is-multi span { color: var(--ink-3); font-weight: 600; }

/* ---- the journey, split into rounds ----
   One line per package NAME. The package key is (project, block, frame type) and
   never the full name, so a scope that widens between revisions keeps the package
   together — at the cost of two separate rounds of work sharing one chain. Read
   flat, that looks like a package reaching Free twice for no reason; split by name
   it reads as two rounds, each ending clean. */
.dcc-rounds { display: flex; flex-direction: column; gap: 8px; margin: 7px 0; }
.dcc-round {
  border-left: 2px solid var(--rule-2); padding-left: 9px;
}
.dcc-round-h {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  font-size: var(--fs-meta); margin-bottom: 4px;
}
.dcc-round-h b { color: var(--ink); overflow-wrap: anywhere; }
/* A round line is titled with the DELIVERY FOLDER it came out of, minus the
   version words: '251001-DatVo-All-Type 2B_A Free Clash' reads as
   '251001-DatVo-All-Type 2B_A'. The folder is the thing that exists on the drive,
   and the per-round Block ticks sitting under this line rewrite what the parser
   made of it — so the line above them shows the source, not the reading. The
   block inside it is bold, because the block is the half being corrected. */
.dcc-round-src { color: var(--ink-2); overflow-wrap: anywhere; }
.dcc-round-n {
  font-family: var(--mono); font-size: var(--fs-label); letter-spacing: var(--ls-label);
  text-transform: uppercase; color: var(--ink-4); white-space: nowrap;
}
.dcc-round-span { font-family: var(--mono); font-size: var(--fs-label); color: var(--ink-4); white-space: nowrap; }
.dcc-round .dcc-chain { margin: 0; }

/* Project and Block live INSIDE a round, because they rewrite that round's reports
   and one package can hold more than one delivery — FPW1 keeps '3B_B WF' and
   '3B_D Wall Frame' in the same package, and a package-level control set both. */
/* One ROW per field, label left and values right (Dat, 10/09/2026).

   Project, Block and Type used to run together on one wrapping line. With
   eighteen frame types that is three lines of ticks and no edge between one
   field and the next — the label saying which is which ends up mid-line. A grid
   with a fixed label column gives every field its own line and lines the three
   labels up under each other. */
.dcc-moves {
  display: grid; grid-template-columns: max-content 1fr; gap: 4px 10px;
  align-items: baseline;
  margin-top: 6px; padding: 6px 8px; border-radius: var(--r);
  background: var(--doing-bg);
}
.dcc-move-row { display: contents; }
.dcc-move-l {
  font-family: var(--mono); font-size: var(--fs-label); letter-spacing: var(--ls-label);
  text-transform: uppercase; color: var(--doing); white-space: nowrap;
}
.dcc-move-val { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; min-width: 0; }

/* The two settings that belong to the PACKAGE, not to a round: same rows, same
   folded lists, but no amber and no ⚠ — nothing here rewrites a report. */
.dcc-moves-pkg { background: none; padding: 2px 0 0; border-top: 1px solid var(--rule-2); margin-top: 8px; }
.dcc-move-l-plain { color: var(--ink-4); }

/* What is picked now, so the row reads without opening anything. */
.dcc-move-now {
  font-size: var(--fs-meta); color: var(--ink); font-weight: 600;
  overflow-wrap: anywhere;
}

/* The long list, folded. <details> rather than a popup: the browser owns the
   open state, so there is none to keep, nothing to close on an outside click,
   and a re-render simply leaves it shut — which is what happens anyway, since
   every change in here reloads the statistics. */
.dcc-pick { position: relative; }
.dcc-pick-sum {
  list-style: none; cursor: pointer; user-select: none;
  font-size: var(--fs-label); color: var(--doing);
  border: 1px dashed var(--rule-2); border-radius: var(--r);
  padding: 1px 7px; white-space: nowrap;
}
.dcc-pick-sum::-webkit-details-marker { display: none; }
.dcc-pick-sum::after { content: ' ▾'; opacity: .7; }
.dcc-pick[open] > .dcc-pick-sum { border-style: solid; color: var(--ink); }
.dcc-pick[open] > .dcc-pick-sum::after { content: ' ▴'; }
.dcc-pick-sum:hover { border-color: var(--doing); color: var(--ink); }
.dcc-pick-list {
  display: flex; flex-wrap: wrap; gap: 4px;
  margin-top: 5px; padding: 6px; border-radius: var(--r);
  border: 1px solid var(--rule-2); background: var(--card);
  max-height: 168px; overflow-y: auto;
}

/* ===== Diary Clash Check: KPI row + Needs attention (Dat, 11/09/2026) =====
   Replaces the four .dcc-kpi tiles (their rules above are now unused). Every
   card is tinted by its state — a wash of the state colour from the top-left
   corner, a border mixed from it and the icon badge in it — and the same
   recipe colours the Needs-attention cards, so a red card means stalled
   wherever it sits. --dcc-violet is Deferred; it lives on these two blocks
   only, so no other tab sees it. */
.dcc-kr, .dcc-attn, .dcc-card { --dcc-violet: #5B5BD6; }
@media (prefers-color-scheme: dark) { .dcc-kr, .dcc-attn, .dcc-card { --dcc-violet: #9A9CF7; } }
:root[data-theme="light"] .dcc-kr, :root[data-theme="light"] .dcc-attn, :root[data-theme="light"] .dcc-card { --dcc-violet: #5B5BD6; }
:root[data-theme="dark"] .dcc-kr, :root[data-theme="dark"] .dcc-attn, :root[data-theme="dark"] .dcc-card { --dcc-violet: #9A9CF7; }

.dcc-kr {
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)) minmax(0, 1.3fr);
  gap: 12px; margin: 0 0 14px;
}
.dcc-kc {
  --k: var(--brand2);
  display: grid; grid-template-columns: 40px minmax(0, 1fr);
  grid-template-areas: "ico num" "ico lbl" "bar bar" "wk wk";
  column-gap: 12px; row-gap: 2px; align-content: start;
  padding: 14px 16px; border-radius: 10px; min-width: 0;
  background: linear-gradient(150deg, color-mix(in oklab, var(--k) 16%, var(--card-solid)) 0%, var(--card-solid) 72%);
  border: 1px solid color-mix(in oklab, var(--k) 30%, var(--rule));
}
.dcc-kc-doing { --k: var(--doing); }
.dcc-kc-stale { --k: var(--danger); }
.dcc-kc-free  { --k: var(--done); }
.dcc-kc-defer { --k: var(--dcc-violet); }
.dcc-kc-ring  { --k: var(--done); }
.dcc-kc-ico {
  grid-area: ico; width: 40px; height: 40px; border-radius: 10px; display: grid; place-items: center;
  color: var(--k); background: color-mix(in oklab, var(--k) 20%, transparent); font-style: normal;
}
.dcc-kc-ico svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.dcc-kc > b { grid-area: num; font-size: 26px; line-height: 1.05; font-weight: 700; color: var(--k); font-variant-numeric: tabular-nums; }
.dcc-kc-all > b { color: var(--ink); }
.dcc-kc > span:not([class]) { grid-area: lbl; font: 700 11px/1.3 var(--font); letter-spacing: .04em; text-transform: uppercase; color: var(--ink-2); }
/* Every card is as tall as the tallest (Free carries a bar): the empty bar row
   takes the slack, so "this week" sits on the same line in all five. */
.dcc-kc:not(.dcc-kc-ring) { grid-template-rows: auto auto 1fr auto; }
.dcc-kc-wk { align-self: end; }
.dcc-kc-bar { grid-area: bar; display: flex; gap: 8px; align-items: center; margin-top: 10px; }
.dcc-kc-bar em { flex: 1; height: 6px; border-radius: 3px; background: var(--rule); overflow: hidden; }
.dcc-kc-bar em i { display: block; height: 100%; border-radius: 3px; background: var(--done); }
.dcc-kc-bar small { font-size: 12px; font-weight: 700; color: var(--done); font-variant-numeric: tabular-nums; }
.dcc-kc-wk { grid-area: wk; margin-top: 10px; font-size: 12px; color: var(--ink-3); }
.dcc-kc-wk em { font-style: normal; font-weight: 700; margin-right: 2px; }
.dcc-kc-wk .up { color: var(--done); }
.dcc-kc-wk .dn { color: var(--danger); }
.dcc-kc-wk .flat { color: var(--ink-2); }

.dcc-kc-ring { grid-template-columns: auto minmax(0, 1fr); grid-template-areas: "t t" "ring of"; align-items: center; row-gap: 8px; }
.dcc-kc-t { grid-area: t; font: 700 11px/1.3 var(--font); letter-spacing: .08em; text-transform: uppercase; color: var(--ink-2); }
.dcc-ring { grid-area: ring; width: 72px; height: 72px; display: block; }
.dcc-ring .tr { fill: none; stroke: var(--rule); stroke-width: 8; }
.dcc-ring .pg { fill: none; stroke: var(--done); stroke-width: 8; stroke-linecap: round; }
.dcc-ring text { fill: var(--ink); font: 700 15px var(--font); }
.dcc-kc-of { grid-area: of; display: grid; }
.dcc-kc-of b { font-size: 18px; font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; }
.dcc-kc-of small { font-size: 12px; color: var(--ink-3); }

@media (max-width: 1200px) { .dcc-kr { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 640px) {
  .dcc-kr { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .dcc-kc-ring { grid-column: 1 / -1; }
}

.dcc-attn .dcc-card-h > span:first-child { display: inline-flex; gap: 8px; align-items: center; }
.dcc-attn-ico { display: inline-grid; font-style: normal; }
.dcc-attn-ico svg { width: 16px; height: 16px; fill: none; stroke: var(--danger); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.dcc-att-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 10px; padding: 12px 14px 14px; }
.dcc-att {
  --k: var(--danger);
  display: grid; grid-template-columns: 32px minmax(0, 1fr); grid-template-areas: "ico t" "ico s" "ico n";
  column-gap: 10px; row-gap: 1px; align-items: center; text-align: left;
  padding: 10px 12px; border-radius: 8px; cursor: pointer; font: inherit; color: var(--ink);
  background: linear-gradient(150deg, color-mix(in oklab, var(--k) 16%, var(--card-solid)) 0%, var(--card-solid) 75%);
  border: 1px solid color-mix(in oklab, var(--k) 32%, var(--rule));
  transition: transform .12s ease, border-color .12s ease;
}
.dcc-att:hover { border-color: var(--k); transform: translateY(-1px); }
.dcc-att:focus-visible { outline: 2px solid var(--k); outline-offset: 2px; }
.dcc-att-doing { --k: var(--doing); }
.dcc-att .dcc-kc-ico { grid-area: ico; width: 32px; height: 32px; border-radius: 8px; align-self: start; }
.dcc-att .dcc-kc-ico svg { width: 16px; height: 16px; }
.dcc-att b { grid-area: t; font: 700 12.5px var(--mono); overflow-wrap: anywhere; }
.dcc-att span { grid-area: s; font-size: 12px; font-weight: 600; color: var(--k); }
.dcc-att small { grid-area: n; font-size: 11.5px; color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dcc-att small:empty { display: none; }
.dcc-att-more { padding: 0 16px 14px; font-size: 12px; color: var(--ink-3); }
@media (prefers-reduced-motion: reduce) { .dcc-att { transition: none; } .dcc-att:hover { transform: none; } }

/* ===== Diary Clash Check: 🗑 Remove this Free (Dat, 11/09/2026) =====
   On the strip a clicked Free step opens, just before its ✕. Danger-tinted: it
   deletes a report, and a confirm names what the package falls back to. */
.dcc-step-detail .dcc-step-del { margin-left: auto; }
.dcc-step-detail .dcc-step-del + .dcc-clear { margin-left: 0; }
.dcc-step-del {
  height: 26px; padding: 0 10px; border-radius: var(--r); cursor: pointer; font: 600 12px var(--font);
  color: var(--danger); background: var(--danger-bg);
  border: 1px solid color-mix(in oklab, var(--danger) 35%, transparent);
}
.dcc-step-del:hover { border-color: var(--danger); }

/* ===== Diary Clash Check: Deferred = ON HOLD (Dat, 11/09/2026) =====
   A package somebody put on hold with ⏸ Defer. Violet, the colour the KPI row
   already gives Deferred, so a violet cell and the violet card mean one thing.
   Replaces the old brand-blue "free · deferred" look (that case is plain Free now). */
.dcc-tag.defer { background: color-mix(in srgb, var(--dcc-violet) 16%, transparent); color: var(--dcc-violet); }
.dcc-cell.defer {
  color: var(--dcc-violet);
  background: linear-gradient(180deg, color-mix(in srgb, var(--dcc-violet) 26%, var(--card-solid)), color-mix(in srgb, var(--dcc-violet) 10%, var(--card-solid)));
}
.dcc-lg.defer { color: var(--dcc-violet); }
.dcc-hold-btn {
  margin-left: auto; height: 26px; padding: 0 10px; border-radius: var(--r); cursor: pointer;
  font: 600 12px var(--font); color: var(--dcc-violet);
  background: color-mix(in srgb, var(--dcc-violet) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--dcc-violet) 40%, transparent);
}
.dcc-hold-btn:hover { border-color: var(--dcc-violet); }
.dcc-hold-btn.resume { color: var(--done); background: var(--done-bg); border-color: color-mix(in srgb, var(--done) 40%, transparent); }
.dcc-hold-btn.resume:hover { border-color: var(--done); }
.dcc-hold-note { font-size: 12px; color: var(--dcc-violet); }

/* ===== Diary Clash Check: ✓ Mark as free beside ⏸ Defer (Dat, 11/09/2026) =====
   Green, the Free colour; it takes the push to the right edge and Defer follows it.
   ▶ Resume goes neutral so it is not a second green button next to Free. */
.dcc-pfree-btn { color: var(--done); background: var(--done-bg); border-color: color-mix(in srgb, var(--done) 40%, transparent); }
.dcc-pfree-btn:hover { border-color: var(--done); }
.dcc-pfree-btn + .dcc-hold-btn { margin-left: 0; }
.dcc-hold-btn.resume { color: var(--ink); background: var(--card-solid); border-color: var(--rule-2); }
.dcc-hold-btn.resume:hover { border-color: var(--ink-3); }

/* ===== Diary Clash Check: KPI cards open their packages (Dat, 17/09/2026) =====
   Each card is a button now: a hover lift, a ring in its own colour while its
   list is open, and the list itself as a card under the row, its rows
   clickable. The list scrolls on its own so a long one does not push the
   matrix off the screen. */
.dcc-kc[role="button"] { cursor: pointer; transition: transform .12s ease, box-shadow .12s ease, border-color .12s ease; }
.dcc-kc[role="button"]:hover { transform: translateY(-1px); border-color: color-mix(in oklab, var(--k) 60%, var(--rule)); }
.dcc-kc[role="button"]:focus-visible { outline: 2px solid var(--k); outline-offset: 2px; }
.dcc-kc.is-on { border-color: var(--k); box-shadow: 0 0 0 1px var(--k), 0 8px 22px -14px var(--k); }
@media (prefers-reduced-motion: reduce) { .dcc-kc[role="button"] { transition: none; } .dcc-kc[role="button"]:hover { transform: none; } }
.dcc-klist .dcc-card-h { align-items: center; }
.dcc-klist .dcc-card-h .dcc-clear { margin-left: auto; }
.dcc-klist-wrap { max-height: 420px; overflow: auto; }
.dcc-klist-table thead th { position: sticky; top: 0; z-index: 1; background: var(--card-solid); }
.dcc-klist-row { cursor: pointer; }
.dcc-klist-row:hover td { background: var(--hover); }
.dcc-klist-row:focus-visible { outline: 2px solid var(--brand2); outline-offset: -2px; }
.dcc-klist-proj { font-family: var(--mono); font-weight: 700; white-space: nowrap; }
.dcc-klist-unit { color: var(--ink-3); }
.dcc-klist-name { color: var(--ink-2); }
.dcc-klist-when { color: var(--ink-3); white-space: nowrap; font-variant-numeric: tabular-nums; }

/* The issue card on the KPI screen: who raised and who closed, per month.
   `.num` right-aligns and uses tabular figures so the columns can be compared
   down the page rather than read one by one. */
.kpi-iss-from { font-size: var(--fs-meta); color: var(--ink-3); font-style: italic; }
.kpi-table td.num, .kpi-table th.num {
  text-align: right; font-family: var(--mono); font-variant-numeric: tabular-nums;
}

/* ============================================================
   Issues raised & closed
   ------------------------------------------------------------
   Read across a room in a review, not scanned down a page at a desk, so the
   figures carry more weight here than in the hours table above.

   The two measures are coloured — open amber, closed green — and the colour is
   NEVER the only carrier: every figure is printed, the columns are named, and
   the bar has a title. (A pie was the obvious reach for a two-part split and is
   the wrong one: exact values matter here, and an unlabelled colour-only slice
   is the accessibility failure the pattern is known for.)
   ============================================================ */
.kpi-iss-table td {
  font-size: var(--fs-lead);
  padding-top: 10px; padding-bottom: 10px;
}
.kpi-iss-table td.num { font-weight: 700; font-variant-numeric: tabular-nums; }
.kpi-iss-table td.num b { font-weight: 800; color: var(--ink); }

/* Amber for what is still open, green for what is finished — the same two the
   rest of the app uses for "doing" and "done", so a colour means one thing
   across the whole screen. */
.kpi-iss-table td.kpi-iss-open   { color: var(--doing); }
.kpi-iss-table td.kpi-iss-closed { color: var(--ok); }
/* A zero is an absence, not a result. At full strength the emptiest cell in the
   table is the one that catches the eye — so it steps back to the muted ink and
   drops the colour, which would otherwise say "amber: look here" about nothing. */
.kpi-iss-table td.num.zero { color: var(--ink-4); font-weight: 400; }

.kpi-iss-who { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.kpi-iss-name { font-weight: 600; color: var(--ink); }
/* The member the ACC login belongs to, when it is known. Secondary on purpose —
   the account is what the export says, the person is the translation. */
.kpi-iss-who .kpi-sub { font-size: var(--fs-meta); color: var(--ink-4); }

/* One mark, two readings: length = share of the month, cut = how much of this
   person's own work is still open. */
.kpi-iss-barh { width: 34%; }
.kpi-iss-barc { padding-right: 14px !important; }
.kpi-iss-bar {
  display: flex; height: 10px; border-radius: 999px; overflow: hidden;
  background: var(--rule); min-width: 10px;
}
.kpi-iss-bar i { display: block; height: 100%; }
.kpi-iss-bar i.o { background: var(--doing); }
.kpi-iss-bar i.c { background: var(--ok); }

/* The last line of the same list, not a footer bolted under it. */
.kpi-iss-sum td {
  border-top: 2px solid var(--rule-2); color: var(--ink-2);
  font-weight: 600; font-size: var(--fs-body);
}
.kpi-iss-sum .kpi-iss-who { color: var(--ink-3); letter-spacing: var(--ls-label); text-transform: uppercase;
  font-size: var(--fs-label); font-family: var(--mono); }

/* The three tiles above the table take the same two colours, so the headline
   figure and the column under it are visibly the same measure. */
.cl-kpi-n.kpi-iss-open   { color: var(--doing); }
.cl-kpi-n.kpi-iss-closed { color: var(--ok); }

@media (max-width: 720px) {
  /* The bar is the first thing to go: it is the one column whose information is
     also printed as a number beside it. */
  .kpi-iss-barh, .kpi-iss-barc { display: none; }
}

/* Said under the table rather than in a tooltip: a figure sitting on the wrong
   row, or missing from one, is the failure this note exists to prevent. */
.kpi-iss-note {
  padding: 8px 14px; font-size: var(--fs-meta); color: var(--ink-3);
  border-top: 1px solid var(--rule); line-height: 1.6;
}
.kpi-iss-note code {
  font-family: var(--mono); font-size: var(--fs-label);
  background: var(--bg); padding: 1px 5px; border-radius: 4px;
}

/* ===== Diary Clash Check — the ↩ Undo button (12/10/2026) =====
   One of the actions on the Month row, drawn like the others. Disabled it keeps
   its place rather than disappearing, so the row does not jump the moment a
   change is made. The small number is how many more steps are behind it. */
.dcc-undo-btn {
  font-variant-numeric: tabular-nums;
}
.dcc-undo-btn:disabled {
  opacity: .45;
  cursor: default;
  background: var(--card);
  border-color: var(--rule-2);
}
.dcc-undo-btn i {
  font-style: normal;
  font-size: 11px;
  font-weight: 600;
  color: var(--ink-3);
  background: var(--bg);
  border-radius: 999px;
  padding: 1px 6px;
  margin-left: 4px;
}

/* ===== Diary Clash Check — deleting a type (12/10/2026) =====
   ✕ on a column head, and 🗑 beside each type the dictionary learned here. Both
   stay quiet until the head (or the chip) is under the cursor, so a table of ten
   columns is not a row of ten delete buttons. */
.dcc-colh { position: relative; }
.dcc-colx {
  position: absolute; top: 0; right: 2px;
  border: 0; background: none; cursor: pointer; padding: 0 3px; line-height: 1;
  font-size: 11px; color: var(--ink-4); opacity: 0;
  transition: opacity .12s, color .12s;
}
.dcc-colh:hover .dcc-colx, .dcc-colx:focus-visible { opacity: .75; }
.dcc-colx:hover { color: var(--danger); opacity: 1; }
.dcc-colx:disabled { opacity: .3; cursor: default; }

.dcc-tchips { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; }
.dcc-tchip {
  display: inline-flex; align-items: center; gap: 3px;
  border: 1px solid var(--rule-2); border-radius: 999px;
  padding: 2px 4px 2px 9px; font-size: 11.5px; color: var(--ink-2);
  background: var(--card);
}
.dcc-tchip.is-builtin { padding-right: 9px; color: var(--ink-3); background: var(--bg); }
.dcc-tchip i { font-style: normal; font-size: 10px; color: var(--ink-4); text-transform: uppercase; }
.dcc-tchip-x {
  border: 0; background: none; cursor: pointer; line-height: 1;
  font-size: 11px; padding: 1px 3px; border-radius: 999px; opacity: .55;
  transition: opacity .12s, background .12s;
}
.dcc-tchip:hover .dcc-tchip-x { opacity: 1; }
.dcc-tchip-x:hover { background: var(--danger-bg); }
.dcc-tchip-x:disabled { opacity: .3; cursor: default; }

/* ===== Diary Clash Check — 🚫 Hide a package (13/10/2026) =====
   A hidden package is OFF the board by default. Under 👁 it comes back faint and
   dashed: on screen to be found and put back, not to be read as live work. */
.dcc-hidden-btn.on {
  border-color: var(--accent);
  color: var(--ink);
}
.dcc-mx .dcc-cell.is-hidden {
  opacity: .4;
  border-style: dashed;
}
.dcc-mx .dcc-cell.is-hidden:hover { opacity: .75; }
.dcc-pkg.is-hidden { opacity: .62; }
.dcc-pkg.is-hidden:hover, .dcc-pkg.is-hidden:focus-within { opacity: 1; }
.dcc-tag.hidden {
  background: var(--bg);
  color: var(--ink-3);
  border: 1px dashed var(--rule-2);
}
