* { box-sizing: border-box; margin: 0; }
/* Colour lives here and nowhere else, so a second theme is a second block of
   values rather than a second stylesheet. Names say the role, not the shade:
   --line is whatever a border is in this theme, light or dark. */
:root {
  color-scheme: light;
  --bg: #f4f2fb; --panel: #ffffff; --raise: #faf9fe; --hover: #f3f0ff; --chip: #ece7fb;
  --accent-soft: #f6f3ff; --accent-strong: #e9e1ff;
  --line: #ddd7ee; --line-soft: #efecf9; --line-strong: #e3ddf5;
  --ink: #17131f; --muted: #6f6a7d; --faint: #9a92ad;
  --brand: #7c5cff;
  --q1: #e5484d; --q2: #4f76ff; --q3: #d8a410; --q4: #8a8496;
  --red-ink: #b3262c; --red-bg: #fde5e6; --red-line: #e0868b;
  --red-on-dark: #ffb4b7; --red-bg-dark: #4a1d20;
  --green-ink: #2c7a39; --green-bg: #e7f5e9; --green-line: #bfe3c6;
  --amber-ink: #8a6d0d; --amber-bg: #fdf3d7; --amber-line: #e5c65e;
  --amber-on-dark: #ffe2a1; --amber-bg-dark: #4a3d1d;
  --blue-ink: #2b4bb8; --blue-bg: #e2ebff; --blue-line: #8aa4e8;
  --violet-ink: #4f3fa8; --violet-line: #b3a3ea;
  --shadow: rgba(23,19,31,.08); --shadow-lift: rgba(23,19,31,.26);
  /* The column is a surface like any other now, not a slab of dark: white
     against the board's lavender, with an edge to separate them. */
  --side-bg: #ffffff; --side-ink: #241f33; --side-line: #e4dff2;
  --side-hover: #f2eefc; --side-hover-strong: #e9e2fa; --side-field: #f7f5fc;
  --radius: 12px;
}

/* Dark. Written once and pointed at twice: by the toggle, and by the system
   setting for anyone who has not touched the toggle. The :not() is what lets a
   deliberate choice of Light win over a system that prefers dark. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { color-scheme: dark; }
}
:root[data-theme="dark"] { color-scheme: dark; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
  --bg: #12101f; --panel: #1b1730; --raise: #221d3a; --hover: #2b2350; --chip: #322a55;
  --accent-soft: #271f47; --accent-strong: #362b63;
  --line: #362f59; --line-soft: #262041; --line-strong: #453c6f;
  --ink: #ece9f8; --muted: #a79fc0; --faint: #7f7799;
  --brand: #8f72ff;
  --q1: #ff6b70; --q2: #7c9aff; --q3: #e8bd45; --q4: #9e97ae;
  --red-ink: #ff9ea1; --red-bg: #3a1b20; --red-line: #7c3b40;
  --red-on-dark: #ffb4b7; --red-bg-dark: #4a1d20;
  --green-ink: #7fd694; --green-bg: #16301f; --green-line: #33603f;
  --amber-ink: #f0c96a; --amber-bg: #3a3016; --amber-line: #6d5c2b;
  --amber-on-dark: #ffe2a1; --amber-bg-dark: #4a3d1d;
  --blue-ink: #9db4ff; --blue-bg: #1d2748; --blue-line: #415292;
  --violet-ink: #baa9ff; --violet-line: #5b4b9a;
  --shadow: rgba(0,0,0,.34); --shadow-lift: rgba(0,0,0,.55);
  --side-bg: #0f0c1e; --side-ink: #e9e5f8; --side-line: #332c58;
  --side-hover: rgba(233,229,248,.1); --side-hover-strong: rgba(233,229,248,.16); --side-field: #191430;
  }
}
:root[data-theme="dark"] {
  --bg: #12101f; --panel: #1b1730; --raise: #221d3a; --hover: #2b2350; --chip: #322a55;
  --accent-soft: #271f47; --accent-strong: #362b63;
  --line: #362f59; --line-soft: #262041; --line-strong: #453c6f;
  --ink: #ece9f8; --muted: #a79fc0; --faint: #7f7799;
  --brand: #8f72ff;
  --q1: #ff6b70; --q2: #7c9aff; --q3: #e8bd45; --q4: #9e97ae;
  --red-ink: #ff9ea1; --red-bg: #3a1b20; --red-line: #7c3b40;
  --red-on-dark: #ffb4b7; --red-bg-dark: #4a1d20;
  --green-ink: #7fd694; --green-bg: #16301f; --green-line: #33603f;
  --amber-ink: #f0c96a; --amber-bg: #3a3016; --amber-line: #6d5c2b;
  --amber-on-dark: #ffe2a1; --amber-bg-dark: #4a3d1d;
  --blue-ink: #9db4ff; --blue-bg: #1d2748; --blue-line: #415292;
  --violet-ink: #baa9ff; --violet-line: #5b4b9a;
  --shadow: rgba(0,0,0,.34); --shadow-lift: rgba(0,0,0,.55);
  --side-bg: #0f0c1e; --side-ink: #e9e5f8; --side-line: #332c58;
  --side-hover: rgba(233,229,248,.1); --side-hover-strong: rgba(233,229,248,.16); --side-field: #191430;
}

body { font-family: -apple-system, "Segoe UI", Roboto, sans-serif; background: var(--bg); color: var(--ink); }
.hidden { display: none !important; }

/* The page is a column of controls and a board beside it. The column is where
   everything you do to the board lives, so the board itself holds nothing but
   tasks — and there is room down there for the next thing that needs a home. */
#app { display: grid; grid-template-columns: var(--side, 248px) minmax(0, 1fr); min-height: 100vh; align-items: start; }
#sidebar { border-right: 1px solid var(--side-line); position: sticky; top: 0; z-index: 20; height: 100vh; overflow-y: auto; background: var(--side-bg); color: var(--side-ink); padding: 14px 12px; display: flex; flex-direction: column; gap: 4px; }
#content { min-width: 0; padding-top: 4px; }

.side-head { display: flex; align-items: center; gap: 8px; padding: 2px 6px 10px; }
.side-toggle { margin-left: auto; background: transparent; border: 0; color: var(--side-ink); font-size: 15px; line-height: 1; padding: 5px 7px; border-radius: 7px; cursor: pointer; opacity: .75; }
.side-toggle:hover { background: var(--side-hover-strong); opacity: 1; }

/* Whose board this is, at the top, the way an account always is. */
.side-who { display: flex; align-items: center; gap: 9px; padding: 4px 6px 10px; min-width: 0; }
.side-face { flex: 0 0 auto; }
.side-face .avatar { width: 28px; height: 28px; font-size: 11px; }
.side-who-body { min-width: 0; flex: 1; }
.side-who .gm-field { display: flex; flex-direction: column; align-items: stretch; gap: 2px; font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em; opacity: .6; }
.side-who select { width: 100%; background: var(--side-hover); color: var(--side-ink); border: 1px solid var(--side-line); border-radius: 7px; padding: 5px 8px; font-size: 13px; font-weight: 600; cursor: pointer; }
.side-who .gm-name { font-size: 14px; font-weight: 700; }

/* The one button on this column that makes something, so it is the one that
   is filled in rather than outlined. */
.side-add { display: flex; align-items: center; gap: 9px; width: 100%; background: var(--brand); color: white; border: 0; border-radius: 9px; padding: 9px 11px; font: inherit; font-size: 13.5px; font-weight: 600; cursor: pointer; margin-bottom: 8px; }
.side-add:hover { filter: brightness(1.08); }
.side-add-plus { font-size: 17px; line-height: 1; width: 18px; text-align: center; }

.side-search { margin-bottom: 10px; }
.side-search .search-field { width: 100%; }

/* Every row on this column is the same row: an icon, a name, and the whole
   width to click. A view, a filter and Refresh all read the same way. */
.side-nav { display: flex; flex-direction: column; gap: 1px; }
.side-item { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; background: transparent; border: 0; color: var(--side-ink); font: inherit; font-size: 13.5px; padding: 8px 10px; border-radius: 8px; cursor: pointer; }
.side-item:hover { background: var(--side-hover); }
.side-item.active { background: var(--brand); color: white; font-weight: 600; }
.side-icon { flex: 0 0 auto; width: 18px; text-align: center; font-size: 14px; opacity: .85; }
.side-item.active .side-icon { opacity: 1; }

