/* The board, set as an application rather than a document.
 *
 * `style.css` is loaded first and everything structural in it is kept: the
 * body is a flex column pinned to the viewport with `overflow: hidden`, the
 * header is its first row, `main` scrolls underneath and `#foot` is the strip
 * along the bottom. That shape is the point — a header with the view switcher
 * in it should not scroll away from somebody halfway down a list of forty
 * projects, and the version should not have to be scrolled to.
 *
 * Every colour is one of the six tokens. A board that invents a green for
 * "fine" and a red for "stuck" has invented a palette that light mode has
 * never seen; `--warn` and the dot classes in `style.css` already exist and
 * already work in both themes.
 */

/* By id, not `main`, so this wins on specificity rather than on which
   stylesheet happened to load last.

   The prefix on every class and id here is the same instinct kept from when
   `style.css` was seventeen hundred lines belonging to a different app: it
   caught this page out once — `#review-body` there was that app's weekly
   filing report, `max-height: 16rem` with a border, and this page's week
   silently rendered into a box four inches tall. `style.css` is this repo's
   now and a tenth of the size, and the split it draws still earns its keep: a
   rule without the prefix is one any page on this deployment would want. */
#pj-main {
  flex: 1;
  display: block;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 1rem;
  /* No safe-area inset here. `#foot` is the bottom element and reserves it
     already; reserving it twice leaves a phone with a band of empty scroll
     above a footer that was never over the home indicator. */
}

.pj-view { max-width: 62rem; margin: 0 auto; }

/* ---------------------------------------------------------------- header */

header .pj-spacer { margin-left: auto; }

header .pj-views { display: flex; gap: .35rem; }
header .pj-views button.on {
  border-color: var(--accent);
  color: var(--accent);
}

.pj-whoami { color: var(--dim); font-size: .9rem; white-space: nowrap; }
/* Below the width where the name and three theme buttons stop fitting, the
   name is the one that goes: it says who you are, which you know, and the
   buttons do something. */
@media (max-width: 34rem) { .pj-whoami { display: none; } }

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

.pj-chips { display: flex; flex-wrap: wrap; gap: .4rem; margin-bottom: 1.1rem; }
.pj-chips button {
  background: var(--panel); color: var(--dim); border: 1px solid var(--line);
  border-radius: 999px; padding: .3rem .8rem; cursor: pointer;
  font-family: inherit; font-size: .9rem;
}
.pj-chips button.on { color: var(--accent); border-color: var(--accent); }
/* The one chip not everybody has. Marked rather than merely present, because
   "why can Marc not see this button" is asked of every screen eventually and
   the answer should be on the screen. */
.pj-chips button.pj-privileged::after {
  content: "administrator";
  margin-left: .45rem; font-size: .7rem; color: var(--dim);
}

/* ----------------------------------------------------------------- board */

.pj-group { margin-bottom: 1.6rem; }
.pj-group > h2 {
  font-size: .75rem; letter-spacing: .08em; text-transform: uppercase;
  color: var(--dim); font-weight: 600; margin: 0 0 .5rem;
}

.pj-row {
  display: grid;
  grid-template-columns: .8rem 1fr auto;
  gap: .1rem .7rem;
  width: 100%;
  text-align: left;
  background: var(--panel); color: var(--text);
  border: 1px solid var(--line); border-radius: .6rem;
  padding: .7rem .9rem;
  margin-bottom: .45rem;
  cursor: pointer;
  font-family: inherit; font-size: 1em;
}
.pj-row:hover { border-color: var(--accent); }
.pj-row .dot { grid-row: 1; align-self: center; }
.pj-row .pj-name { font-weight: 600; }
.pj-row .pj-right { text-align: right; color: var(--dim); font-size: .9rem; white-space: nowrap; }
/* The second line of a row: everything that is not the name. On a phone the
   third column drops under the second rather than squeezing the name into
   two characters. */
