/* Warp — the app shell.
   External by necessity, not by taste: nginx serves style-src 'self' with no
   'unsafe-inline', so an inline <style> or style="" attribute is refused by the
   browser and the page renders naked. Same reason login.css exists.

   The language continues the login page — dark ground, the warp thread in gold
   (structure), the weft in teal (what crosses it) — but denser. The login card
   is seen once; this is opened twenty times a day and has to behave like an
   instrument rather than a poster. */

:root {
  --bg:        #0e1116;
  --bg-raised: #151a22;
  --bg-sunk:   #0b0e12;
  --line:      #232a35;
  --line-soft: #1a2029;
  --ink:       #e6e9ef;
  --ink-dim:   #8b95a7;
  /* Lifted from #5d6675, which measured 3.26:1 on --bg and 3.01:1 on
     --bg-raised — below the 4.5:1 AA floor, and every use of it is 10-13px
     text, so none of it qualifies as "large". This value measures 4.95:1 and
     4.57:1. It carries the planner's unplaced REASONS and the assumed-estimate
     chip, which are load-bearing explanations, not decoration. */
  --ink-faint: #7a8394;
  --warp:      #d9a441;   /* the warp thread: the fixed structure */
  --weft:      #4a9d8f;   /* the weft: what crosses it, day by day */
  --danger:    #e0685f;
  --radius:    10px;

  --rail-w:    340px;
  --topbar-h:  52px;

  /* Without this the USER AGENT still paints light: white scrollbars in the
     rail and the panes, white spin buttons on all 21 capacity number inputs,
     light checkbox chrome. On a deliberately dark instrument that is the most
     visible cosmetic defect there is, and it is one declaration. */
  color-scheme: dark;
}

* { box-sizing: border-box; }

html, body { height: 100%; }