.side-block { margin-top: 14px; display: flex; flex-direction: column; gap: 1px; }
.side-title { font-size: 10.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; opacity: .45; padding: 0 10px 6px; }

.side-foot { margin-top: auto; padding-top: 14px; display: flex; flex-direction: column; gap: 1px; }

/* A <details> in this column is a row like any other, and its panel opens over
   the board rather than pushing the rows below it down the page. */
#sidebar details > summary { display: flex; align-items: center; gap: 10px; width: 100%; background: transparent; border: 0; color: var(--side-ink); font: inherit; font-size: 13.5px; padding: 8px 10px; border-radius: 8px; cursor: pointer; list-style: none; }
#sidebar details > summary::-webkit-details-marker { display: none; }
#sidebar details > summary::after { content: '›'; margin-left: auto; opacity: .5; transform: rotate(90deg); }
#sidebar details[open] > summary::after { transform: rotate(-90deg); }
#sidebar details > summary:hover { background: var(--side-hover); }
#sidebar details.active > summary, #sidebar details[open] > summary { background: var(--side-hover-strong); }
#sidebar details > .menu-options { position: static; min-width: 0; width: 100%; margin: 2px 0 4px; padding: 4px 0 4px 12px; background: transparent; color: var(--side-ink); box-shadow: none; border-radius: 0; border-left: 1px solid var(--side-line); display: flex; flex-direction: column; gap: 1px; }
#sidebar .menu-options button { color: var(--side-ink); font-size: 13px; padding: 7px 10px; border-radius: 7px; }
#sidebar .menu-options button:hover { background: var(--side-hover-strong); }
#sidebar .menu-options button.danger { color: var(--red-ink); }
#sidebar .filter-options-row { flex-direction: column; align-items: stretch; gap: 1px; }
#sidebar .filter-menu > summary { border: 0; border-radius: 7px; background: transparent; color: var(--side-ink); font-size: 13px; padding: 7px 10px; white-space: normal; }
#sidebar .filter-menu > summary::after { content: '›'; margin-left: auto; opacity: .5; transform: rotate(90deg); }
#sidebar .filter-menu[open] > summary::after { transform: rotate(-90deg); }
#sidebar .filter-menu.active > summary { background: var(--brand); color: white; }
#sidebar .filter-options { position: static; min-width: 0; width: 100%; background: transparent; color: var(--side-ink); box-shadow: none; border-radius: 0; margin: 1px 0 3px; padding: 2px 0 2px 12px; border-left: 1px solid var(--side-line); display: flex; flex-direction: column; gap: 1px; max-height: 220px; overflow-y: auto; }
#sidebar .filter-options label { font-size: 12.5px; padding: 4px 8px; }
#sidebar .filter-options label:hover { background: var(--side-hover); }
#sidebar .filter-options-row .ghost { border-color: var(--side-line); color: var(--side-ink); background: transparent; margin-top: 4px; }

/* Folded, the column keeps its icons and gives the width back to the board. */
#app.is-folded { --side: 60px; }
#app.is-folded .side-label, #app.is-folded .side-search, #app.is-folded .side-title,
#app.is-folded .side-who-body, #app.is-folded #counts { display: none; }
#app.is-folded #sidebar { padding: 14px 8px; align-items: center; }
#app.is-folded .side-item, #app.is-folded .side-add { justify-content: center; padding-left: 0; padding-right: 0; gap: 0; }
#app.is-folded .side-head { padding-bottom: 6px; }
#app.is-folded .side-who { justify-content: center; padding-left: 0; padding-right: 0; }

/* Narrow screens have no width to give a column, so it becomes a strip again. */
@media (max-width: 860px) {
  #app { grid-template-columns: minmax(0, 1fr); }
  #sidebar { position: static; height: auto; flex-direction: row; flex-wrap: wrap; align-items: center; gap: 8px; }
  .side-nav, .side-block, .side-foot { flex-direction: row; flex-wrap: wrap; margin: 0; }
  .side-foot { padding-top: 0; }
  .side-title, .side-head { display: none; }
  .side-add, .side-search { margin: 0; width: auto; }
}

.brand { font-size: 13px; font-weight: 700; letter-spacing: .02em; white-space: nowrap; }
.dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--brand); margin-right: 6px; }
.gm-field { display: inline-flex; gap: 6px; align-items: center; font-size: 12px; opacity: .85; }
.gm-name { font-size: 13px; font-weight: 600; opacity: .9; }

/* Typing is the fastest way to find one task among a hundred, so the box sits
   in the toolbar rather than behind anything. */
.search-field { position: relative; display: inline-flex; align-items: center; flex: 1 1 200px; max-width: 340px; }
#search-input { width: 100%; padding: 7px 34px 7px 12px; border-radius: 999px; border: 1px solid var(--side-line); background: var(--side-field); color: var(--side-ink); font-size: 13px; }
#search-input::placeholder { color: var(--faint); }
#search-input:focus { outline: none; border-color: var(--brand); }
#search-input::-webkit-search-cancel-button { display: none; }
.search-key { position: absolute; right: 12px; font-size: 11px; color: var(--faint); border: 1px solid var(--side-line); border-radius: 4px; padding: 0 5px; pointer-events: none; }
#search-input:focus ~ .search-key, .search-field:not(:has(#search-clear.hidden)) .search-key { display: none; }
#search-clear { position: absolute; right: 8px; background: transparent; border: none; color: var(--faint); font-size: 16px; line-height: 1; padding: 2px 6px; cursor: pointer; }
#search-clear:hover { color: white; }

/* One dropdown pattern, used by "More" and by "Filters". */
.menu { position: relative; }
.menu > summary { list-style: none; cursor: pointer; white-space: nowrap; }
.menu > summary::-webkit-details-marker { display: none; }
.menu > summary::after { content: " \25BE"; opacity: .6; }
.menu-options { position: absolute; z-index: 30; top: calc(100% + 6px); right: 0; min-width: 210px; background: var(--panel); color: var(--ink); border-radius: 10px; padding: 6px; box-shadow: 0 8px 26px var(--shadow-lift); display: grid; gap: 2px; }
.menu-options button { width: 100%; text-align: left; background: none; border: none; color: var(--ink); font-size: 13px; padding: 8px 10px; border-radius: 6px; cursor: pointer; }
.menu-options button:hover { background: var(--hover); }
.menu-options button.danger { color: var(--red-ink); }

#filter-panel > summary { padding: 5px 12px; border: 1px solid var(--side-line); border-radius: 999px; font-size: 12px; }
#filter-panel.active > summary { background: var(--brand); border-color: var(--brand); color: white; }
/* The panel keeps the four menus on one line and opens over the board, so the
   page does not jump every time it is opened. */
.filter-options-row { left: 0; right: auto; display: flex; gap: 8px; flex-wrap: wrap; align-items: center; min-width: 0; overflow: visible; }
.filter-options-row .ghost { border-color: var(--line); color: var(--muted); }
#counts { font-size: 12px; opacity: .8; margin-left: auto; }
#warning { background: var(--red-bg-dark); color: var(--red-on-dark); padding: 8px 12px; border-radius: 8px; font-size: 13px; }
#status-banner { background: var(--amber-bg-dark); color: var(--amber-on-dark); padding: 8px 12px; border-radius: 8px; font-size: 13px; display: flex; gap: 10px; align-items: center; }
.banner-action { background: var(--amber-on-dark); border: none; color: var(--amber-bg-dark); font-size: 12px; font-weight: 700; padding: 3px 12px; border-radius: 999px; cursor: pointer; }