.pj-row .pj-under {
  grid-column: 2 / -1; color: var(--dim); font-size: .9rem;
  display: flex; flex-wrap: wrap; gap: .15rem .8rem;
}
.pj-row .pj-late { color: var(--warn); }
@media (max-width: 34rem) {
  /* Two rows rather than one squeezed one. `style.css` gives the header a
     single flex line, which on a phone puts the theme buttons off the right
     edge — and they cannot simply be dropped here, because this app is served
     from its own port and therefore its own origin: the light-or-dark choice
     made in the chat is in the chat's `localStorage`, not this one's. */
  header { flex-wrap: wrap; }
  header .pj-spacer { margin-left: 0; }

  /* Name, then who and what is next, then the dates. Left as a two-column
     grid the dates landed *above* the owner, which is the least useful thing
     on the row sitting where the eye goes first. */
  .pj-row { grid-template-columns: .8rem 1fr; }
  .pj-row .pj-under { grid-column: 2; grid-row: 2; }
  .pj-row .pj-right { grid-column: 2; grid-row: 3; text-align: left; white-space: normal; }
}

.pj-empty { color: var(--dim); }

/* --------------------------------------------------------------- project */

.pj-back {
  background: none; border: 0; color: var(--accent); cursor: pointer;
  font-family: inherit; font-size: .95rem; padding: 0; margin-bottom: .8rem;
}

.pj-title { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; margin-bottom: .2rem; }
.pj-title h1 { font-size: 1.35rem; margin: 0; }
.pj-tag {
  font-size: .8rem; color: var(--dim);
  border: 1px solid var(--line); border-radius: 999px; padding: .1rem .6rem;
}
.pj-tag.pj-attention { color: var(--warn); border-color: var(--warn); }

.pj-dates { color: var(--dim); font-size: .9rem; margin: 0; }
/* Said in the register somebody would say it in, not shouted. `--warn` is
   already carrying the dot and the tag; a third thing in the same colour on
   the same screen stops meaning anything. */
/* Why a project is not fine, directly under its name — it says what the
   chip beside the name means, and a chip nobody can explain is ignored. */
.pj-why { margin: .1rem 0 .3rem; font-size: .85rem; }

.pj-done-when {
  background: var(--panel); border: 1px solid var(--line); border-radius: .6rem;
  padding: .8rem .9rem; margin: .9rem 0;
}
.pj-done-when b { display: block; font-size: .75rem; letter-spacing: .08em;
  text-transform: uppercase; color: var(--dim); margin-bottom: .2rem; }

.pj-block { margin-top: 1.6rem; }
.pj-block > h2 {
  font-size: .75rem; letter-spacing: .08em; text-transform: uppercase;
  color: var(--dim); font-weight: 600; margin: 0 0 .55rem;
  display: flex; align-items: baseline; gap: .8rem;
}
.pj-block > h2 .pj-add { margin-left: auto; color: var(--accent); font-size: .8rem;
  text-transform: none; letter-spacing: 0; }

.pj-team { display: flex; flex-wrap: wrap; gap: .4rem; }
.pj-person {
  border: 1px solid var(--line); border-radius: 999px; padding: .2rem .7rem;
  font-size: .9rem;
}
.pj-person .pj-role { color: var(--dim); font-size: .8rem; margin-left: .35rem; }

.pj-step { display: flex; gap: .6rem; align-items: baseline; padding: .35rem 0;
  border-bottom: 1px solid var(--line); }
.pj-step:last-child { border-bottom: 0; }
.pj-step .pj-box { color: var(--dim); }
.pj-step .pj-what { flex: 1; }
.pj-step.pj-done .pj-what { color: var(--dim); text-decoration: line-through; }
.pj-step .pj-who, .pj-step .pj-when { color: var(--dim); font-size: .9rem; white-space: nowrap; }
/* Which column a task is in, carried on its row in the project's list. Quiet:
   it is context for the title, not a second thing to read. */
.pj-lane {
  border: 1px solid var(--line); border-radius: 999px;
  padding: 0 .5rem; font-size: .78rem; color: var(--dim); white-space: nowrap;
}
.pj-step .pj-when.pj-late { color: var(--warn); }

.pj-note { display: grid; grid-template-columns: 5.5rem 1fr; gap: .2rem .8rem;
  padding: .55rem 0; border-bottom: 1px solid var(--line); }