body.app {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 14px/1.5 ui-sans-serif, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* The warp: vertical threads under tension. Pure CSS, so nothing to load and
   nothing to leak. Fainter here than on the login page — it is background on a
   surface you stare at all day, not the hero. */
.warp-threads {
  position: fixed;
  inset: 0;
  background-image: repeating-linear-gradient(
    90deg,
    transparent 0 46px,
    rgba(217, 164, 65, 0.03) 46px 47px
  );
  pointer-events: none;
  z-index: 0;
}

/* ----------------------------------------------------------------- topbar */

.topbar {
  position: relative;
  z-index: 1;
  flex: 0 0 var(--topbar-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 0 18px;
  border-bottom: 1px solid var(--line);
  background: var(--bg-sunk);
}

.mark { display: flex; align-items: baseline; gap: 12px; min-width: 0; }

.mark-name {
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.015em;
}

.mark-tag {
  color: var(--ink-faint);
  font-size: 12px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.topbar-right { display: flex; align-items: center; gap: 12px; }

.who { color: var(--ink-dim); font-size: 12px; }

.ghost {
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--ink-dim);
  font: inherit;
  font-size: 12px;
  padding: 5px 10px;
  cursor: pointer;
}

.ghost:hover:not(:disabled) { color: var(--ink); border-color: var(--ink-faint); }

/* `Today` is disabled whenever you are already on today — the DEFAULT state —
   so an unguarded hover meant the home surface offered a pointer and a
   highlight on a control that does nothing, every day. */
.ghost:disabled { opacity: 0.45; cursor: default; }

/* ------------------------------------------------------------------ frame */

.frame {
  position: relative;
  z-index: 1;
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: var(--rail-w) 1fr;
  min-height: 0;
}

/* ------------------------------------------------------------------- rail */

.rail {
  border-right: 1px solid var(--line);
  background: var(--bg-raised);
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.rail-head {
  flex: 0 0 auto;
  padding: 12px 14px;
  border-bottom: 1px solid var(--line-soft);
}

.kind-toggle { display: flex; gap: 4px; }

.kind {
  flex: 1 1 0;
  padding: 6px 8px;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--ink-dim);
  font: inherit;
  font-size: 12px;
  cursor: pointer;
}

.kind:hover { color: var(--ink); }

.kind[aria-pressed="true"] {
  background: var(--bg-sunk);
  border-color: var(--warp);
  color: var(--ink);
}

.rail-scroll {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 10px 8px 28px;
}

.rail-status {
  padding: 6px 8px;
  color: var(--ink-faint);
  font-size: 12px;
  min-height: 1.2em;
}

/* ------------------------------------------------------------------- tree */

.tree { display: flex; flex-direction: column; }

.node { display: flex; flex-direction: column; }

.node-children { display: flex; flex-direction: column; }

.node.collapsed > .node-children { display: none; }

/* One row: a twisty, a label, and (on objectives) the chip. */
.row {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;
  padding: 4px 6px;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.row:hover { background: rgba(255, 255, 255, 0.035); }

/* Only rows that actually expand are buttons (see railRow). A leaf row must not
   advertise a pointer cursor for a click that does nothing. */
div.row { cursor: default; }

.twisty {
  flex: 0 0 14px;
  color: var(--ink-faint);
  font-size: 10px;
  line-height: 1;
  text-align: center;
  /* Reserved even when there is nothing to expand, so labels stay aligned
     and the tree does not shimmy as branches open. */
}

.row-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Objective — the row that carries the differentiator. */
.row-objective { padding: 7px 6px; }
.row-objective .row-label { font-weight: 600; letter-spacing: -0.005em; }


/* Project */
.row-project { padding-left: 20px; }
.row-project .row-label { color: var(--ink); font-size: 13px; }

/* Task — a leaf, so no twisty and no pointer affordance beyond the checkbox. */
.row-task { padding-left: 40px; cursor: default; }
.row-task .row-label { color: var(--ink-dim); font-size: 13px; }
.row-task.is-done .row-label { color: var(--ink-faint); text-decoration: line-through; }

/* A dropped task is DECIDED, like a done one — it must not render as an open
   item with a live checkbox offering to complete it. */
.row-task.is-dropped .row-label { color: var(--ink-faint); text-decoration: line-through; opacity: 0.7; }
.row-task.is-dropped .tick { display: none; }

.tick {
  flex: 0 0 14px;
  width: 14px;
  height: 14px;
  margin: 0;
  accent-color: var(--weft);
  cursor: pointer;
}

/* ------------------------------------------------------------------- chip */

/* Two numbers, NEVER blended: velocity ("am I moving?") and status ("am I
   behind?") answer different questions, and collapsing them destroys exactly
   the signal this product sells. They sit in one chip but stay legibly two. */
/* TWO ALIGNED COLUMNS, not a pill.
   The pill packaged velocity and status as one object, which is exactly what
   they are not: they answer different questions and the product's whole claim
   is that they never blend. As fixed-width columns they line up down the rail,
   so the velocity column can be read on its own without reading the names, and
   the status column becomes a colour you scan rather than a badge you parse. */
.chip {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: baseline;
  gap: 10px;
  white-space: nowrap;
}

.chip-velocity {
  width: 30px;
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-size: 13px;
  color: var(--ink);
}

/* Small, letterspaced and upper-case: at this size the WORD is read as a
   label and the COLOUR carries the meaning, which is what lets the column be
   scanned. Fixed width so the right edge never ragged. */
.chip-status {
  width: 72px;
  text-align: right;
  font-size: 9px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* Only the STATUS word takes the colour now. Colouring the velocity figure
   too would tie the two numbers together visually on the one surface built to
   keep them apart — and a red 0.0 reads as "this number is bad", when the
   number is simply a fact. */
.chip-on_track  .chip-status { color: var(--weft); }
.chip-at_risk   .chip-status { color: var(--warp); }
.chip-off_track .chip-status { color: var(--danger); }

/* PALE, never red. The scoring model absorbs rather than punishes — an
   objective with no evidence yet has not failed, it has not started, and
   colouring it like a failure would make every new objective read as a
   reproach on the day you create it. */
.chip-no_evidence .chip-velocity,
.chip-no_evidence .chip-status { color: var(--ink-faint); }

/* CLOSED objectives. `done` borrows the weft — it is an outcome, and the one
   status on the rail that should read as a good one. `dropped` is PALE for the
   same reason no_evidence is: it is a decision, not a failure, and it must
   never borrow the danger colour for having been decided. */
.chip-done .chip-status { color: var(--weft); }
.chip-dropped .chip-velocity,
.chip-dropped .chip-status { color: var(--ink-faint); }

/* Consistency: the third derived number, deliberately quiet. A meter, not a
   streak — it decays and recovers and never resets to zero. */
.meter {
  flex: 0 0 30px;
  height: 3px;
  border-radius: 2px;
  background: var(--line-soft);
  overflow: hidden;
}

/* Eleven discrete widths rather than an inline style. See railMeter(). */
.meter-fill { height: 100%; background: var(--weft); border-radius: 2px; }
.meter-fill.lvl-0  { width: 0; }
.meter-fill.lvl-1  { width: 10%; }
.meter-fill.lvl-2  { width: 20%; }
.meter-fill.lvl-3  { width: 30%; }
.meter-fill.lvl-4  { width: 40%; }
.meter-fill.lvl-5  { width: 50%; }
.meter-fill.lvl-6  { width: 60%; }
.meter-fill.lvl-7  { width: 70%; }
.meter-fill.lvl-8  { width: 80%; }
.meter-fill.lvl-9  { width: 90%; }
.meter-fill.lvl-10 { width: 100%; }

.meter-empty { visibility: hidden; }

/* ------------------------------------------------------------ inline create */

/* Type and enter. No modal anywhere in the rail: a dialog to add a task is how
   a planner becomes something you avoid opening. */
.inline-new { display: block; margin: 2px 0 2px; }

.inline-new input {
  width: 100%;
  padding: 5px 8px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 6px;
  color: var(--ink);
  font: inherit;
  font-size: 13px;
}

.inline-new input::placeholder { color: var(--ink-faint); }

.inline-new input:hover { border-color: var(--line-soft); }

.inline-new input:focus {
  background: var(--bg-sunk);
  border-color: var(--line);
  outline: none;
}

.inline-new input:focus::placeholder { color: var(--ink-faint); }

.inline-new input:disabled { opacity: 0.5; }

.new-project input { margin-left: 20px; width: calc(100% - 20px); }
.new-task    input { margin-left: 40px; width: calc(100% - 40px); }

/* A grouping row: it names a set, it does not claim anything. Quieter than a
   scored objective and without a chip's worth of trailing space, so the eye
   reads it as a heading rather than as an objective whose score is missing. */
.row-container .row-label {
  color: var(--ink-dim);
  letter-spacing: 0.01em;
}

/* ------------------------------------------------------- area sections --- */

/* Life area as a permanent HEADING rather than something you switch to see.
   The balance between work and the rest of life is then legible without
   touching a control, which is the point of holding both in one system. */
.area-head {
  margin: 4px 0 8px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--warp);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--warp);
}

.area-head:not(:first-child) { margin-top: 22px; }

/* A PROJECT is a labelled rule. Four levels spend three indents before a task
   title starts; naming the project on a hairline separates it just as well and
   costs no level. */
.row-project {
  padding-left: 6px;
  gap: 8px;
}

.row-project .row-label {
  flex: 0 0 auto;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.rule-line {
  flex: 1 1 auto;
  height: 1px;
  background: var(--line-soft);
}

.row-project .twisty { font-size: 9px; }

/* Tasks keep their OBJECTIVE's indent — that is the level H2 buys back. */
.row-task { padding-left: 20px; }

/* ------------------------------------------------------------- slipped --- */

.slipped {
  margin-top: 22px;
  border-top: 1px solid var(--line-soft);
  padding-top: 12px;
}

.slipped[hidden] { display: none; }

/* Dashed, like every other "committed but not settled" texture in this app —
   the same visual grammar as an unhoured block. Deliberately NOT red: the work
   is owed, not failed, and a pile that shouts is the mechanic the register
   rejects. */
.row-slipped { border-left: 2px dashed var(--line); padding-left: 8px; }

.slipped-when {
  flex: 0 0 auto;
  font-size: 11px;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* -------------------------------------------------------- the day close --- */

.close-list { list-style: none; margin: 0 0 4px; padding: 0; }

.close-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border: 1px solid var(--line-soft);
  border-radius: 7px;
  margin-bottom: 6px;
}

/* The label takes the slack so the cadence, amount and last-seen columns stay
   aligned down the list — a ragged right edge here reads as a form, and this
   surface is trying very hard not to be one. */
.close-what { flex: 1 1 auto; cursor: pointer; }

.close-cadence {
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.close-value { width: 84px; }

.close-last {
  font-size: 11px;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Already logged: present, so you can see where you stand, and visibly not
   actionable, so the surface never invites you to log the same period twice. */
.close-kept { margin-top: 14px; }
.close-list-kept { opacity: 0.72; }

.close-row-kept {
  border-style: dashed;
  color: var(--ink-dim);
}

/* ---------------------------------------------------------- operations --- */

/* A zone, not a row. It sits BELOW the objectives it is not competing with,
   separated by the same rule as the unscheduled list, and it carries no chip:
   containers are not scored, and Operations is the bottom-most instance of
   that rule rather than a special case of it. */
.ops-zone {
  margin-top: 22px;
  border-top: 1px solid var(--line-soft);
  padding-top: 12px;
}

/* Chores read quieter than chosen work — but never faint enough to be missed,
   because unseen chores are what silently eat a day. */
.tree-ops .row-label { color: var(--ink-dim); }
.tree-ops .row-project { font-weight: 500; }

/* --------------------------------------------------------- unscheduled --- */

.unscheduled { margin-top: 22px; border-top: 1px solid var(--line-soft); padding-top: 12px; }

.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin: 0 6px 2px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.count { color: var(--ink-faint); font-variant-numeric: tabular-nums; }

.section-note {
  margin: 0 6px 8px;
  color: var(--ink-faint);
  font-size: 11px;
  line-height: 1.4;
}

.flat-list { list-style: none; margin: 0; padding: 0; }

.flat-list li {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 4px 6px;
  border-radius: 6px;
  color: var(--ink-dim);
  font-size: 13px;
}

.flat-list li:hover { background: rgba(255, 255, 255, 0.035); }

/* Hoisted out of `.flat-list`: rail task rows use `.where` too, and while the
   rule was scoped the annotation rendered larger and brighter than the title it
   annotates. `min-width:0` + `overflow-wrap` so a long unbroken title cannot
   push the row wider than the rail. */
.where {
  color: var(--ink-faint);
  font-size: 11px;
  min-width: 0;
  overflow-wrap: anywhere;
}

.empty { color: var(--ink-faint); font-size: 12px; padding: 4px 6px; }

/* ------------------------------------------------------------------ stage */

.stage { display: flex; flex-direction: column; min-width: 0; min-height: 0; }

.tabs {
  flex: 0 0 auto;
  display: flex;
  gap: 2px;
  padding: 10px 16px 0;
  border-bottom: 1px solid var(--line);
}

.tab {
  padding: 8px 14px 9px;
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  color: var(--ink-dim);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}

.tab:hover { color: var(--ink); }

.tab[aria-selected="true"] {
  color: var(--ink);
  border-bottom-color: var(--warp);
}

.panes { flex: 1 1 auto; overflow-y: auto; min-height: 0; }

.pane { display: none; padding: 28px 30px; }
.pane.is-active { display: block; }

/* Honest empty states: they name what will go here and which slice builds it,
   rather than mocking up a surface that does not exist. */
.placeholder { max-width: 560px; }

.placeholder h3 {
  margin: 0 0 10px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.placeholder p { margin: 0 0 10px; color: var(--ink-dim); }
.placeholder .muted { color: var(--ink-faint); font-size: 13px; }

code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
  color: var(--ink-dim);
}

/* ------------------------------------------------------------------ error */

.app-error {
  position: fixed;
  left: 50%;
  bottom: 18px;
  transform: translateX(-50%);
  z-index: 3;
  margin: 0;
  max-width: 620px;
  padding: 9px 14px;
  border: 1px solid rgba(224, 104, 95, 0.5);
  border-radius: 8px;
  background: var(--bg-raised);
  color: var(--danger);
  font-size: 13px;
}

.app-error:empty { display: none; }

/* ----------------------------------------------------------------- focus */

/* Never suppressed: on a keyboard-driven tree it is the only navigation cue. */
button:focus-visible,
input:focus-visible {
  outline: 2px solid var(--weft);
  outline-offset: 1px;
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* ==========================================================================
   The day pane (S3) and the capacity editor (S8)
   ========================================================================== */

.day-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}

.day-when h3 {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.day-when p { margin: 3px 0 0; font-size: 12px; font-variant-numeric: tabular-nums; }

.day-nav { display: flex; gap: 6px; flex-wrap: wrap; }

.day-section { margin-top: 26px; }

/* ---------------------------------------------------------------- load bar */

.day-load { max-width: 720px; }

/* Committed and scheduled stacked against total capacity. Widths come from
   pct-N classes: style="" is refused by the CSP, and the CSSOM's exemption is
   not worth betting a silently-empty bar on. */
.loadbar {
  display: flex;
  height: 10px;
  border-radius: 5px;
  background: var(--bg-sunk);
  border: 1px solid var(--line-soft);
  overflow: hidden;
}

.loadbar.is-over { border-color: rgba(224, 104, 95, 0.55); }

.seg { display: block; height: 100%; }
.seg-committed { background: var(--ink-faint); }
.seg-scheduled { background: var(--weft); }
.loadbar.is-over .seg-scheduled { background: var(--danger); }

.stats {
  display: flex;
  flex-wrap: wrap;
  gap: 22px;
  margin: 16px 0 4px;
}

.stat { display: flex; flex-direction: column; gap: 2px; }

.stat-label {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.stat-value {
  font-size: 17px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

.stat-over .stat-value { color: var(--danger); }

.finish { margin: 12px 0 0; font-size: 13px; }
.finish .muted { color: var(--ink-faint); }
.over { color: var(--danger); }

/* ------------------------------------------------------------------ splits */

.split { margin-top: 18px; }

.split-head {
  margin: 0 0 6px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.split-row { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }

.pill {
  display: inline-block;
  padding: 2px 9px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 11px;
  color: var(--ink-dim);
  white-space: nowrap;
}

/* Effort is the differentiating half of the capacity number — nobody in the
   studied market displays it — so deep work is the one that gets the colour. */
.effort-deep   { border-color: rgba(74, 157, 143, 0.5); color: var(--weft); }
.effort-normal { color: var(--ink); }
.effort-light  { color: var(--ink-dim); }
.effort-unspecified { border-style: dashed; color: var(--ink-faint); }

.area-work         { border-color: rgba(217, 164, 65, 0.45); color: var(--warp); }
.area-personal     { border-color: rgba(74, 157, 143, 0.45); color: var(--weft); }
/* Operations is neither warp nor weft: chores are real minutes that are not
   output, so they get their own neutral tone rather than borrowing work's. */
.area-operations   { border-color: var(--line); color: var(--ink-dim); }
.area-unattributed { border-style: dashed; color: var(--ink-faint); }

.budget-ok   { border-color: rgba(74, 157, 143, 0.45); color: var(--weft); }
.budget-over { border-color: rgba(217, 164, 65, 0.55); color: var(--warp); }

/* ------------------------------------------------------------------ blocks */

.blocks { list-style: none; margin: 0; padding: 0; }

.block {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 10px;
  border: 1px solid var(--line-soft);
  border-left: 3px solid var(--line);
  border-radius: 7px;
  margin-bottom: 6px;
  background: var(--bg-raised);
}

.block-task.area-work     { border-left-color: var(--warp); }
.block-task.area-personal { border-left-color: var(--weft); }
.block-task.area-operations { border-left-color: var(--line); }
.block-commitment         { border-left-style: dashed; }

.block-time {
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  color: var(--ink-dim);
  flex: 0 0 auto;
}

.block-title { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.block-len {
  font-variant-numeric: tabular-nums;
  font-size: 12px;
  color: var(--ink-faint);
  flex: 0 0 auto;
}

.tiny { padding: 3px 8px; font-size: 11px; }

/* ----------------------------------------------------------------- planner */

.candidate { gap: 8px; }

.flat-list .reason {
  color: var(--ink-faint);
  font-size: 11px;
  font-style: italic;
  min-width: 0;
  overflow-wrap: anywhere;
}

/* There was no bare `.muted` in this file — only `.placeholder .muted` and
   `.finish .muted` — so the day subheading, the two status lines, the capacity
   save status and the "Nothing scheduled." spans all rendered at FULL ink.
   The whole dense-instrument look depends on that hierarchy existing. */
.muted { color: var(--ink-dim); }
.flat-list .assumed { border-bottom: 1px dashed var(--ink-faint); }

.primary {
  margin-top: 12px;
  padding: 8px 14px;
  background: var(--warp);
  border: 0;
  border-radius: 7px;
  color: #17130a;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}

.primary:hover:not(:disabled) { filter: brightness(1.07); }
.primary:disabled { opacity: 0.45; cursor: default; }

.unplaced {
  margin-top: 14px;
  padding: 12px 14px;
  border: 1px solid rgba(217, 164, 65, 0.4);
  border-radius: 8px;
  background: var(--bg-raised);
}

.ok-note { margin: 12px 0 0; color: var(--weft); font-size: 13px; }

/* --------------------------------------------------------------- slideover */

.slideover {
  position: fixed;
  top: var(--topbar-h);
  right: 0;
  bottom: 0;
  width: min(520px, 100%);
  z-index: 2;
  overflow-y: auto;
  padding: 20px 22px 28px;
  border-left: 1px solid var(--line);
  background: var(--bg-raised);
}

.slideover[hidden] { display: none; }

.slideover-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 6px;
}

.slideover-head h4 { margin: 0; font-size: 15px; font-weight: 600; }

.slideover-foot { display: flex; align-items: center; gap: 12px; margin-top: 18px; }

.cap-grid { display: flex; flex-direction: column; gap: 10px; margin-top: 14px; }

.cap-row {
  display: grid;
  grid-template-columns: 92px repeat(3, 1fr);
  gap: 8px;
  align-items: end;
}

.cap-day { font-size: 12px; color: var(--ink-dim); padding-bottom: 8px; }

/* `position: relative` is here rather than in a second `.cap-field` block
   further down: it is the containing block for the visually-hidden labels on
   rows 2-7, and two rules for one selector is a trap for the next editor. */
.cap-field { display: flex; flex-direction: column; gap: 3px; position: relative; }

.cap-label {
  font-size: 10px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.cap-field input {
  width: 100%;
  padding: 6px 8px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--ink);
  font: inherit;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

/* Only the day column carries its label on the first row; repeating "Work /
   Personal / Deep budget" seven times is noise, but they must still exist for
   screen readers, so they are hidden visually rather than removed. */
.cap-row:not(:first-child) .cap-label {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}


/* pct-N widths for the load bar. Discrete classes, not inline styles. */
.seg.pct-0 { width: 0%; }
.seg.pct-1 { width: 1%; }
.seg.pct-2 { width: 2%; }
.seg.pct-3 { width: 3%; }
.seg.pct-4 { width: 4%; }
.seg.pct-5 { width: 5%; }
.seg.pct-6 { width: 6%; }
.seg.pct-7 { width: 7%; }
.seg.pct-8 { width: 8%; }
.seg.pct-9 { width: 9%; }
.seg.pct-10 { width: 10%; }
.seg.pct-11 { width: 11%; }
.seg.pct-12 { width: 12%; }
.seg.pct-13 { width: 13%; }
.seg.pct-14 { width: 14%; }
.seg.pct-15 { width: 15%; }
.seg.pct-16 { width: 16%; }
.seg.pct-17 { width: 17%; }
.seg.pct-18 { width: 18%; }
.seg.pct-19 { width: 19%; }
.seg.pct-20 { width: 20%; }
.seg.pct-21 { width: 21%; }
.seg.pct-22 { width: 22%; }
.seg.pct-23 { width: 23%; }
.seg.pct-24 { width: 24%; }
.seg.pct-25 { width: 25%; }
.seg.pct-26 { width: 26%; }
.seg.pct-27 { width: 27%; }
.seg.pct-28 { width: 28%; }
.seg.pct-29 { width: 29%; }
.seg.pct-30 { width: 30%; }
.seg.pct-31 { width: 31%; }
.seg.pct-32 { width: 32%; }
.seg.pct-33 { width: 33%; }
.seg.pct-34 { width: 34%; }
.seg.pct-35 { width: 35%; }
.seg.pct-36 { width: 36%; }
.seg.pct-37 { width: 37%; }
.seg.pct-38 { width: 38%; }
.seg.pct-39 { width: 39%; }
.seg.pct-40 { width: 40%; }
.seg.pct-41 { width: 41%; }
.seg.pct-42 { width: 42%; }
.seg.pct-43 { width: 43%; }
.seg.pct-44 { width: 44%; }
.seg.pct-45 { width: 45%; }
.seg.pct-46 { width: 46%; }
.seg.pct-47 { width: 47%; }
.seg.pct-48 { width: 48%; }
.seg.pct-49 { width: 49%; }
.seg.pct-50 { width: 50%; }
.seg.pct-51 { width: 51%; }
.seg.pct-52 { width: 52%; }
.seg.pct-53 { width: 53%; }
.seg.pct-54 { width: 54%; }
.seg.pct-55 { width: 55%; }
.seg.pct-56 { width: 56%; }
.seg.pct-57 { width: 57%; }
.seg.pct-58 { width: 58%; }
.seg.pct-59 { width: 59%; }
.seg.pct-60 { width: 60%; }
.seg.pct-61 { width: 61%; }
.seg.pct-62 { width: 62%; }
.seg.pct-63 { width: 63%; }
.seg.pct-64 { width: 64%; }
.seg.pct-65 { width: 65%; }
.seg.pct-66 { width: 66%; }
.seg.pct-67 { width: 67%; }
.seg.pct-68 { width: 68%; }
.seg.pct-69 { width: 69%; }
.seg.pct-70 { width: 70%; }
.seg.pct-71 { width: 71%; }
.seg.pct-72 { width: 72%; }
.seg.pct-73 { width: 73%; }
.seg.pct-74 { width: 74%; }
.seg.pct-75 { width: 75%; }
.seg.pct-76 { width: 76%; }
.seg.pct-77 { width: 77%; }
.seg.pct-78 { width: 78%; }
.seg.pct-79 { width: 79%; }
.seg.pct-80 { width: 80%; }
.seg.pct-81 { width: 81%; }
.seg.pct-82 { width: 82%; }
.seg.pct-83 { width: 83%; }
.seg.pct-84 { width: 84%; }
.seg.pct-85 { width: 85%; }
.seg.pct-86 { width: 86%; }
.seg.pct-87 { width: 87%; }
.seg.pct-88 { width: 88%; }
.seg.pct-89 { width: 89%; }
.seg.pct-90 { width: 90%; }
.seg.pct-91 { width: 91%; }
.seg.pct-92 { width: 92%; }
.seg.pct-93 { width: 93%; }
.seg.pct-94 { width: 94%; }
.seg.pct-95 { width: 95%; }
.seg.pct-96 { width: 96%; }
.seg.pct-97 { width: 97%; }
.seg.pct-98 { width: 98%; }
.seg.pct-99 { width: 99%; }
.seg.pct-100 { width: 100%; }

/* ==========================================================================
   Visually hidden — exposed to assistive tech, absent from the layout.
   ========================================================================== */

/* The consistency meter's VALUE existed only as a fill width and a title
   tooltip: unreachable by keyboard, and contributing nothing to the row's
   accessible name. A tooltip is acceptable for a supplementary explanation;
   it is not acceptable as the only representation of a number. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ==========================================================================
   The week strip (S2). Seven day columns above the day pane.

   The visual argument of this whole surface: a SOLID segment is time with an
   hour behind it, and a HATCHED one is time with only a date behind it. The
   texture is not decoration — it is the difference between "14:00-15:00 on
   Tuesday" and "Tuesday, sometime", and a strip that drew them the same way
   would be claiming a decision you never made. Hue carries it too (gold, the
   warp thread, against the weft's teal) so it does not rest on texture alone,
   and every column's aria-label spells all three numbers out.
   ========================================================================== */

.strip {
  margin: 0 0 26px;
  padding-bottom: 22px;
  border-bottom: 1px solid var(--line-soft);
}

.strip-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 14px;
  margin-bottom: 10px;
}

.strip-head .split-head { margin: 0; }

.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 11px;
  color: var(--ink-faint);
}

.legend li { display: flex; align-items: center; gap: 5px; }

.swatch {
  width: 18px;
  height: 8px;
  border-radius: 2px;
  border: 1px solid var(--line);
}

#week-release { margin-left: auto; }

/* Announcements for an action with no cursor to follow. Reserved height, so
   arming a task does not shunt the seven columns down the page. */
.carry-status {
  min-height: 1.3em;
  margin: 0 0 8px;
  font-size: 12px;
  color: var(--warp);
}

/* ------------------------------------------------------------- the columns */

.week-cols {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.wcol {
  display: flex;
  flex-direction: column;
  gap: 7px;
  min-width: 0;
  padding: 9px 9px 11px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-raised);
}

/* Selected — the column the day pane below is showing. The pair has to read as
   one surface, or the strip is just a widget sitting above an unrelated pane. */
.wcol.is-selected {
  border-color: var(--warp);
  background: var(--bg-sunk);
}

.wcol.is-today .wcol-name { color: var(--ink); }

.wcol.is-over { border-color: rgba(224, 104, 95, 0.45); }

/* Armed: something is in hand and every column is a target. Dashed, because a
   target you may drop on is not the same thing as a target you have chosen. */
.week-cols.is-armed .wcol {
  border-style: dashed;
  border-color: var(--ink-faint);
}

.week-cols.is-armed .wcol.is-hovered,
.wcol.is-hovered {
  border-style: solid;
  border-color: var(--warp);
  background: var(--bg-sunk);
}

#week-release.is-hovered { border-color: var(--warp); color: var(--ink); }

/* --------------------------------------------------------- column controls */

.wcol-pick {
  display: flex;
  align-items: baseline;
  gap: 6px;
  width: 100%;
  padding: 0;
  background: transparent;
  border: 0;
  color: var(--ink-dim);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.wcol-pick:hover { color: var(--ink); }

.wcol-name {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.wcol-date {
  font-size: 15px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

/* Today's marker. A dot rather than a colour swap: the selected column already
   owns the accent, and two meanings on one property is how a legend gets
   written for something that should not need one. */
.wcol-today {
  width: 5px;
  height: 5px;
  margin-left: auto;
  border-radius: 50%;
  background: var(--warp);
  align-self: center;
}

/* ------------------------------------------------------------ the fill bar */

.wbar {
  display: flex;
  height: 8px;
  border-radius: 4px;
  background: var(--bg-sunk);
  border: 1px solid var(--line-soft);
  overflow: hidden;
}

.wcol.is-selected .wbar { background: var(--bg); }

/* Day-only minutes: gold, and HATCHED. See the note at the top of this
   section — the texture is the claim. */
.seg-planned {
  background-color: rgba(217, 164, 65, 0.28);
  background-image: repeating-linear-gradient(
    135deg,
    rgba(217, 164, 65, 0.85) 0 2px,
    transparent 2px 5px);
}

.wcol.is-over .wbar { border-color: rgba(224, 104, 95, 0.5); }

.wcol-num {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px;
  margin: 0;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

.wcol-load { color: var(--ink); font-weight: 600; }
.wcol-cap { color: var(--ink-faint); }
.wcol-over { width: 100%; color: var(--danger); }

/* ----------------------------------------------------------- column chips */

.wcol-tasks {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.wchip {
  display: flex;
  align-items: baseline;
  gap: 4px;
  min-width: 0;
  padding: 3px 5px;
  border-radius: 4px;
  border: 1px solid transparent;
  font-size: 11px;
  color: var(--ink-dim);
}

.wchip-title {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Solid ground: this one has an hour. */
.wchip-hour {
  background: var(--bg-sunk);
  border-color: var(--line-soft);
}

.wcol.is-selected .wchip-hour { background: var(--bg); }

.wchip-time {
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
  color: var(--ink-faint);
}

/* Dashed edge, no fill: a day was chosen, an hour was not. Same distinction
   the bar draws, in the same direction, so the two never argue. */
.wchip-planned {
  border-style: dashed;
  border-color: rgba(217, 164, 65, 0.5);
  color: var(--ink-dim);
}

.wchip-flag { flex: 0 0 auto; color: var(--danger); font-size: 12px; }

.wchip-more,
.wchip-empty { color: var(--ink-faint); font-size: 10px; padding-left: 2px; }

/* The life-area tint the day pane already uses, kept consistent here. */
.wchip.area-work { border-left: 2px solid var(--warp); }
.wchip.area-personal { border-left: 2px solid var(--weft); }
.wchip.area-operations { border-left: 2px solid var(--line); }

/* ======================================================= picking a task up */

/* The keyboard route to a commitment a drag makes. Sits at the end of a rail
   row, quiet until it is used. */
.plan-pick {
  flex: 0 0 auto;
  margin-left: auto;
  padding: 0 4px;
  background: transparent;
  border: 0;
  color: var(--ink-faint);
  font: inherit;
  font-size: 12px;
  line-height: 1;
  cursor: grab;
}

.plan-pick:hover { color: var(--warp); }

.plan-pick.is-carrying { color: var(--warp); }

.row-uncommitted { display: flex; align-items: baseline; gap: 6px; }

.row-task[draggable="true"],
.row-uncommitted[draggable="true"] { cursor: grab; }

.is-dragging { opacity: 0.45; }

/* ============================== the day pane's own no-hour list (S3 delta) */

.unhoured { margin-top: 18px; }

.unhoured .section-note { margin-top: 0; }

/* Same dashed language as the strip's chips, at the day pane's scale. */
.block-unhoured {
  border-style: dashed;
  border-color: rgba(217, 164, 65, 0.4);
}

.block-unhoured .block-time {
  color: var(--ink-faint);
  font-style: italic;
}

.stat-planned .stat-value { color: var(--warp); }

/* ------------------------------------------------------------- carried --- */
/* Work committed to a day that has PASSED. Shown beside the day's load and
   never added to it: counted, a week of slippage makes every day open red and
   "over-committed" stops meaning you chose too much. The backend keeps it out
   of every total; these rules keep it visually outside too. */

.loadrow { display: flex; align-items: center; gap: 7px; }

/* The bar keeps its own geometry and ENDS where it always ended — the gap is
   the claim, so the tail must never be a child of .loadbar. */
.loadrow .loadbar { flex: 1 1 auto; }

/* Fixed width on purpose: a tail scaled to its minutes would be measuring
   against a total this day does not have. Dashed and grey, matching
   .row-slipped in the rail — the work is owed, not failed. */
.loadtail {
  flex: 0 0 auto;
  width: 86px;
  height: 10px;
  border-radius: 5px;
  border: 1px dashed var(--line);
  background-image: repeating-linear-gradient(
    135deg,
    rgba(139, 149, 167, 0.30) 0 2px,
    transparent 2px 5px);
}

.tailcap {
  flex: 0 0 auto;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* The debt line sits in the finish line's register — same size, same margin
   rhythm — because it is the same kind of statement: a fact about the day you
   read once and act on, not a number you watch. */
.carried-line {
  margin: 8px 0 0;
  font-size: 13px;
  color: var(--ink-dim);
}

.carried-line .n {
  color: var(--ink);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.carried-line .when { color: var(--ink-faint); }

/* A candidate already committed to the day on screen — the one you most
   likely came here to give an hour to. */
.candidate.is-planned-here .row-label { color: var(--ink); }

.mark-planned { color: var(--warp); }

/* ==========================================================================
   Responsive. There was no width media query at all: the rail is a fixed
   340px grid track, so the stage — which has min-width:0 — absorbed every
   pixel lost. At 380px the stage track computes to about 39px, and because
   `body.app` sets overflow:hidden there is not even a horizontal-scroll
   escape hatch: the app is simply clipped and unreachable.
   ========================================================================== */

@media (max-width: 860px) {
  :root { --rail-w: 260px; }
  .pane { padding: 18px 16px; }
}

@media (max-width: 720px) {
  /* ~200px of unshrinkable content — time, length, effort pill, Remove —
     sits before the title gets a pixel, so the row overflows before the
     layout stacks. Wrap it instead. */
  .block { flex-wrap: wrap; row-gap: 4px; }
  .block-title { flex: 1 1 100%; order: -1; }
}

@media (max-width: 860px) {
  /* Seven columns of ~60px cannot carry a task title, so the chips go and the
     bar plus the number carry the week. Nothing is hidden that is not also
     one click away in the day pane below. */
  .week-cols { gap: 5px; }
  .wcol { padding: 7px 6px 9px; }
  .wcol-tasks { display: none; }
  .wcol-date { font-size: 13px; }
}

@media (max-width: 620px) {
  /* One column. Each region keeps its own scroll context, so the
     min-height:0 chain and body overflow:hidden both still hold. */
  .frame {
    grid-template-columns: 1fr;
    grid-template-rows: minmax(0, 42vh) minmax(0, 1fr);
  }
  .rail { border-right: 0; border-bottom: 1px solid var(--line); }
  .mark-tag { display: none; }
  .slideover { top: 0; width: 100%; }
  /* Below this the seven columns stop being readable at all. Two rows of
     three-and-four keeps every day reachable rather than clipping Sunday. */
  .week-cols { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .legend { display: none; }
}

@media (max-width: 400px) {
  .cap-row { grid-template-columns: 64px repeat(3, 1fr); gap: 6px; }
}