.filter-menu { position: relative; }
.filter-menu > summary { list-style: none; cursor: pointer; padding: 5px 10px; border: 1px solid var(--line); border-radius: 999px; background: var(--hover); color: var(--ink); font-size: 12px; white-space: nowrap; }
.filter-menu > summary::-webkit-details-marker { display: none; }
.filter-menu > summary::after { content: " \25BE"; opacity: .6; }
.filter-menu.active > summary { background: var(--brand); border-color: var(--brand); color: white; }
.filter-options { position: absolute; z-index: 20; top: calc(100% + 6px); left: 0; min-width: 180px; max-height: 260px; overflow-y: auto; background: var(--panel); color: var(--ink); border-radius: 8px; padding: 6px; box-shadow: 0 6px 20px var(--shadow-lift); display: grid; gap: 2px; }
.filter-options label { display: flex; gap: 8px; align-items: center; padding: 5px 8px; border-radius: 6px; cursor: pointer; font-size: 13px; }
.filter-options label:hover { background: var(--hover); }
.filter-options input { accent-color: var(--brand); }

main { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; padding: 16px 20px; align-items: start; }
.quadrant { background: var(--panel); border-radius: var(--radius); padding: 12px; box-shadow: 0 1px 3px var(--shadow); }
.quadrant h2 { font-size: 14px; margin-bottom: 8px; flex: 0 0 auto; }
.quadrant h2 small { color: var(--muted); font-weight: normal; margin-left: 4px; }
/* Every box sizes to its own contents. Without align-items:start a grid row
   is as tall as its tallest cell, so one busy box inflated the empty one
   beside it and pushed the other two under the fold. */
/* minmax(0, 1fr), not 1fr: a grid track sizes to its contents unless told
   otherwise, and a card whose buttons are showing is 850px wide at its
   narrowest. With a bare 1fr the widest card pushed its column, the column
   pushed the page, and the board had to be scrolled sideways to be read. */
.matrix { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 12px; align-items: start; }
/* Past its cap a box scrolls inside itself rather than growing the page, so no
   box can ever push another off the screen again. */
.quadrant { display: flex; flex-direction: column; align-self: start; max-height: 62vh; min-height: 0; min-width: 0; }
.quadrant .cards { overflow-y: auto; min-height: 26px; }
.quadrant h2 { display: flex; align-items: baseline; gap: 6px; }
.q-count { background: var(--chip); color: var(--violet-ink); border-radius: 999px; font-size: 11px; font-weight: 700; padding: 1px 7px; }
.quadrant[data-quadrant="q1"] .q-count { background: var(--red-bg); color: var(--red-ink); }
.quadrant[data-quadrant="q2"] .q-count { background: var(--blue-bg); color: var(--blue-ink); }
.quadrant[data-quadrant="q3"] .q-count { background: var(--amber-bg); color: var(--amber-ink); }
.quadrant[data-quadrant="q4"] .q-count { background: var(--hover); color: var(--muted); }
/* An empty box is one header line, not a panel of nothing. It keeps its drop
   zone: dragging a card into an empty box is how it stops being empty. */
.quadrant.is-empty { padding-bottom: 8px; }
.quadrant.is-empty h2 { margin-bottom: 4px; }
.quadrant.is-empty .cards::after { content: "nothing here"; color: var(--muted); font-size: 12px; }
.quadrant[data-quadrant="q1"] h2 { color: var(--q1); }
.quadrant[data-quadrant="q2"] h2 { color: var(--q2); }
.quadrant[data-quadrant="q3"] h2 { color: var(--q3); }
.quadrant[data-quadrant="q4"] h2 { color: var(--q4); }

/* The whole width of the Inbox, so it reads as the thing to do there. */
#add-modal .add-body { display: grid; gap: 8px; padding: 16px 20px; }
#add-modal { width: min(560px, calc(100vw - 32px)); }
.add-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 10px; align-items: end; }
#add-form input, #add-form select { padding: 8px 10px; border: 1px solid var(--line); border-radius: 8px; font-size: 13px; font-family: inherit; background: white; color: var(--ink); width: 100%; }
#add-form #add-title { font-size: 15px; font-weight: 600; }
#add-form .field-label { font-size: 12px; color: var(--muted); display: grid; gap: 4px; }
#add-form .form-hint { font-size: 11px; color: var(--muted); line-height: 1.4; margin: 2px 0 0; }
#add-form button[type="submit"] { padding: 8px 14px; border: none; border-radius: 8px; background: var(--brand); color: white; cursor: pointer; font: inherit; font-size: 13px; font-weight: 600; }

.cards { display: grid; gap: 4px; min-height: 26px; align-content: start; min-width: 0; }
.cards.drag-over { outline: 2px dashed var(--brand); outline-offset: 4px; border-radius: 8px; }

/* How much a card can say is decided by the width of its own box, not the
   width of the window: the same 1200px screen gives a two-column matrix half
   the room a one-column one gets. Below these widths the fields a GM can work
   out from the task itself give up their space so the name stays readable. */
.quadrant { container-type: inline-size; }
@container (max-width: 460px) { .card .client { display: none; } }
@container (max-width: 330px) { .card .chip.due { display: none; } }

/* Pointing at a card asks for its buttons, and on a narrow box the buttons
   and the whole row of fields cannot both fit. The fields that are only being
   read give up their room first, so the task's name survives the hover: the
   client (which the box and the tier stripe already imply), then the status. */
@container (max-width: 820px) {
  .card:hover .client, .card:focus-within .client { display: none; }
}
@container (max-width: 620px) {
  .card:hover .chip.status, .card:focus-within .chip.status { display: none; }
}


/* One task, one line, 44px tall. The lanes are fixed so the eye runs down a
   single channel instead of re-reading a paragraph per task; only the title is
   at full contrast, because only the title is the work. */