.pj-note:last-child { border-bottom: 0; }
.pj-note .pj-at { color: var(--dim); font-size: .9rem; }
.pj-note .pj-by { grid-column: 2; color: var(--dim); font-size: .8rem; }
.pj-note .pj-body { grid-column: 2; }
@media (max-width: 34rem) {
  .pj-note { grid-template-columns: 1fr; }
  .pj-note .pj-by, .pj-note .pj-body { grid-column: 1; }
}

.pj-links { display: flex; flex-wrap: wrap; gap: .4rem; }
.pj-link {
  border: 1px solid var(--line); border-radius: .5rem; padding: .25rem .7rem;
  font-size: .9rem; color: var(--text); text-decoration: none;
}
.pj-link .pj-kind { color: var(--dim); margin-right: .4rem; }

/* ---------------------------------------------------------------- review */

.pj-review-lead { color: var(--dim); margin: 0 0 1.4rem; }
.pj-review-lead b { color: var(--text); font-weight: 600; }

/* ============================================================== the board ==
 *
 * Columns, and cards dragged between them.
 *
 * **Pointer events rather than HTML5 drag-and-drop**, which is the whole
 * reason this is fifty lines instead of ten. The `dragstart`/`drop` API does
 * not fire on a touch screen at all — the feature would have worked at a desk
 * and silently not existed on the phone half the people here use. Pointer
 * events are one code path for both, and the cost is drawing the moving card
 * ourselves.
 */

/* Wide views scroll sideways inside themselves rather than making the page do
   it: a board with nine columns must not put the header out of reach. */
.pj-wide { max-width: none; }

.pj-boardbar {
  display: flex; flex-wrap: wrap; gap: .5rem; align-items: center;
  margin-bottom: 1rem;
}
.pj-boardbar select, .pj-boardbar button {
  background: var(--panel); color: var(--text); border: 1px solid var(--line);
  border-radius: .5rem; padding: .3rem .7rem; cursor: pointer;
  font-family: inherit; font-size: .9rem;
}
.pj-boardbar .pj-spacer { margin-left: auto; }

.pj-columns {
  display: flex; gap: .8rem; align-items: flex-start;
  overflow-x: auto; padding-bottom: .5rem;
}
.pj-column {
  flex: 0 0 17rem; display: flex; flex-direction: column; gap: .45rem;
  background: var(--panel); border: 1px solid var(--line); border-radius: .6rem;
  padding: .6rem; min-height: 6rem;
  /* `Done` accumulates for ever. Left unbounded it ran off the bottom of the
     screen and took the board's own sideways scrollbar out of reach with it. */
  max-height: min(34rem, calc(100dvh - 16rem));
  overflow-y: auto;
}
/* Where the card would land. Marked on the column rather than by moving the
   real cards around, so nothing reflows under the pointer while you aim. */
.pj-column.pj-over { border-color: var(--accent); }
.pj-column > h2 {
  font-size: .75rem; letter-spacing: .08em; text-transform: uppercase;
  color: var(--dim); font-weight: 600; margin: 0 0 .1rem;
  display: flex; gap: .5rem;
  /* Which column you are dropping into has to stay readable while its cards
     scroll past. */
  position: sticky; top: 0; z-index: 1;
  background: var(--panel); padding-bottom: .25rem;
}
.pj-column > h2 .pj-count { margin-left: auto; font-variant-numeric: tabular-nums; }

.pj-card {
  background: var(--bg); border: 1px solid var(--line); border-radius: .5rem;
  padding: .5rem .6rem; cursor: grab;
  display: flex; flex-direction: column; gap: .2rem;
  /* Or the browser scrolls the column instead of moving the card. */
  touch-action: none;
}
.pj-card:hover { border-color: var(--accent); }
.pj-card .pj-card-title { font-size: .95rem; }
.pj-card .pj-card-meta {
  display: flex; flex-wrap: wrap; gap: .1rem .6rem;
  color: var(--dim); font-size: .8rem;
}
.pj-card .pj-late { color: var(--warn); }
/* The card under the pointer, drawn at the cursor. `fixed` so a column that
   scrolls does not drag it out of line. */
.pj-card.pj-lifted {
  position: fixed; z-index: 40; pointer-events: none;
  width: 15.8rem; box-shadow: 0 .6rem 1.4rem rgba(0, 0, 0, .35);
  border-color: var(--accent); cursor: grabbing;
}
/* The hole it came out of, so the column does not close up and re-open under
   the pointer while it is being aimed. */
.pj-slot {
  border: 1px dashed var(--line); border-radius: .5rem; height: 3.2rem;
}
.pj-milestone-chip {
  border: 1px solid var(--line); border-radius: 999px;
  padding: 0 .45rem; font-size: .75rem; color: var(--dim);
}

/* ============================================================ the timeline =
 *
 * Percentages against one scale, so a bar, a diamond, a month band and the
 * line for today cannot disagree about where a date is. The whole thing has a
 * `min-width` and scrolls inside itself: squeezing a quarter into a phone
 * produces a chart with no readable dates on it.
 */

.pj-gantt-scroll { overflow-x: auto; padding-bottom: .5rem; }
.pj-gantt { min-width: 46rem; }

.pj-gantt-row { display: grid; grid-template-columns: 15rem 1fr; align-items: center; }
/* Pinned, because the chart opens at today and scrolls. Without this the
   names scroll off to the left and what is left is a wall of bars belonging
   to nobody — which is exactly what a phone showed. */
.pj-gantt-label {
  font-size: .9rem; padding: .35rem .7rem .35rem 0; line-height: 1.25;
  position: sticky; left: 0; z-index: 2;
  background: var(--bg);
}
.pj-gantt-label.pj-sub { padding-left: 1rem; color: var(--dim); font-size: .85rem; }
/* `var(--bg)`, not `none`: a clickable row label is the sticky cell the bars
   scroll underneath, and `background: none` let them run straight through the
   project's name. */
button.pj-gantt-label {
  background: var(--bg); border: 0; color: var(--text); text-align: left;
  cursor: pointer; font-family: inherit;
}
button.pj-gantt-label:hover { color: var(--accent); }

/* `overflow: hidden` is belt to the clamp's braces. Anything absolutely
   positioned in here with a negative offset otherwise escapes into the sticky
   label column beside it and widens the scroll container — which is what the
   month labels were doing. */
.pj-gantt-track {
  position: relative; height: 2rem; border-left: 1px solid var(--line);
  overflow: hidden;
}
.pj-gantt-head .pj-gantt-track { height: 2.2rem; }
.pj-gantt-head .pj-gantt-label { background: var(--bg); }

.pj-gantt-month {
  position: absolute; top: 0; bottom: 0;
  border-left: 1px solid var(--line);
  font-size: .75rem; color: var(--dim); padding-left: .3rem;
  /* Top, so the `today` marker can have the bottom. They were both centred
     and overlapped into "Septtodayber" whenever today fell early in a month. */
  display: flex; align-items: flex-start; overflow: hidden;
}
/* Faint, and behind everything: this is a ruler, not a series. */
.pj-gantt-grid { position: absolute; top: 0; bottom: 0; border-left: 1px solid var(--line); opacity: .5; }

.pj-gantt-bar {
  position: absolute; top: 50%; transform: translateY(-50%);
  height: 1.1rem; border-radius: .3rem;
  background: var(--accent); opacity: .55;
  min-width: 2px;
}
.pj-gantt-bar.pj-attention { background: var(--warn); opacity: .7; }
.pj-gantt-bar.pj-done { background: var(--dim); opacity: .35; }

.pj-gantt-diamond {
  position: absolute; top: 50%; width: .6rem; height: .6rem;
  transform: translate(-50%, -50%) rotate(45deg);
  background: var(--text); border: 1px solid var(--bg);
}
.pj-gantt-diamond.pj-attention { background: var(--warn); }
.pj-gantt-diamond.pj-done { background: var(--dim); }

/* Today, drawn over everything, because "are we behind" is the question the
   chart is open to answer. */