.card { background: var(--raise); border: 1px solid var(--line-strong); border-radius: 8px; cursor: grab; font-size: 13px; min-width: 0; }
.card:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.card .row { display: flex; align-items: center; gap: 8px; height: 42px; padding: 0 10px; min-width: 0; overflow: hidden; }
.card.dragging { opacity: .4; }
.card .title { font-weight: 600; flex: 1 1 auto; min-width: 8ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Muted, capped, and gone entirely when the task has no client. The logo is a
   fixed square, so only the name gives ground as the card narrows. */
.card .client { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 5px; max-width: 112px; min-width: 0; font-size: 12px; color: var(--muted); }
.card .client-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A face or a logo. One shape whichever way it resolves: a picture fills the
   circle, initials centre in it, an emoji sits on the page's own background.
   Fixing the size on the span rather than the img is what keeps the row from
   shifting when a signed Notion URL expires and the picture falls back. */
.avatar { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; border-radius: 50%; overflow: hidden; background: var(--chip); color: white; font-size: 9px; font-weight: 700; letter-spacing: .02em; line-height: 1; user-select: none; }
.avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* An emoji is already a picture; a coloured disc behind it only muddies it. */
.avatar.is-emoji { background: none; font-size: 15px; }
/* A client's mark is usually a wordmark or a square logo, so it is not cropped
   to a circle the way a face is. */
.avatar.logo { border-radius: 4px; }
.avatar.logo img { object-fit: contain; }
.card .avatar.who { width: 22px; height: 22px; font-size: 9px; }
#list-table .col-client { white-space: nowrap; }
#list-table .col-client .avatar { width: 16px; height: 16px; font-size: 8px; margin-right: 6px; vertical-align: -3px; }
/* The picture beside a picker, sized to the line it sits on. */
.row-value { display: flex; align-items: center; gap: 7px; min-width: 0; }
/* The picture takes over the row's left edge, so the select no longer needs the
   negative margin that was aligning it under the label. */
#edit-form .detail-row .row-value select { flex: 1 1 auto; width: auto; min-width: 0; margin-left: 0; }
.avatar.row-face { width: 22px; height: 22px; font-size: 9px; }

.card .pri-flag { flex: 0 0 auto; color: var(--red-ink); font-weight: 800; font-size: 14px; line-height: 1; }
.card .chip { flex: 0 0 auto; white-space: nowrap; }
.card .chip.due { font-variant-numeric: tabular-nums; }
/* The checklist inside a card. Indented under an accent rule so it reads as
   part of the task rather than as more cards. */
.card .sub-toggle { flex: 0 0 auto; border: 0; background: var(--chip); color: var(--violet-ink); border-radius: 999px; font-size: 11px; font-weight: 600; padding: 1px 8px; cursor: pointer; vertical-align: text-bottom; }
.card .sub-toggle:hover { background: var(--chip); }
.row-subs { margin-left: 7px; font-size: 11px; font-weight: 600; color: var(--violet-ink); background: var(--chip); border-radius: 999px; padding: 1px 7px; }
.subtasks { display: grid; gap: 2px; margin: 0 10px 8px 18px; padding-left: 8px; border-left: 2px solid var(--line-strong); cursor: auto; }
.subtask { display: flex; gap: 7px; align-items: flex-start; font-size: 12px; line-height: 1.4; }
.subtask > label { display: flex; gap: 7px; align-items: flex-start; flex: 1; cursor: pointer; }
.subtask input { margin: 2px 0 0; accent-color: var(--brand); cursor: pointer; }
.subtask.is-done > label { color: var(--faint); text-decoration: line-through; }
/* Out of the way until the row is wanted, since the name is what gets read. */
.sub-edit { border: 0; background: none; color: var(--faint); font: inherit; font-size: 11px; padding: 0 2px; cursor: pointer; opacity: 0; }
.subtask:hover .sub-edit, .sub-edit:focus { opacity: 1; }
.sub-edit:hover { color: var(--brand); text-decoration: underline; }
@media (hover: none) { .sub-edit { opacity: 1; } }
/* Deleting a subtask asks before it does anything: the first click turns the
   button into the question, and the second answers it. Armed, it is red, so
   what the next click does is never in doubt. */
.sub-del { border: 0; background: none; color: var(--faint); font: inherit; font-size: 11px; padding: 0 2px; cursor: pointer; opacity: 0; }
.subtask:hover .sub-del, .sub-del:focus { opacity: 1; }
.sub-del:hover { color: var(--red-ink); text-decoration: underline; }
.sub-del.armed { color: var(--red-ink); font-weight: 700; opacity: 1; }
#edit-sub-list .sub-del[disabled], .sub-del[disabled] { opacity: .5; cursor: default; text-decoration: none; }
@media (hover: none) { .sub-del { opacity: 1; } }

/* Inside the dialog the checklist is being managed rather than read, so both
   controls stay drawn instead of waiting for a pointer to find them. */
#edit-sub-list .sub-edit, #edit-sub-list .sub-del { opacity: 1; }
/* Starting a subtask opens a dialog rather than writing one word into a box,
   so this is a button and reads like one. */
.sub-add-btn { justify-self: start; border: 1px dashed var(--line-strong); background: none; color: var(--brand); font: inherit; font-size: 12px; font-weight: 600; padding: 5px 10px; border-radius: 8px; cursor: pointer; }
.sub-add-btn:hover { background: var(--hover); border-style: solid; }
.chip { font-size: 11px; padding: 2px 8px; border-radius: 999px; background: var(--chip); color: var(--violet-ink); }
.chip.status { background: var(--blue-bg); color: var(--blue-ink); }
.chip.status.quiet { background: var(--hover); color: var(--faint); }
.chip.manual { background: var(--green-bg); color: var(--green-ink); }
.chip.priority { background: var(--amber-bg); color: var(--amber-ink); }
.chip.priority.hot { background: var(--red-bg); color: var(--red-ink); }
.chip.due { background: var(--green-bg); color: var(--green-ink); }
.chip.due.overdue { background: var(--red-bg); color: var(--red-ink); font-weight: 600; }
.chip.due.today { background: var(--amber-bg); color: var(--amber-ink); font-weight: 600; }
.card.tier-risk { border-left: 3px solid var(--red-line); }
.card.tier-comp { border-left: 3px solid var(--blue-line); }
.card.tier-onb { border-left: 3px solid var(--amber-line); }
.card.tier-big { border-left: 3px solid var(--violet-line); }
.chip.tier.tier-risk { background: var(--red-bg); color: var(--red-ink); }
.chip.tier.tier-comp { background: var(--blue-bg); color: var(--blue-ink); }
.chip.tier.tier-onb { background: var(--amber-bg); color: var(--amber-ink); }
.chip.tier.tier-big { background: var(--chip); color: var(--violet-ink); }
.card a { color: var(--brand); font-size: 12px; text-decoration: none; }
.card .actions { flex: 0 0 auto; display: flex; gap: 6px; align-items: center; }
.card .actions button { white-space: nowrap; }
.card .notion-link { font-size: 13px; line-height: 1; padding: 0 2px; }
.card .actions:empty { display: none; }
.card .hide { background: none; border: 1px solid var(--line-strong); color: var(--muted); cursor: pointer; font-size: 12px; padding: 3px 10px; border-radius: 6px; }
.card .hide:hover { border-color: var(--brand); color: var(--brand); }
/* A hidden card is only on screen because "Show hidden" is on, so it reads as
   set aside rather than as part of the work order. */
.card.is-hidden { opacity: .55; border-style: dashed; background: var(--bg); }
.card.is-hidden .hide { border-color: var(--brand); color: var(--brand); font-weight: 600; }
.card .edit { background: none; border: 1px solid var(--line-strong); color: var(--muted); cursor: pointer; font-size: 12px; padding: 3px 10px; border-radius: 6px; }
.card .edit:hover { border-color: var(--brand); color: var(--brand); }
.card .dismiss { background: none; border: none; color: var(--muted); cursor: pointer; font-size: 12px; }
.card .mark-done { background: var(--green-bg); border: 1px solid var(--green-line); color: var(--green-ink); cursor: pointer; font-size: 12px; font-weight: 600; padding: 3px 10px; border-radius: 6px; }
.card .mark-done:disabled { opacity: .5; cursor: default; }

/* The buttons belong to the one card being dealt with, so they sit back until
   the pointer or the keyboard arrives. They fade rather than vanish: a button
   nobody can see is a button nobody finds. A touch screen has no hover to
   offer, so there they are simply always on. */
/* Four buttons drawn on every task, permanently, cost more of the line than
   the task name. They belong to the one row being dealt with, so they arrive
   with the pointer or the keyboard and leave with it. A touch screen has no
   hover to offer, so there they are simply always on.

   The status chip goes the same way when it says what every other row says.
   It is never removed, because it is the only way to change a status from the
   board — it just stops repeating "Not started" ten times down the column. */
@media (hover: hover) {
  .card .actions { display: none; }
  .card:hover .actions, .card:focus-within .actions { display: flex; }
  .card .chip.status.quiet { display: none; }
  .card:hover .chip.status.quiet, .card:focus-within .chip.status.quiet { display: inline-block; }
}

/* Editable in place: the two fields a GM changes most often, without the
   dialog. They read as chips until clicked. */
.chip-edit { border: 1px solid transparent; cursor: pointer; font-family: inherit; }
.chip-edit:hover { border-color: var(--brand); }
.chip-edit:disabled { opacity: .5; cursor: default; }
select.chip-edit { appearance: none; }
.card .meta .inline-select { font-size: 11px; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--brand); background: white; color: var(--ink); font-family: inherit; }
.card .meta .inline-date { font-size: 11px; padding: 1px 6px; border-radius: 999px; border: 1px solid var(--brand); background: white; color: var(--ink); font-family: inherit; }

/* The reset at the top of this file sets margin:0 on everything, which stops a
   modal dialog centring itself, so it is put back here. */
#edit-modal, #add-modal, #help-modal { background: var(--panel); margin: auto; border: none; border-radius: var(--radius); padding: 0; max-width: 420px; width: calc(100% - 32px); max-height: calc(100vh - 48px); box-shadow: 0 12px 40px var(--shadow-lift); color: var(--ink); }
#edit-modal::backdrop, #add-modal::backdrop, #help-modal::backdrop { background: rgba(22,17,43,.45); }

/* Starting a subtask is still a form to fill in, so that dialog keeps the
   stacked layout the task dialog has grown out of. */

/* The task dialog is the one screen a GM reads rather than fills in, so it is
   laid out as a document: a wide sheet, the name at the top of the page, and
   the fields in a margin down the right. */
#edit-modal { max-width: 780px; }
#edit-form { display: grid; grid-template-rows: auto 1fr auto; max-height: calc(100vh - 48px); }