.pj-gantt-today {
  position: absolute; top: 0; bottom: 0; width: 0;
  border-left: 1px solid var(--accent);
}
.pj-gantt-today.pj-labelled::after {
  content: "today"; position: absolute; bottom: -.1rem; left: .25rem;
  font-size: .7rem; color: var(--accent); background: var(--bg); padding: 0 .15rem;
  /* Flipped to the left of the line when today is near the right-hand end, so
     the word is not cut off by the track's overflow. */
  white-space: nowrap;
}
.pj-gantt-today.pj-labelled.pj-flip::after { left: auto; right: .25rem; }

.pj-gantt-note { color: var(--dim); font-size: .85rem; margin: .5rem 0 0; }

/* ================================================================= dialogs = */

dialog#pj-columns-dialog {
  background: var(--panel); color: var(--text);
  border: 1px solid var(--line); border-radius: .7rem;
  padding: 1.1rem; max-width: 26rem; width: calc(100% - 2rem);
}
dialog#pj-columns-dialog::backdrop { background: rgba(0, 0, 0, .5); }
dialog#pj-columns-dialog h2 { margin: 0 0 .4rem; font-size: 1.05rem; }
.pj-dim { color: var(--dim); font-size: .85rem; margin: 0 0 .9rem; }

.pj-column-edit { display: flex; gap: .4rem; align-items: center; margin-bottom: .4rem; }
.pj-column-edit input {
  flex: 1; background: var(--bg); color: var(--text);
  border: 1px solid var(--line); border-radius: .4rem;
  padding: .3rem .5rem; font-family: inherit; font-size: .9rem;
}
/* Scoped by the dialog's id, and it has to be: `dialog button:not(.quiet)` in
   `style.css` is the primary-action look and outranks a bare class selector,
   so an earlier version of this rule lost and these came out as five solid
   accent slabs. An id plus a class plus a type beats it. */
#pj-columns-dialog .pj-column-edit button {
  background: var(--panel); color: var(--dim); border: 1px solid var(--line);
  border-radius: .4rem; padding: .2rem .5rem; cursor: pointer;
  font-family: inherit; font-size: .9rem;
}
#pj-columns-dialog .pj-column-edit button:hover { color: var(--text); border-color: var(--accent); }

.pj-dialog-actions { display: flex; gap: .5rem; margin-top: .9rem; }
/* `Done` keeps the accent fill `style.css` gives a dialog's primary action, and
   `+ add a column` carries that file's `quiet` class for the secondary one. An
   earlier version overrode the colour here and painted accent text on the
   accent fill: a button with nothing on it. */
#pj-columns-dialog .pj-dialog-actions #pj-columns-close { margin-left: auto; }

/* One person, then their switches. A row of small buttons rather than
   checkboxes, because what they say is what pressing them will leave true, and
   a checkbox needs a label beside it saying the same thing twice.

   Scoped by the dialog's id for the reason the column editor is: the
   primary-action fill in `style.css` outranks a bare class selector, and these
   would otherwise come out as four accent slabs each. */
dialog#pj-people-dialog {
  background: var(--panel); color: var(--text);
  border: 1px solid var(--line); border-radius: .7rem;
  padding: 1.1rem; max-width: 30rem; width: calc(100% - 2rem);
}
dialog#pj-people-dialog::backdrop { background: rgba(0, 0, 0, .5); }
dialog#pj-people-dialog h2 { margin: 0 0 .4rem; font-size: 1.05rem; }
.pj-person-edit {
  padding: .5rem 0;
  border-top: 1px solid var(--line);
}
.pj-person-edit:first-child { border-top: 0; }
.pj-person-head { display: flex; gap: .5rem; align-items: baseline; }
.pj-person-edit .pj-who { flex: 1; font-weight: 600; }
/* The four switches, wrapping as a group beneath the name. `nowrap` on each
   is what stops "may be invited" breaking across two lines and reading as two
   separate things. */
.pj-switches {
  display: flex; flex-wrap: wrap; gap: .3rem .9rem; margin-top: .35rem;
}
#pj-people-dialog .pj-person-edit button {
  background: var(--panel); color: var(--dim); border: 1px solid var(--line);
  border-radius: .4rem; padding: .2rem .5rem; cursor: pointer;
  font-family: inherit; font-size: .85rem;
}
#pj-people-dialog .pj-person-edit button:hover { border-color: var(--dim); }

/* A box and its words are one target, so the label is clickable — the words
   are the bigger half of it and missing them is the commonest way a checkbox
   feels broken. */
.pj-switch {
  display: inline-flex; align-items: center; gap: .3rem;
  font-size: .85rem; color: var(--dim); cursor: pointer;
  white-space: nowrap;
}
.pj-switch input { accent-color: var(--accent); margin: 0; cursor: pointer; }
.pj-switch:hover { color: var(--text); }
.pj-switch input:disabled { cursor: progress; }
/* Ticked, the words come forward. Off, they sit back — so the row can be read
   at a glance as "what is true about this person" rather than as four labels
   of equal weight. */
.pj-switch:has(input:checked) { color: var(--text); }
#pj-people-dialog .pj-dialog-actions #pj-people-close { margin-left: auto; }
/* A code shown once. Monospaced and spaced out, because it is read down a
   phone as often as it is pasted. */
#pj-people-code { margin: .8rem 0 0; font-size: .9rem; }
.pj-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 1.05rem; letter-spacing: .12em;
  background: var(--bg); border: 1px solid var(--line); border-radius: .4rem;
  padding: .15rem .45rem; color: var(--accent); user-select: all;
}
/* The small button on a person's row that mints one. Scoped by the dialog's
   id for the reason the switches beside it are: the primary-action fill in
   `style.css` outranks a bare class selector. */
#pj-people-dialog .pj-person-edit button.pj-plain {
  color: var(--dim); border-style: dashed;
}
/* Warm rather than red. Taking somebody off is reversible in the sense that
   matters — they can be added back and the history never named a row in
   `people` — so this is not the colour of something you cannot undo. It is
   just not the colour of `code` either. */
#pj-people-dialog .pj-person-edit button.pj-remove:hover {
  color: var(--warn); border-color: var(--warn);
}

/* ============================================================== the middle =
 * A project's own description, which is a paragraph rather than the one
 * sentence beside it.
 */
/* A task listed under the milestone it leads to. Indented and a shade back, so
   the milestone reads as the heading it now is. */
.pj-step.pj-under { padding-left: 1.6rem; }
.pj-step.pj-under .pj-what { color: var(--dim); }
.pj-step.pj-milestone .pj-what { font-weight: 600; }
/* The diamond is a control now. Same size and place as the span it replaces,
   so nothing shifts when somebody may not press it. */
button.pj-box.pj-mark {
  background: none; border: 0; padding: 0; cursor: pointer;
  color: inherit; font: inherit;
}
button.pj-box.pj-mark:hover { color: var(--accent); }
/* `+ task` on a milestone's own line, and the two links to this project's
   other screens. Quiet: they are always there, and a row of accent buttons
   down the page would compete with the work. */
.pj-step .pj-add { margin-left: .5rem; }

/* One row of things to press, under one line of facts. Buttons wedged into
   running text stop the line reading as a line. */
.pj-elsewhere {
  display: flex; flex-wrap: wrap; align-items: center; gap: .4rem;
  margin: .5rem 0 1.1rem;
}
.pj-elsewhere .pj-spacer { flex: 1; }
.pj-elsewhere button {
  background: none; border: 1px solid var(--line); color: var(--dim);
  border-radius: .4rem; padding: .15rem .6rem; cursor: pointer;
  font-family: inherit; font-size: .85rem;
}
.pj-elsewhere button:hover { color: var(--accent); border-color: var(--accent); }
/* The one that ends something. Warm on hover only — it is a button you press
   deliberately, not one to be wary of at rest. */
.pj-elsewhere button.pj-retire:hover { color: var(--warn); border-color: var(--warn); }

/* A title you can press to change. It has to read as the text it replaces, or
   every line on the page turns into a row of buttons. */
button.pj-what.pj-editable {
  background: none; border: 0; padding: 0; margin: 0; cursor: pointer;
  color: inherit; font: inherit; text-align: left;
}
button.pj-what.pj-editable:hover { color: var(--accent); }
/* The disclosure on a milestone: how many tasks, and whether they are showing.
   Doubles as the count, so a shut milestone still says how much is under it. */