/* A thin strip for where the task lives and how to leave, nothing else. */
.detail-head { display: flex; gap: 10px; align-items: center; padding: 10px 14px 10px 20px; border-bottom: 1px solid var(--line-soft); }
.detail-crumb { font-size: 12px; font-weight: 600; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.detail-link { margin-left: auto; font-size: 12px; color: var(--brand); text-decoration: none; white-space: nowrap; }
.detail-link:hover { text-decoration: underline; }
.detail-link.hidden + .detail-close { margin-left: auto; }
.detail-close { background: none; border: none; color: var(--muted); font-size: 20px; line-height: 1; padding: 2px 6px; border-radius: 6px; cursor: pointer; }
.detail-close:hover { background: var(--hover); color: var(--ink); }

.detail-body { display: grid; grid-template-columns: 1fr 264px; min-height: 0; overflow-y: auto; }
.detail-main { padding: 18px 20px 22px; display: grid; gap: 14px; align-content: start; min-width: 0; }
.detail-main .form-hint { font-size: 12px; line-height: 1.45; color: var(--muted); }

/* Name first and big, with the tick beside it, the way the task itself reads.
   The box only appears once the pointer or the caret is in it. */
.detail-title-row { display: flex; gap: 11px; align-items: flex-start; }
.detail-check { flex: none; width: 22px; height: 22px; margin-top: 2px; border: 1.5px solid var(--line-strong); border-radius: 50%; background: none; color: transparent; cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 0; }
.detail-check:hover:not(:disabled) { border-color: var(--green-ink); background: var(--green-bg); color: var(--green-ink); }
.detail-check:disabled { opacity: .4; cursor: default; }
.detail-tick { font-size: 12px; line-height: 1; }
#edit-form.is-complete .detail-check { background: var(--green-ink); border-color: var(--green-ink); color: white; }
#edit-form.is-complete .detail-title { color: var(--muted); text-decoration: line-through; }
#edit-form .detail-title { font-size: 20px; font-weight: 700; line-height: 1.3; width: 100%; padding: 3px 8px; border: 1px solid transparent; border-radius: 8px; background: none; color: var(--ink); font-family: inherit; resize: none; overflow: hidden; display: block; }
#edit-form .detail-title:hover { border-color: var(--line-strong); }
#edit-form .detail-title:focus { outline: none; border-color: var(--brand); background: white; }

/* The checklist keeps the name's left edge, so the task and its parts read as
   one column rather than two. */
#edit-subtasks { display: grid; gap: 2px; padding-left: 33px; }

/* The heading is the fold control and the progress count at once. It reads as
   a heading, not as a button, until the pointer arrives. */
.sub-head { display: flex; align-items: center; gap: 6px; justify-self: start; border: 0; background: none; font: inherit; font-size: 13px; font-weight: 700; color: var(--ink); padding: 4px 6px 4px 0; margin-left: -4px; border-radius: 6px; cursor: pointer; }
.sub-head:hover { color: var(--brand); }
.sub-head .sub-count { font-weight: 600; color: var(--muted); font-size: 12px; }
.sub-head .sub-chev { display: inline-block; font-size: 11px; color: var(--faint); transition: transform .12s ease; width: 10px; }
#edit-subtasks.is-folded .sub-chev { transform: rotate(-90deg); }
/* Folded, the heading and its count are all that is left. */
#edit-subtasks.is-folded #edit-sub-body { display: none; }
#edit-sub-body { display: grid; gap: 2px; }

/* Inside the dialog a subtask is a row of a list with a line under it, the way
   a task manager draws one, rather than a bullet with a tick beside it. */
#edit-sub-list { display: grid; gap: 0; padding-left: 0; border-left: 0; }
#edit-sub-list:empty { display: none; }
#edit-sub-list .subtask.is-inline { align-items: center; gap: 10px; padding: 7px 2px; border-bottom: 1px solid var(--line-soft); font-size: 13px; }
/* A round tick, because a square one reads as a spreadsheet. */
#edit-sub-list .subtask.is-inline > input[type="checkbox"] { appearance: none; -webkit-appearance: none; flex: 0 0 auto; width: 17px; height: 17px; margin: 0; border: 1.5px solid var(--line-strong); border-radius: 50%; background: white; cursor: pointer; display: grid; place-content: center; }
#edit-sub-list .subtask.is-inline > input[type="checkbox"]:hover { border-color: var(--brand); }
#edit-sub-list .subtask.is-inline > input[type="checkbox"]:checked { background: var(--brand); border-color: var(--brand); }
#edit-sub-list .subtask.is-inline > input[type="checkbox"]:checked::after { content: "\2713"; color: white; font-size: 11px; line-height: 1; }
#edit-sub-list .subtask.is-inline > input[type="checkbox"]:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
/* The name fills the row, so clicking anywhere along it opens the subtask. */
.sub-title { flex: 1 1 auto; text-align: left; border: 0; background: none; font: inherit; font-size: 13px; color: var(--ink); padding: 2px 0; cursor: text; min-width: 0; }
.sub-title:hover { color: var(--brand); }
.subtask.is-done .sub-title { color: var(--faint); text-decoration: line-through; }
/* Deleting is a row action, so it waits for the pointer rather than sitting on
   every line. It keeps its space, so nothing shifts when it appears, and the
   keyboard reaches it the same as ever. */
#edit-sub-list .subtask.is-inline .sub-del { opacity: 0; transition: opacity .1s ease; }
#edit-sub-list .subtask.is-inline:hover .sub-del,
#edit-sub-list .subtask.is-inline:focus-within .sub-del,
#edit-sub-list .subtask.is-inline .sub-del.armed { opacity: 1; }

/* Beside the name the add row is a line of the checklist, not a button parked
   under it, so it drops the dashed box it wears elsewhere. */
#edit-subtasks .sub-add-btn { border: 0; padding: 6px 0; font-weight: 600; display: flex; align-items: center; gap: 9px; }
#edit-subtasks .sub-add-btn:hover { background: none; }
#edit-subtasks .sub-add-btn:hover .sub-add-label { text-decoration: underline; }
.sub-add-btn .sub-plus { display: inline-grid; place-content: center; width: 17px; height: 17px; font-size: 15px; line-height: 1; color: var(--brand); }

/* The box a subtask is written in. It is the same width as the row it will
   become, and it opens where that row will be. */
.sub-compose-box { display: grid; gap: 8px; border: 1px solid var(--line-strong); border-radius: 10px; padding: 10px 11px 9px; background: white; margin: 4px 0; box-shadow: 0 1px 3px var(--shadow); }
.sub-compose-title { border: 0; padding: 0; font: inherit; font-size: 14px; font-weight: 600; color: var(--ink); background: none; width: 100%; }
.sub-compose-title:focus { outline: none; }
.sub-compose-title::placeholder { color: var(--faint); font-weight: 400; }
.sub-compose-row { display: flex; align-items: center; gap: 6px; }
.sub-compose-chips { display: flex; align-items: center; gap: 6px; flex: 1 1 auto; min-width: 0; flex-wrap: wrap; }
/* Each field is a chip: small, bordered, and only as wide as what it holds. */
.chip-field { font: inherit; font-size: 11px; color: var(--faint); background: white; border: 1px solid var(--line); border-radius: 7px; padding: 3px 6px; max-width: 130px; cursor: pointer; }
.chip-field:hover { border-color: var(--line-strong); }
.chip-field:focus { outline: none; border-color: var(--brand); }
.sub-compose-acts { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }
.sub-compose-cancel { border: 0; background: none; color: var(--faint); font-size: 17px; line-height: 1; width: 26px; height: 26px; border-radius: 7px; cursor: pointer; }
.sub-compose-cancel:hover { background: var(--hover); color: var(--ink); }
/* The tick is the one filled thing in the box, so what finishes it is obvious. */
.sub-compose-save { border: 0; background: var(--brand); color: white; font-size: 13px; line-height: 1; width: 30px; height: 26px; border-radius: 7px; cursor: pointer; }
.sub-compose-save:hover { filter: brightness(1.06); }
.sub-compose-save[disabled], .sub-compose-cancel[disabled] { opacity: .5; cursor: default; }
.sub-compose-box .edit-error { margin: 0; }

/* The margin: one field to a line, each named above its value, hairlines
   between them so eight fields read as a list and not as a form. */
.detail-side { background: var(--raise); border-left: 1px solid var(--line-soft); padding: 6px 16px 16px; display: grid; align-content: start; }
.detail-row { display: grid; gap: 3px; font-size: 11px; font-weight: 600; letter-spacing: .02em; color: var(--muted); padding: 10px 0; border-bottom: 1px solid var(--line-soft); }
.detail-row:last-child { border-bottom: none; }
#edit-form .detail-row select, #edit-form .detail-row input { width: 100%; font-size: 13px; font-weight: 400; letter-spacing: 0; color: var(--ink); font-family: inherit; background: none; border: 1px solid transparent; border-radius: 6px; padding: 4px 6px; margin-left: -6px; }
#edit-form .detail-row select:hover, #edit-form .detail-row input:hover { background: white; border-color: var(--line-strong); }
#edit-form .detail-row select:focus, #edit-form .detail-row input:focus { outline: none; background: white; border-color: var(--brand); }

/* Editing is the one action here that reaches past this browser, so it says so
   before the GM saves rather than after. */
.detail-foot { display: flex; gap: 14px; align-items: center; padding: 12px 20px; border-top: 1px solid var(--line-soft); background: var(--panel); }
.detail-foot .edit-warning { flex: 1; margin: 0; }
.detail-foot .edit-actions { margin-top: 0; }
/* Delete keeps its distance from Save in a row this short, so the two are
   never reached for at once. */
.detail-foot .edit-actions .danger-btn { margin-right: 18px; }
.edit-warning { font-size: 11px; line-height: 1.4; background: var(--amber-bg); color: var(--amber-ink); padding: 7px 10px; border-radius: 8px; }
.edit-error { font-size: 12px; line-height: 1.45; background: var(--red-bg); color: var(--red-ink); padding: 8px 10px; border-radius: 8px; }
.edit-actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 4px; }
.edit-actions button { padding: 8px 14px; border: none; border-radius: 8px; font-size: 13px; cursor: pointer; background: var(--brand); color: white; }
.edit-actions button:disabled { opacity: .55; cursor: default; }
.edit-actions .ghost-dark { background: transparent; border: 1px solid var(--line); color: var(--muted); }
/* Pushed to the far left by the auto margin, so it never sits next to Save.
   Asked once, it fills in red: what the next click does is never in doubt. */