button.pj-open {
  background: none; border: 1px solid var(--line); color: var(--dim);
  border-radius: 999px; padding: 0 .45rem; cursor: pointer;
  font-family: inherit; font-size: .75rem;
}
button.pj-open:hover { color: var(--accent); border-color: var(--accent); }
/* Held open for a milestone with nothing under it, so the titles down the
   column still line up with the ones that have a count. */
.pj-open { display: inline-block; min-width: 2.4rem; text-align: center; }
.pj-empty-open { border: 1px solid transparent; }

/* The whole row opens it — a three-character target at one end of a wide line
   is a target you miss. */
.pj-step.pj-openable { cursor: pointer; }
.pj-step.pj-openable:hover { background: var(--panel); }

/* Editing behind a pencil, so the title can stay a title. An editable title
   and a clickable row are two meanings for the same pixels. */
button.pj-pencil {
  background: none; border: 0; padding: 0 .35rem; cursor: pointer;
  color: var(--line); font: inherit; font-size: .85rem;
}
.pj-step:hover button.pj-pencil { color: var(--dim); }
button.pj-pencil:hover { color: var(--accent); }

/* Which project a task belongs to, when the list spans them. */
button.pj-tag.pj-of { cursor: pointer; font-size: .75rem; }
button.pj-tag.pj-of:hover { color: var(--accent); border-color: var(--accent); }

/* A chip that is a control. It must read as the chip it replaces, or the
   title turns into a row of buttons. */
button.pj-tag { cursor: pointer; font: inherit; }
button.pj-tag:hover { color: var(--accent); border-color: var(--accent); }

/* ================================================================ reports = */

.pj-reports { max-height: 22rem; overflow-y: auto; }
.pj-report { border-top: 1px solid var(--line); padding: .5rem 0; }
.pj-report:first-child { border-top: 0; }
.pj-report.pj-done { opacity: .55; }
.pj-report-head {
  display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap;
  font-size: .8rem; color: var(--dim);
}
.pj-report-head .pj-spacer { flex: 1; }
/* `done` is a quiet thing to press on one line of a list, not the dialog's
   primary action — but `dialog button:not(.quiet)` in `style.css` paints every
   button in here blue and outranks a bare class, so it is said again by id. */
#pj-ask .pj-report-head .pj-plain {
  background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--accent); font-family: inherit; font-size: .8rem;
}
.pj-report .pj-body { margin: .25rem 0 0; white-space: pre-wrap; color: var(--dim); }
.pj-report code {
  font-size: .75rem; background: var(--bg); border: 1px solid var(--line);
  border-radius: .3rem; padding: 0 .3rem;
}

.pj-about { margin: .9rem 0; max-width: 46rem; }
.pj-about p { margin: 0; }

@media (max-width: 34rem) {
  .pj-gantt-row { grid-template-columns: 8rem 1fr; }
  .pj-column { flex-basis: 14rem; }
  .pj-card.pj-lifted { width: 12.8rem; }
}

/* A count beside a heading, as opposed to something you can do. */
.pj-block > h2 .pj-tally {
  margin-left: auto; color: var(--dim); font-size: .8rem;
  text-transform: none; letter-spacing: 0;
}

/* A refusal from the server, shown where the person is looking rather than in
   a dialog they have to dismiss. */
.pj-says {
  flex: none; padding: .5rem 1rem; color: var(--warn);
  border-bottom: 1px solid var(--line); background: var(--panel); font-size: .9rem;
}

/* The one form dialog. Same furniture as the column editor, and scoped by id
   for the same reason: `dialog button:not(.quiet)` in `style.css` is the
   primary-action look and outranks a bare class selector. */
dialog#pj-ask {
  background: var(--panel); color: var(--text);
  border: 1px solid var(--line); border-radius: .7rem;
  padding: 1.1rem; max-width: 30rem; width: calc(100% - 2rem);
}
dialog#pj-ask::backdrop { background: rgba(0, 0, 0, .5); }
dialog#pj-ask h2 { margin: 0 0 .4rem; font-size: 1.05rem; }

.pj-field { display: block; margin-bottom: .7rem; }
.pj-field > span {
  display: block; font-size: .78rem; letter-spacing: .06em;
  text-transform: uppercase; color: var(--dim); margin-bottom: .2rem;
}
.pj-field input, .pj-field textarea, .pj-field select {
  width: 100%; background: var(--bg); color: var(--text);
  border: 1px solid var(--line); border-radius: .4rem;
  padding: .4rem .55rem; font-family: inherit; font-size: .95rem;
}
.pj-field textarea { min-height: 5rem; resize: vertical; }
/* Small print, wherever in the dialog it is. It used to be styled only inside
   a field, so the same class on a line of its own — the instruction under a
   sign-in code, say — came out at body size and read as the message. */
#pj-ask .pj-hint {
  text-transform: none; letter-spacing: 0; font-size: .8rem; color: var(--dim);
}
.pj-field .pj-hint { margin-top: .25rem; }
.pj-ask-error { color: var(--warn); font-size: .85rem; margin: 0 0 .6rem; }

/* Which queue a report belongs in, asked as three cards rather than a select.
   It is the first question and the one people answer wrongly when it is a list
   they have to open — the whole choice is on screen, with what each one means
   written under it. Each card is a real `<input type=radio>` in a `<label>`,
   so the arrow keys work and this is one control rather than three buttons. */
.pj-cards { display: grid; gap: .4rem; grid-template-columns: 1fr; }
@media (min-width: 30rem) {
  .pj-cards { grid-template-columns: repeat(3, 1fr); }
}
.pj-card {
  display: block; cursor: pointer; background: var(--bg);
  border: 1px solid var(--line); border-radius: .5rem; padding: .5rem .6rem;
}
.pj-card:hover { border-color: var(--dim); }
.pj-card.on { border-color: var(--accent); background: var(--panel); }
/* The radio itself is off screen rather than `display: none`, which would take
   it out of the tab order and off the arrow keys with it. */
.pj-card input {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.pj-card input:focus-visible + .pj-card-name { text-decoration: underline; }
.pj-card-name { display: block; font-size: .9rem; }
.pj-card-said {
  display: block; font-size: .78rem; color: var(--dim); margin-top: .15rem;
  text-transform: none; letter-spacing: 0;
}
/* What goes with the report, said before the button rather than after. */
.pj-sent-as { margin: 0 0 .7rem; }
/* A report's own headline, which is what an administrator reads down. */
.pj-summary { margin: .3rem 0 0; font-size: .95rem; }

/* What a guest's link looks like when it comes back: selectable, wrapping, and
   obviously a thing to copy rather than to read. */
.pj-link-out {
  display: block; width: 100%; background: var(--bg); color: var(--text);
  border: 1px solid var(--accent); border-radius: .4rem;
  padding: .5rem; font-family: ui-monospace, monospace; font-size: .8rem;
  overflow-wrap: anywhere;
}

/* A `+` in a heading that does something. A button, so it is reachable from a
   keyboard, painted as the text it replaced. */
.pj-add.pj-plain {
  background: none; border: 0; padding: 0; cursor: pointer;
  color: var(--accent); font-family: inherit; font-size: .8rem;
  text-transform: none; letter-spacing: 0;
}
.pj-chips .pj-doer { color: var(--accent); border-color: var(--accent); }
.pj-chips .pj-spacer { margin-left: auto; }

/* The guest's invitation, laid out like the gate it stands in for. Not the
   gate itself: they are not signing in, they are being told what they have
   been invited to — and the copy, the button and what happens next all differ.
   `.gate-card` inside it is `style.css`'s, deliberately shared, so the two
   screens a person meets before they are anybody look like one product. */
#pj-join {
  position: fixed; inset: 0; z-index: 10; display: flex;
  align-items: center; justify-content: center; padding: 1rem;
  background: var(--bg);
}
#pj-join[hidden] { display: none; }
#pj-join-error:not(:empty) { margin-top: .8rem; color: var(--warn); }