.edit-actions .danger-btn { margin-right: auto; background: transparent; border: 1px solid var(--red-line); color: var(--red-ink); }
.edit-actions .danger-btn:hover { background: var(--red-bg); }
.edit-actions .danger-btn.armed { background: var(--red-ink); border-color: var(--red-ink); color: white; font-weight: 700; }

#help-modal { max-width: 640px; }
.help-body { padding: 22px; display: grid; gap: 10px; font-size: 13px; line-height: 1.5; }
.help-body h2 { font-size: 17px; }
.help-body ol { padding-left: 20px; display: grid; gap: 4px; }
.help-body .note { color: var(--muted); font-size: 12px; }
.help-body kbd { border: 1px solid var(--line); border-radius: 4px; padding: 0 5px; font-size: 11px; }
.help-body .c-q1 { color: var(--red-ink); }
.help-body .c-q2 { color: var(--blue-ink); }
.help-body .c-q3 { color: var(--amber-ink); }
.help-body .c-q4 { color: var(--muted); }

/* One control, two states, so it reads as a switch rather than two buttons
   that happen to sit together. */
#view-toggle { display: inline-flex; border: 1px solid var(--side-line); border-radius: 8px; overflow: hidden; }

/* Columns scroll sideways rather than squeeze: eight statuses will not fit a
   laptop, and a 90px-wide card is worse than a scrollbar. */
#kanban-view { padding: 16px 24px; }
/* A column used to be 300px wide whatever the screen was, so three status
   columns left two thirds of a 1680px board empty and crowded everything
   against the left edge. The columns share the width now: how many fit is the
   screen's business, and under 260px each they wrap onto the next row rather
   than making the board scroll sideways. */
#kanban { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); gap: 12px; padding-bottom: 8px; }
/* Every column reaches the same height, so a column with nothing in it is
   still a target worth dropping onto, and the fullest one scrolls inside
   itself instead of pushing the others off the screen. */
.kanban-col { min-width: 0; display: flex; flex-direction: column; max-height: calc(100vh - 190px); background: var(--panel); border-radius: var(--radius); padding: 10px 12px 4px; box-shadow: 0 1px 3px var(--shadow); }
.kanban-col h2 { margin: 0 0 8px; font-size: 13px; text-transform: uppercase; letter-spacing: .4px; color: var(--muted); display: flex; align-items: center; gap: 7px; }
.kanban-col .col-count { background: var(--chip); color: var(--violet-ink); border-radius: 999px; font-size: 11px; padding: 1px 7px; }
.kanban-col .cards { flex: 1 1 auto; min-height: 40px; overflow-y: auto; align-content: start; }
/* A column is 300px wide and a task's name is not. On the matrix a card is
   one line because the box is wide; here the name takes the first line to
   itself, up to two lines of it, and everything else reads underneath. A
   column of "9- Post…" says nothing about the work. */
#kanban .card .row { flex-wrap: wrap; height: auto; min-height: 42px; padding: 8px 10px; row-gap: 5px; column-gap: 6px; }
#kanban .card .title { flex: 1 1 0; min-width: calc(100% - 30px); white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; line-height: 1.3; }
#kanban .card .actions { flex-basis: 100%; }
/* The column a card sits in is its status, so the chip repeating it is a
   third of the card's second line spent saying where the card already is. */
#kanban .card .chip.status { display: none; }

#kanban-empty { padding: 8px 2px; color: var(--muted); }

#list-view { padding: 16px 24px; display: grid; gap: 12px; }
.tab-strip { display: flex; gap: 8px; flex-wrap: wrap; }
.tab-strip .tab { display: inline-flex; gap: 7px; align-items: center; background: var(--panel); border: 1px solid var(--line-strong); color: var(--muted); font-size: 13px; padding: 7px 14px; border-radius: 999px; cursor: pointer; }
.tab-strip .tab:hover { border-color: var(--brand); color: var(--brand); }
.tab-strip .tab.active { background: var(--brand); border-color: var(--brand); color: white; font-weight: 600; }
.tab-strip .tab-count { background: var(--chip); color: var(--violet-ink); font-size: 11px; font-weight: 700; padding: 1px 7px; border-radius: 999px; }
.tab-strip .tab.active .tab-count { background: rgba(255,255,255,.24); color: white; }

.list-panel { background: var(--panel); border-radius: var(--radius); padding: 6px 0; box-shadow: 0 1px 3px var(--shadow); overflow-x: auto; }
#list-table { width: 100%; border-collapse: collapse; font-size: 13px; }
#list-table th { text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); font-weight: 600; padding: 10px 14px; border-bottom: 1px solid var(--chip); }
#list-table td { padding: 5px 14px; border-bottom: 1px solid var(--line-soft); vertical-align: middle; height: 44px; }
#list-table tbody tr:not(.group-row) { cursor: pointer; }
#list-table .row-title { display: inline; }
#list-table tr:last-child td { border-bottom: none; }
#list-table .row-title { font-weight: 600; }
#list-table .col-due, #list-table .col-status { white-space: nowrap; }
/* Overdue is the one thing a GM should catch without reading, so the row
   carries it, not just the date cell. */
#list-table tr.row-overdue { background: var(--red-bg); }
#list-table tr.row-overdue .due-overdue { color: var(--red-ink); font-weight: 700; }
#list-table .due-today { color: var(--amber-ink); font-weight: 600; }
#list-table .due-nodate, #list-table .due-closed { color: var(--muted); }
#list-table .col-priority.hot { color: var(--red-ink); font-weight: 600; }
#list-table tr.is-hidden { opacity: .55; }
#list-table tr.is-closed .row-title { color: var(--muted); }
#list-table .col-actions { white-space: nowrap; text-align: right; }
#list-table .col-actions a { color: var(--brand); font-size: 12px; text-decoration: none; margin-right: 8px; }
#list-table .row-btn { background: none; border: 1px solid var(--line-strong); color: var(--muted); cursor: pointer; font-size: 12px; padding: 3px 10px; border-radius: 6px; margin-left: 6px; }
#list-table .row-btn:hover { border-color: var(--brand); color: var(--brand); }
#list-table .row-btn.done { background: var(--green-bg); border-color: var(--green-line); color: var(--green-ink); font-weight: 600; }
#list-table .row-btn.reopen { background: var(--blue-bg); border-color: var(--blue-line); color: var(--blue-ink); font-weight: 600; }
#list-table .row-btn:disabled { opacity: .5; cursor: default; }
/* The band a group of rows reads under. It sticks while its rows scroll past,
   because a row halfway down a long list means nothing without knowing which
   box it belongs to. The count is the whole point: "Do Next · 9" says what a
   nine-card panel says, in one line. */
.list-panel { max-height: calc(100vh - 190px); overflow-y: auto; overflow-x: auto; }
#list-table .group-row th { position: sticky; top: 0; z-index: 2; background: var(--panel); padding: 8px 14px 6px; border-bottom: 1px solid var(--chip); text-transform: none; letter-spacing: 0; }
.group-toggle { display: inline-flex; align-items: center; gap: 7px; background: none; border: none; padding: 0; cursor: pointer; font: inherit; font-size: 12px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--muted); }
.group-toggle:hover { color: var(--brand); }
.group-count { background: var(--chip); color: var(--violet-ink); font-size: 11px; font-weight: 700; padding: 1px 7px; border-radius: 999px; letter-spacing: 0; }
.group-q1 .group-toggle { color: var(--q1); } .group-q1 .group-count { background: var(--red-bg); color: var(--red-ink); }
.group-q2 .group-toggle { color: var(--q2); } .group-q2 .group-count { background: var(--blue-bg); color: var(--blue-ink); }
.group-q3 .group-toggle { color: var(--q3); } .group-q3 .group-count { background: var(--amber-bg); color: var(--amber-ink); }
.group-q4 .group-toggle { color: var(--q4); } .group-q4 .group-count { background: var(--hover); color: var(--muted); }
#list-empty { padding: 18px 14px; color: var(--muted); font-size: 13px; }
#list-more { padding: 12px 14px; text-align: center; border-top: 1px solid var(--line-soft); }
#more-rows-btn { background: none; border: 1px solid var(--line-strong); color: var(--brand); font-size: 13px; font-weight: 600; padding: 7px 18px; border-radius: 999px; cursor: pointer; }
#more-rows-btn:hover { border-color: var(--brand); background: var(--hover); }

/* Two boxes side by side need a screen wide enough for both. Under this the
   matrix reads as one column: a 320px box cannot hold a task's name and its
   buttons at the same time, and a name that disappears when you point at it
   is worse than a longer board. */
@media (max-width: 1150px) {
  .matrix { grid-template-columns: 1fr; }
  /* Stacked, the four boxes share one column instead of two, so each gets a
     smaller share of the screen before it starts scrolling inside itself. */
  .quadrant { max-height: 38vh; }
}

@media (max-width: 900px) {
  main { grid-template-columns: 1fr; }
  header { padding: 10px 14px 12px; }
  main, #list-view, #kanban-view, #calendar-view { padding: 12px 14px; }
  .search-field { order: 9; max-width: none; flex-basis: 100%; }
  #counts { margin-left: 0; flex-basis: 100%; }
  /* The columns a GM can infer from the task itself go first when there is no
     room; the date and what to do about it stay. */
  #list-table .col-client, #list-table .col-category, #list-table .col-priority { display: none; }
  /* No room for a margin, so the fields fall in under the task and the strip
     that held them becomes a band across the foot of the name. */
  .detail-body { grid-template-columns: 1fr; }
  .detail-side { border-left: none; border-top: 1px solid var(--line-soft); }
  .detail-foot { flex-wrap: wrap; }
  .detail-foot .edit-warning { flex-basis: 100%; }
  #edit-form .detail-title { font-size: 18px; }
}

/* ---------------------------------------------------------------- calendar */
#calendar-view { padding: 16px 24px; display: grid; gap: 12px; }

/* The top bar's switch, in the light: same shape, a border that belongs on a
   white page. */
.seg { display: inline-flex; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.seg .seg-btn { background: var(--panel); border: 0; color: var(--muted); font: inherit; font-size: 13px; padding: 6px 12px; cursor: pointer; }
.seg .seg-btn:hover { color: var(--brand); }
.seg .seg-btn.active { background: var(--brand); color: white; font-weight: 600; }

/* The board by date. The bar reads left to right the way the eye does: where
   you are, then how much you are looking at. */
.cal-bar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.cal-bar h2 { font-size: 19px; font-weight: 700; margin: 0 6px 0 2px; }
.cal-arrow { width: 30px; height: 30px; border: 1px solid var(--line); background: var(--panel); color: var(--ink); border-radius: 8px; font-size: 17px; line-height: 1; cursor: pointer; }
.cal-arrow:hover { border-color: var(--brand); color: var(--brand); }
.cal-bar-end { display: flex; align-items: center; gap: 8px; margin-left: auto; }
.cal-today { border: 1px solid var(--line); background: var(--panel); color: var(--ink); border-radius: 8px; padding: 6px 12px; font: inherit; font-size: 13px; cursor: pointer; }
.cal-today:hover { border-color: var(--brand); color: var(--brand); }

.cal-panel { background: var(--panel); border-radius: var(--radius); overflow: hidden; box-shadow: 0 1px 3px var(--shadow); }
/* The weekday names carry the grid, so they are read as headings rather than
   as a caption under the toolbar: darker, spaced, and over a tint that closes
   the head and the grid into one panel. */
.cal-head { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); border-bottom: 1px solid var(--line-strong); background: var(--raise); }
.cal-weekday { padding: 9px 10px; font-size: 11.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--ink); text-align: center; }
/* Today is named at the top of its own column, so it is found from the head
   rather than by hunting the grid for a tinted square. */
.cal-weekday.is-today { color: var(--brand); }

/* Every week is the same height whatever it holds, so the grid stays a grid:
   a day with more than fits says "+N more" rather than stretching its row. */
.cal-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); grid-auto-rows: minmax(112px, auto); }
.cal-day { border-right: 1px solid var(--line-soft); border-bottom: 1px solid var(--line-soft); padding: 5px 6px 7px; display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.cal-day:nth-child(7n) { border-right: 0; }
/* The days on loan from the months either side are still days, just quieter. */
.cal-day.is-outside { background: var(--raise); }
.cal-day.is-outside .cal-day-num { color: var(--faint); }
.cal-day-head { display: flex; align-items: center; justify-content: flex-end; min-height: 22px; }
/* The date is what a square is looked up by, so it is read at a glance: full
   ink rather than the muted grey the rest of the furniture uses. */
.cal-day-num { font-size: 13px; font-weight: 700; color: var(--ink); padding: 3px 7px; border-radius: 999px; line-height: 1.15; }

/* Today, said three ways so it survives a crowded grid: the square is tinted,
   the date is a filled pill, and a brand rule runs down the left edge. The
   outline sits inside the cell so it never nudges the grid a pixel. */
/* A square is a way into its own day, so it says so under the pointer. */
.cal-day.is-openable { cursor: pointer; }
.cal-day.is-openable:hover { background: var(--hover); }
.cal-day.is-openable.is-today:hover { background: var(--accent-strong); }
.cal-day.is-today { background: var(--accent-soft); box-shadow: inset 3px 0 0 var(--brand), inset 0 0 0 1px var(--line-strong); }
.cal-day.is-today .cal-day-num { background: var(--brand); color: white; box-shadow: 0 1px 4px rgba(124,92,255,.45); }

/* One day, one column: the seven-column grid would leave it a seventh of the
   screen wide with six empty squares beside it. */
.cal-head.is-day, .cal-grid.is-day { grid-template-columns: minmax(0, 1fr); }
.cal-grid.is-day { grid-auto-rows: minmax(220px, auto); }
.cal-grid.is-day .cal-day { border-right: 0; padding: 10px 14px 14px; gap: 5px; }
.cal-head.is-day .cal-weekday { text-align: left; padding-left: 14px; }
/* One column reads top-left down, so the date leads the day rather than
   sitting alone against the far edge with the whole screen between them. */
.cal-grid.is-day .cal-day-head { justify-content: flex-start; }
/* With a whole row to itself a task is worth reading, not squinting at. */
.cal-grid.is-day .cal-chip { font-size: 13px; padding: 6px 9px; }
.cal-grid.is-day .cal-day-num { font-size: 15px; }

/* A task in a square gets one line: the name, and a colour saying how loudly
   the board is asking for it. */
.cal-chip { display: flex; align-items: center; gap: 5px; width: 100%; text-align: left; border: 0; border-left: 3px solid var(--q4); background: var(--hover); color: var(--ink); border-radius: 5px; padding: 3px 6px; font: inherit; font-size: 11.5px; line-height: 1.3; cursor: pointer; white-space: nowrap; overflow: hidden; }
/* The name is the part that gives way when the square is narrow; the logo is
   a fixed square and holds its size. */
.cal-chip-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.cal-chip .avatar { width: 14px; height: 14px; font-size: 7px; }
.cal-chip .avatar.is-emoji { font-size: 11px; }
/* A finished task's logo fades with the rest of the chip rather than staying
   the one bright thing on a struck-through line. */
.cal-chip.is-done .avatar { opacity: .55; }
.cal-chip:hover { background: var(--hover); }
.cal-chip.q-q1 { border-left-color: var(--q1); }
.cal-chip.q-q2 { border-left-color: var(--q2); }
.cal-chip.q-q3 { border-left-color: var(--q3); }
.cal-chip.q-q4, .cal-chip.q-tray { border-left-color: var(--q4); }
/* Overdue is the one state worth shouting, so it keeps the red whatever box
   the task is filed in. */
.cal-chip.is-overdue { background: var(--red-bg); border-left-color: var(--q1); color: var(--red-ink); }
.cal-chip.is-overdue:hover { background: var(--red-bg); }
.cal-chip.is-done { background: var(--raise); color: var(--faint); text-decoration: line-through; border-left-color: var(--line-strong); }

.cal-more { align-self: flex-start; border: 0; background: none; color: var(--brand); font: inherit; font-size: 11px; font-weight: 600; padding: 2px 4px; cursor: pointer; border-radius: 5px; }
.cal-more:hover { background: var(--hover); }

/* Undated work sits under the grid rather than falling off the calendar. */
#cal-undated { margin-top: 14px; background: var(--panel); border-radius: var(--radius); padding: 12px 14px; box-shadow: 0 1px 3px var(--shadow); }
#cal-undated h3 { font-size: 13px; margin: 0 0 8px; color: var(--muted); }
#cal-undated-list { display: flex; flex-wrap: wrap; gap: 6px; }
#cal-undated-list .cal-chip { width: auto; max-width: 260px; }

/* Seven columns will not fit on a phone, so the grid becomes the days
   themselves: one column, each square as tall as what it holds. */
@media (max-width: 720px) {
  .cal-head { display: none; }
  .cal-grid { grid-template-columns: 1fr; grid-auto-rows: auto; }
  .cal-day { border-right: 0; min-height: 0; }
  .cal-day:empty { display: none; }
  .cal-day-head { justify-content: flex-start; }
}

/* ---- a task's description: the paragraph of context under its name ---- */
.desc-wrap { margin: 10px 0 4px; }
.desc-top { display: flex; align-items: center; gap: 10px; margin-bottom: 5px; }
.desc-label { font-size: 11.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--muted); }
/* The marks, kept small and out of the way until the description is worked on. */
.desc-tools { display: flex; align-items: center; gap: 2px; margin-left: auto; }
.desc-tool { min-width: 26px; height: 26px; display: inline-flex; align-items: center; justify-content: center; border: 0; background: none; color: var(--muted); font: inherit; font-size: 12.5px; line-height: 1; border-radius: 6px; cursor: pointer; padding: 0 5px; }
.desc-tool:hover { background: var(--hover); color: var(--brand); }
/* Lit for whatever the caret is sitting in, so the state is read not guessed. */
.desc-tool.is-on { background: var(--brand); color: white; }
.desc-tool-gap { width: 1px; height: 16px; background: var(--line-strong); margin: 0 4px; }

/* It grows with what is in it rather than scrolling: a description is there to
   be read, and three lines behind a scrollbar is not read. */
.desc-box { width: 100%; min-height: 52px; max-height: 320px; overflow-y: auto; border: 1px solid var(--line-strong); border-radius: 8px; padding: 9px 11px; font: inherit; font-size: 13.5px; line-height: 1.5; color: var(--ink); background: var(--panel); }
.desc-box:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px rgba(124,92,255,.14); }
/* An empty editor says what it is for. :empty alone will not do it — a browser
   keeps a <p><br></p> in there — so the placeholder hangs off the first line. */
.desc-box:empty::before, .desc-box > p:only-child:empty::before { content: attr(data-placeholder); color: var(--faint); }
.desc-box:empty::before { content: attr(data-placeholder); }
/* A body built in Notion is shown as it is, and plainly not a box to type in. */
.desc-box.is-locked { background: var(--raise); border-style: dashed; cursor: default; }

/* What the description itself looks like. Tight margins: this is a paragraph
   of context inside a dialog, not an article. */
.desc-box p { margin: 0 0 6px; }
.desc-box p:last-child { margin-bottom: 0; }
.desc-box ul, .desc-box ol { margin: 0 0 6px; padding-left: 22px; }
.desc-box li { margin: 2px 0; }
.desc-box a { color: var(--brand); text-decoration: underline; }
.desc-box code { background: var(--line-soft); border-radius: 4px; padding: 1px 4px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; }
.desc-box strong { font-weight: 700; }

/* ---- comments ---- */
#edit-comments { margin-top: 14px; border-top: 1px solid var(--line-soft); padding-top: 4px; }
.comment { display: flex; gap: 9px; padding: 8px 0; }
.comment + .comment { border-top: 1px solid var(--line-soft); }
.comment-face { flex: 0 0 auto; width: 26px; height: 26px; font-size: 10px; }
.comment-body { min-width: 0; flex: 1; }
.comment-head { display: flex; align-items: baseline; gap: 7px; }
.comment-who { font-size: 12.5px; font-weight: 700; color: var(--ink); }
.comment-when { font-size: 11px; color: var(--muted); }
/* Whatever someone typed, kept as they typed it — line breaks included. */
.comment-text { margin: 2px 0 0; font-size: 13px; line-height: 1.5; color: var(--ink); white-space: pre-wrap; overflow-wrap: anywhere; }

.comment-compose { position: relative; margin-top: 8px; }
#edit-comment { width: 100%; min-height: 36px; resize: none; overflow-y: auto; border: 1px solid var(--line-strong); border-radius: 8px; padding: 8px 11px; font: inherit; font-size: 13px; line-height: 1.45; color: var(--ink); background: var(--panel); }
#edit-comment:focus { outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px rgba(124,92,255,.14); }
.comment-foot { display: flex; align-items: center; gap: 10px; margin-top: 6px; }
.comment-foot .edit-error { margin: 0; flex: 1; }
.comment-send { margin-left: auto; border: 0; background: var(--brand); color: white; border-radius: 8px; padding: 6px 14px; font: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer; }
.comment-send:hover { filter: brightness(1.06); }
.comment-send:disabled { opacity: .55; cursor: default; }

/* The names offered while an @ is being typed. It sits over the dialog rather
   than pushing the compose box down as it opens and closes. */
.mention-menu { position: absolute; left: 0; bottom: calc(100% + 4px); z-index: 5; min-width: 220px; max-width: 100%; background: var(--panel); border: 1px solid var(--line-strong); border-radius: 10px; box-shadow: 0 8px 24px var(--shadow-lift); padding: 4px; display: flex; flex-direction: column; }
.mention-option { display: flex; align-items: center; gap: 8px; width: 100%; text-align: left; border: 0; background: none; color: var(--ink); font: inherit; font-size: 13px; padding: 6px 8px; border-radius: 7px; cursor: pointer; }
.mention-option:hover, .mention-option.is-first { background: var(--hover); }

/* Said only when a board that holds work is showing none of it. */
#board-note { margin: 10px 20px 0; font-size: 13px; color: var(--muted); }
