/* A thin layer on top of pico.css defaults. */

/* --- sitewide scale -------------------------------------------------- */
/* Everything is drawn at 80% of pico's own size. pico sizes the whole
   interface off the root font size, which it steps up at each breakpoint,
   so scaling that one variable takes the type, the spacing, the form
   controls and the rounding with it - which is what keeps the proportions
   the same rather than only making the words smaller. Each value here is
   80% of pico's at the same width. */
:root { --pico-font-size: 80%; }
@media (min-width: 576px)  { :root { --pico-font-size: 85%; } }
@media (min-width: 768px)  { :root { --pico-font-size: 90%; } }
@media (min-width: 1024px) { :root { --pico-font-size: 95%; } }
@media (min-width: 1280px) { :root { --pico-font-size: 100%; } }
@media (min-width: 1536px) { :root { --pico-font-size: 105%; } }

/* --- navbar --------------------------------------------------------- */
/* The collapsing menu and theme toggle follow the pattern used on
   https://cgi.cse.unsw.edu.au/~cs6420/, with the click handlers bound in
   app.js rather than inline, which the Content-Security-Policy forbids. */
/* A solid accent bar under the navbar, in the style of the COMP6420 site. */
header > nav {
    margin-bottom: 1.25rem;
    padding: .25rem .6rem;
    border-bottom: 8px solid var(--pico-primary);
    box-shadow: 0 4px 6px rgba(0, 0, 0, .1);
    line-height: 1.2;
    align-items: center;
}
header > nav li { display: flex; align-items: center; }

/* --- the wordmark ---------------------------------------------------- */
/* The logo is one SVG, drawn by scripts/makelogo.py and inlined by the
   template rather than linked, so currentColor below reaches it and one file
   serves both themes. The words are outlines, not text in a webfont: nothing
   to download, nothing to lay out, and the same shapes wherever the file is
   opened.
   Its own width and height attributes are what it falls back to on its own;
   here the height is set and the width follows the viewBox. */
.brand {
    display: inline-flex;
    align-items: center;
    /* In off the edge of the page, so the mark has room to be a mark rather
       than something jammed into the corner. */
    margin-left: .55rem;
    /* The accent colour, which is what the bar under the navbar is drawn in.
       Not var(--pico-color): pico redefines that on an anchor to mean the
       link colour, so asking for it would quietly hand back the accent
       anyway. Naming it outright says what is meant. */
    color: var(--pico-primary);
    text-decoration: none;
    transition: color .2s ease-in-out;
}
.brand svg { display: block; height: 3.1rem; width: auto; }
.brand:hover { color: var(--pico-primary-hover); }


/* Everything in the navbar sits on one line, including the sign-out button,
   which pico would otherwise render at full form-control height. */
header > nav form { margin: 0; display: flex; align-items: center; }
.sign-out { width: auto; margin: 0; padding: .3rem .7rem; font-size: .8rem; }
header > nav li.who { color: var(--pico-muted-color); font-size: .9rem; }

/* Nothing in the navbar wraps inside itself. A squeezed "Sign out" breaking
   across two lines, or a dropdown's chevron dropping below the name it
   belongs to, makes the bar look broken well before it has actually run out
   of room; the menu collapses behind the hamburger instead, at the width
   where the row stops fitting. */
#nav-menu > li, #nav-menu .dropdown > summary, .sign-out { white-space: nowrap; }

.hamburger { display: none; background: none; border: 1px solid var(--pico-muted-border-color);
             border-radius: .3rem; cursor: pointer; margin: 0 .25rem 0 auto; padding: .5rem .6rem;
             width: auto; flex-direction: column; justify-content: space-around; align-items: center; }
.hamburger span { display: block; width: 1.5rem; height: 2px; margin: .2rem 0; border-radius: 2px;
                  background-color: var(--pico-muted-color); transition: all .3s ease; }
.hamburger:hover span { background-color: var(--pico-contrast); }

.theme-toggle { display: flex; align-items: center; justify-content: center; background: none;
                border: none; box-shadow: none; cursor: pointer; color: currentColor; width: auto;
                margin: 0; padding: .5rem; transition: opacity .3s ease; }
.theme-toggle:hover { opacity: .7; background: none; }
.theme-toggle svg { stroke: currentColor; }

nav .dropdown { margin: 0; }
nav .dropdown ul { min-width: 14rem; max-height: 70vh; overflow-y: auto; }
nav .dropdown ul li { padding-block: .25rem; }
#nav-menu .view-actions { display: block; }

/* A long project name takes the project menu's own name, so it is capped
   rather than allowed to push the rest of the bar off the page.

   The cap goes on the name inside the summary rather than on the summary
   itself. pico draws the chevron as a right-floated ::after, and a float on a
   nowrap line is laid out after the text it follows: with the clipping on the
   summary, a name long enough to overflow took the chevron over the edge with
   it and the arrow was cut in half. Making the summary a flex row puts the
   name and the chevron side by side, so only the name is ever shortened. */
#nav-menu .dropdown > summary { display: flex; align-items: center; max-width: 14rem; }
#nav-menu .dropdown > summary > .menu-label {
    min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#nav-menu .dropdown > summary::after { float: none; flex: 0 0 auto; }

/* The hamburger takes over while the row still fits comfortably. pico's
   container steps down at 1024px, and below that the bar has less room than
   it needs; collapsing here rather than at 900px is what keeps the band
   between them from looking broken. */
@media (max-width: 1023px) {
    .hamburger { display: flex; }
    nav { flex-wrap: wrap; }
    #nav-menu { order: 3; width: 100%; display: none; flex-direction: column; align-items: stretch; }
    #nav-menu.open { display: flex; }
    #nav-menu > li { width: 100%; }
    nav ul:first-of-type { flex-grow: 1; }
    nav .dropdown ul { position: static; width: 100%; }
}

/* --- the to-do tree ------------------------------------------------ */
.todo-tree, .todo-children { list-style: none; padding-left: 0; margin: 0; }
/* pico styles list markers on the li, so clearing it on the ul is not enough. */
.todo-tree li { list-style: none; }
.todo-tree li::marker { content: ""; }
.todo-children { padding-left: 1.1rem; margin-left: .55rem;
                 border-left: 1px solid var(--pico-muted-border-color); }

.todo-row { display: flex; gap: .5rem; align-items: baseline;
            padding: .2rem .3rem; border-radius: .3rem; }
.todo-row:hover { background: var(--pico-code-background-color); }
.todo-row.resolved .todo-text { text-decoration: line-through; opacity: .55; }

/* --- a deleted to-do, in the view only an admin can ask for ----------
   It is faded rather than struck through: the strike already means "finished"
   on the row above it, and a deleted to-do is neither. The tools are gone
   except the one that puts it back, so the row reads as a record of
   something rather than as work in hand. */
.todo-row.deleted { opacity: .72; }
.todo-row.deleted .todo-text { font-style: italic; }
.todo-row.deleted .todo-ref { color: var(--pico-muted-color); cursor: default; }
.todo-row.deleted:hover { background: var(--pico-code-background-color); }
.status-deleted { flex: none; width: 1.6rem; text-align: center; filter: grayscale(1); }
.badge.deleted-at { background: var(--pico-muted-border-color); color: var(--pico-muted-color); }
.went-with { font-size: .72em; white-space: nowrap; }
.tool.restore { opacity: 1; }
/* The tools on an ordinary row appear on hover; this one is always there,
   since it is the only thing the row offers. */
.todo-row.deleted .todo-tools { opacity: 1; visibility: visible; }
.sort-filter, .completed-filter, .deleted-filter { margin-top: .6rem; }
/* --- rearranging the list ------------------------------------------
   The grip is faint until the row is under the pointer or holds the focus:
   there is one on every row, so at full strength a dozen of them would read
   as a column of their own down the left of the list. */
.drag-handle {
    flex: none; align-self: center; width: 1rem; padding: 0; margin: 0;
    background: none; border: none; box-shadow: none; line-height: 1;
    font-size: .95em; color: var(--pico-muted-color); opacity: .3;
    cursor: grab; touch-action: none;
}
.todo-row:hover .drag-handle, .drag-handle:focus-visible { opacity: 1; }
.drag-handle:focus-visible { outline: 2px solid var(--pico-primary); border-radius: .2rem; }
.drag-handle:active { cursor: grabbing; }
/* The deleted rows have no grip - there is no list to move them about in -
   so they carry the same gap instead, to stay in line with the rest. */
.drag-handle.spacer { visibility: hidden; cursor: default; }
/* A view read by due date is not in an order anybody set, so there is
   nothing in it to rearrange. */
.fixed-order .drag-handle { display: none; }

.todo.dragging > .todo-row { opacity: .4; }
/* Where the row would land: a line above or below it, or the row itself
   ringed when the drop would tuck the dragged one underneath it. */
.todo-row.drop-before { box-shadow: inset 0 2px 0 0 var(--pico-primary); }
.todo-row.drop-after { box-shadow: inset 0 -2px 0 0 var(--pico-primary); }
.todo-row.drop-inside {
    outline: 2px dashed var(--pico-primary); outline-offset: -2px;
    background: var(--pico-primary-background); color: var(--pico-primary-inverse);
}

/* The place to let go of a sub-to-do that is being brought out to a list of
   its own. It is only in the page while something is being dragged. */
.drop-root {
    margin-top: .5rem; padding: .5rem .6rem; border-radius: .3rem;
    border: 1px dashed var(--pico-muted-border-color);
    color: var(--pico-muted-color); font-size: .8em; text-align: center;
}
.drop-root.drop-here {
    border-color: var(--pico-primary); border-style: solid;
    color: var(--pico-primary);
}

/* --- the four-state checkbox ---------------------------------------- */
.status-picker { margin: 0; flex: none; position: relative; }
/* pico styles summaries as list items, and any [role=button] as a full-width
   button, so the box has to state its own shape. */
.status-picker > summary {
    display: inline-flex; align-items: center; justify-content: center;
    width: 1.25rem; min-width: 1.25rem; height: 1.25rem; padding: 0; margin: 0;
    box-sizing: border-box;
    border: 1px solid var(--pico-form-element-border-color);
    border-radius: .25rem; background: var(--pico-form-element-background-color);
    font-size: .85rem; line-height: 1; cursor: pointer; list-style: none;
}
/* An open to-do's box holds no symbol, and an empty box has no baseline to
   offer the row: flexbox then lines its bottom edge up with the text's
   baseline, which leaves the words sitting half a line low against it. A
   zero-width space gives every state the baseline the tick already has, so
   the box sits on the line of the text it belongs to. */
.status-picker > summary::before { content: "\200b"; }
.status-picker > summary::after { display: none; content: none; }
.status-picker > summary::marker { content: ""; }
.status-picker > summary::-webkit-details-marker { display: none; }
.status-picker > summary:hover { border-color: var(--pico-primary); }
.status-picker[open] > summary { border-color: var(--pico-primary); }

/* pico colours a plain summary through `details summary:not([role])`, which
   outranks a single class, so the box states its colour more specifically. */
.status-done, .status-picker > summary.status-done { color: #2e7d32; }
.status-warn, .status-picker > summary.status-warn { color: #a06800; }
.status-blocked, .status-picker > summary.status-blocked { color: #c62828; }
:root[data-theme="dark"] .status-done,
:root[data-theme="dark"] .status-picker > summary.status-done { color: #66bb6a; }
:root[data-theme="dark"] .status-warn,
:root[data-theme="dark"] .status-picker > summary.status-warn { color: #ffca28; }
:root[data-theme="dark"] .status-blocked,
:root[data-theme="dark"] .status-picker > summary.status-blocked { color: #ef5350; }

/* A wash of the symbol's own colour behind it, so a glance down the list
   reads as colour before it reads as shape. Pale enough that the symbol and
   the border still carry the meaning. */
.status-picker > summary.status-done { background: #e7f4e8; }
.status-picker > summary.status-warn { background: #fdf4e0; }
.status-picker > summary.status-blocked { background: #fbeceb; }
:root[data-theme="dark"] .status-picker > summary.status-done { background: rgba(102, 187, 106, .16); }
:root[data-theme="dark"] .status-picker > summary.status-warn { background: rgba(255, 202, 40, .16); }
:root[data-theme="dark"] .status-picker > summary.status-blocked { background: rgba(239, 83, 80, .16); }

.status-picker > ul {
    position: absolute; z-index: 10; left: 0; top: 1.6rem; min-width: 11rem;
    list-style: none; padding: .25rem; margin: 0;
    background: var(--pico-card-background-color); border-radius: .35rem;
    border: 1px solid var(--pico-muted-border-color);
    box-shadow: 0 4px 10px rgba(0, 0, 0, .18);
}
.status-picker > ul li { margin: 0; }
/* pico redefines --pico-color to its button text colour inside a button, so
   the label has to inherit the page colour instead of using that variable. */
.status-choice {
    display: flex; align-items: center; gap: .5rem; width: 100%; margin: 0;
    padding: .3rem .45rem; border: none; background: none; box-shadow: none;
    color: inherit; font-size: .85rem; text-align: left; cursor: pointer;
}
.status-picker > ul { color: var(--pico-color); }
.status-choice:hover, .status-choice:focus { background: var(--pico-secondary-background); }
.status-choice.chosen { font-weight: 600; }
.status-choice .status { width: 1rem; display: inline-block; text-align: center; }
.todo-text { flex: 0 1 auto; }
.todo-badges { display: inline-flex; flex-wrap: wrap; gap: .3rem; align-items: baseline;
               flex: 1 1 auto; min-width: 0; }

/* The row's own buttons sit on the right and stay out of the way until the
   row is hovered or something in it has focus. */
.todo-tools { display: inline-flex; gap: .1rem; flex: none; margin-left: auto;
              opacity: 0; transition: opacity .12s ease-in-out; }
.todo-row:hover .todo-tools,
.todo-row:focus-within .todo-tools { opacity: 1; }
@media (hover: none) { .todo-tools { opacity: 1; } }

.tool { background: none; border: none; box-shadow: none; cursor: pointer;
        width: auto; margin: 0; padding: .1rem .25rem; line-height: 1.1;
        font-size: .95rem; border-radius: .3rem; color: inherit; }
.tool:hover, .tool:focus { background: var(--pico-secondary-background); }
.tool.add { font-weight: 700; }

/* --- badges -------------------------------------------------------- */
.badge { font-size: .72em; padding: .1rem .4rem; border-radius: .4rem; white-space: nowrap;
         background: var(--pico-secondary-background); color: var(--pico-secondary-inverse);
         text-decoration: none; border: none; }
.badge.tag { background: var(--pico-primary-background); color: var(--pico-primary-inverse); }
.badge.due.overdue { background: var(--pico-del-color, #b3261e); color: #fff; }
.badge.private { background: var(--pico-contrast-background); color: var(--pico-contrast-inverse); }
button.badge { cursor: pointer; width: auto; margin: 0; }

/* --- compose lines -------------------------------------------------- */
.compose { display: flex; gap: .35rem; align-items: center; margin: .35rem 0; }
.compose input[type=text] { flex: 1 1 auto; width: auto; min-width: 0; margin: 0; }
.compose .tool { flex: 0 0 auto; width: auto; }
.compose.root { margin-top: .75rem; }
.compose.child { padding-left: 1.65rem; }
.compose-slot:empty { display: none; }

.todo-edit { display: flex; gap: .35rem; align-items: center; margin: 0; }
/* pico sets width:100% on inputs and submit buttons, which splits a flex row
   evenly between the field and its buttons. These selectors are deliberately
   more specific than pico's, so the field takes the room and the buttons take
   only what they need. */
.todo-edit input[type=text] { flex: 1 1 auto; width: auto; min-width: 0; margin: 0; }
.todo-edit .tool { flex: 0 0 auto; width: auto; }
.todo.editing { padding: .1rem 0; }

/* --- dialogs -------------------------------------------------------- */
#modal:empty { display: none; }
#modal dialog article { max-width: 32rem; }
#modal fieldset { max-height: 15rem; overflow-y: auto; }
#modal footer { display: flex; gap: .5rem; justify-content: flex-end; margin-bottom: 0; }
#modal footer button { width: auto; margin: 0; }
.todo-quote { font-style: italic; margin-bottom: .75rem; }
.tag-suggestions { display: flex; flex-wrap: wrap; gap: .3rem; }
.attachment-list { list-style: none; padding-left: 0; }
.attachment-list li { display: flex; gap: .4rem; align-items: center; }

/* --- odds and ends -------------------------------------------------- */
.muted { color: var(--pico-muted-color); }
.empty { padding: .5rem 0; }
.error { color: var(--pico-del-color, #b3261e); }
article.error { border-left: 4px solid var(--pico-del-color, #b3261e); }
article.flash { border-left: 4px solid var(--pico-primary); }
.todo-detail { margin-top: 2rem; }
.inline-form { display: inline-flex; gap: .4rem; align-items: center; margin: 0; }
/* Both controls, not just the field: a button keeps pico's bottom margin
   otherwise, which makes the form taller than the button inside it and leaves
   that button sitting above the plain ones beside it. */
.inline-form input, .inline-form button { margin: 0; }
.row { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; }
label.inline { display: inline-flex; gap: .4rem; align-items: center; }
.link-button { background: none; border: none; padding: 0; margin: 0 .25rem; width: auto;
               font-size: .75em; color: var(--pico-muted-color); cursor: pointer; }
.save-view { align-items: center; }
.save-view input[type=text] { flex: 1 1 16rem; width: auto; min-width: 0; margin: 0; }
.save-view button[type=submit] { flex: 0 0 auto; width: auto; margin: 0; }
#save-view-status:empty { display: none; }
.signin { max-width: 26rem; margin: 2rem auto; }
.filters { margin-bottom: 1rem; }
.filters summary { font-size: .9rem; }
/* The switches at the foot of the filter panel each take a line of their
   own. They are three separate choices, and side by side one label runs
   straight into the next one's box. */
.filters label.inline.sort-filter,
.filters label.inline.completed-filter,
.filters label.inline.deleted-filter { display: flex; }
.mention { color: var(--pico-primary); }
/* Another to-do's number, written into the text. It is a link, but it is
   also a word in a sentence, so it is coloured and left in the flow rather
   than dressed up as a badge. */
.todo-text .ref.in-text {
    color: var(--pico-primary); text-decoration: none;
    border-bottom: 1px dotted var(--pico-primary);
}
.todo-text .ref.in-text:hover { text-decoration: none; border-bottom-style: solid; }
/* URLs typed into a to-do are linked in place, and must not push the row's
   buttons off the edge. */
.todo-text a { overflow-wrap: anywhere; }

/* --- @mention completion -------------------------------------------- */
/* The menu is positioned against the viewport rather than the field, so
   that it is never clipped by a dialog or by the row it belongs to. */
.mention-menu { position: fixed; z-index: 100; margin: 0; padding: .25rem; list-style: none;
                max-height: 14rem; overflow-y: auto; border-radius: var(--pico-border-radius);
                background: var(--pico-card-background-color); color: var(--pico-color);
                border: 1px solid var(--pico-muted-border-color);
                box-shadow: 0 .4rem 1rem rgba(0, 0, 0, .25); }
.mention-menu li { padding: .25rem .5rem; border-radius: var(--pico-border-radius);
                   cursor: pointer; white-space: nowrap; }
.mention-menu li.chosen { background: var(--pico-primary-background);
                          color: var(--pico-primary-inverse); }
.mention-menu li.chosen small { color: inherit; }

/* --- renaming an attachment ------------------------------------------ */
.attachment-rename { display: flex; gap: .35rem; align-items: center; margin: 0; }
.attachment-rename input[type=text] { flex: 1 1 auto; width: auto; min-width: 0; margin: 0; }
.attachment-rename .tool { flex: 0 0 auto; width: auto; }
.attachment-list li { display: flex; gap: .35rem; align-items: center; }
/* The size pushes the rename and remove buttons to the right, so they line
   up down the list however long the names are. */
.attachment-list li > small { margin-right: auto; }
.attachment-list li > form { flex: 1 1 auto; min-width: 0; }

/* --- notes ------------------------------------------------------------ */
.notes-dialog textarea { width: 100%; font-family: inherit; resize: vertical; }
.note-list { list-style: none; padding: 0; margin: 0 0 1rem; }
.note-list li { display: flex; gap: .35rem; align-items: center; }
/* The whole row is the way in, so it reads as a list rather than a form. */
/* color: inherit, not var(--pico-color): on a button pico redefines that to
   mean the text of a filled button, which is white, and this one has no fill
   - so the note's title was being drawn white on a white card and only
   appeared once a hover put a dark background behind it. */
.note-open { flex: 1 1 auto; width: auto; margin: 0; padding: .4rem .6rem; text-align: left;
             background: none; border: none; color: inherit; cursor: pointer;
             border-radius: var(--pico-border-radius); }
.note-open:hover, .note-open:focus-visible { background: var(--pico-secondary-background);
                                             color: var(--pico-secondary-inverse); }
.note-open:hover small, .note-open:focus-visible small { color: inherit; }
.note-title { display: block; }
.note-byline { margin-bottom: .5rem; }
/* A note keeps the shape it was written in - line breaks, blank lines and
   indentation - and a long one scrolls rather than pushing the dialog off
   the screen. */
.note-body { white-space: pre-wrap; overflow-wrap: break-word; max-height: 60vh; overflow-y: auto;
             padding: .6rem .8rem; border-radius: var(--pico-border-radius);
             background: var(--pico-code-background-color); }
.badge.note { cursor: pointer; }

/* --- weekly roundup --------------------------------------------------- */
.week { margin-bottom: 2.5rem; }
/* The same accent the navbar uses, to divide one week from the next. */
.week > h2 { font-size: 1.25rem; margin-bottom: .75rem; padding-bottom: .4rem;
             border-bottom: 4px solid var(--pico-primary); }
/* A panel: one person's week, or one project's. They are the same card with
   different things in them, and they are told apart by class so that a test -
   or a stylesheet - can name one without catching the other. */
.week-user, .week-project-panel { margin: 0 0 1rem; padding: .8rem 1rem; }
.week-user > h4, .week-project-panel > h4 { font-size: 1.05rem; margin-bottom: .5rem; }
/* Which way round the week is being read, beside which projects it covers. */
.roundup-scope select { min-width: 9rem; }
/* What a panel does not already say about an entry: the project a person's
   work was in, and whose work it was in a project's panel or in the panel of
   somebody who owns the project it happened in. */
.badge.project-of { background: var(--pico-code-background-color); color: var(--pico-muted-color);
                    max-width: 14rem; overflow: hidden; text-overflow: ellipsis; }
.badge.actor { background: none; padding-inline: 0; color: var(--pico-muted-color); }
.week-project-panel .panel-owners { margin: -.3rem 0 .5rem; }
.badge.settled-at { background: var(--pico-muted-border-color); color: var(--pico-muted-color); }
.week-todos { list-style: none; padding: 0; margin: 0; }
.week-todos li { display: flex; gap: .4rem; align-items: baseline; flex-wrap: wrap;
                 padding: .1rem 0; }
.week-comments { margin-top: .8rem; border-top: 1px solid var(--pico-muted-border-color);
                 padding-top: .6rem; }
.comment { margin: 0 0 .5rem; padding: .4rem .6rem; }
.comment-byline { margin: 0 0 .2rem; font-size: .8em; }
.comment-body { white-space: pre-wrap; overflow-wrap: break-word; }
.comment-form { align-items: center; margin-top: .5rem; }
.comment-form input[type=text] { flex: 1 1 auto; width: auto; min-width: 0; margin: 0; }
.comment-form button { flex: 0 0 auto; width: auto; margin: 0; }
/* A week that has been settled reads differently from the one in progress. */
/* Whether the account of a week is settled or still being written. It is said
   once, on the week's own heading, rather than on every panel in it. */
.week-state { margin-left: .5rem; vertical-align: middle; font-weight: normal; }
.week-state.live { background: var(--pico-primary-background); color: var(--pico-primary-inverse); }

/* --- projects --------------------------------------------------------- */
/* The number people quote a to-do by, in front of its text. */
.todo-ref { flex: none; font-variant-numeric: tabular-nums; font-size: .85em;
            color: var(--pico-muted-color); text-decoration: none; white-space: nowrap; }
.todo-ref:hover { text-decoration: underline; }
.project-picker { flex: 0 0 auto; width: auto; margin: 0; }

/* The projects table is edited in place: the cell that shows a thing is the
   control that changes it. A cell-edit button therefore has to read as the
   cell's contents rather than as a button - no chrome, the surrounding
   colour, the surrounding alignment - and say that it is one only when the
   pointer is on it or it has the focus. */
.projects td { vertical-align: middle; }
.cell-edit {
    display: inline-flex; align-items: center; gap: .3rem; flex-wrap: wrap;
    width: 100%; margin: 0; padding: .2rem .35rem;
    background: none; border: 1px solid transparent; box-shadow: none;
    border-radius: var(--pico-border-radius);
    color: inherit; font-size: inherit; font-weight: inherit; text-align: left;
    cursor: pointer;
}
.cell-edit:hover, .cell-edit:focus-visible {
    background: var(--pico-code-background-color);
    border-color: var(--pico-muted-border-color);
}
.cell-edit > .pencil { opacity: 0; font-size: .8em; transition: opacity .1s; }
.cell-edit:hover > .pencil, .cell-edit:focus-visible > .pencil { opacity: .7; }
/* Touch has no hover, so there is nothing to reveal the mark with. */
@media (hover: none) {
    .cell-edit > .pencil { opacity: .5; }
}

/* Who owns a project is a dropdown in its own column: a project can belong
   to more than one person, so it holds tick boxes and is applied with the
   button at the foot of the list. */
.owner-picker { margin: 0; }
.owner-picker > .dropdown { margin: 0; }
/* The summary keeps the look pico gives a dropdown - it reads as a control
   you can open, which is the whole point of putting it here - and only its
   size is brought down to what a table row can carry. */
.owner-picker summary { padding: .4rem .6rem; font-size: .9em; }
.owner-picker summary > .badge + .badge { margin-left: .25rem; }
.owner-picker ul { min-width: 13rem; max-height: 60vh; overflow-y: auto; z-index: 20; }
.owner-picker ul li { padding-block: .15rem; }
.owner-picker ul label { display: flex; align-items: center; gap: .4rem; margin: 0; }
.owner-picker .owner-apply {
    position: sticky; bottom: 0; padding-top: .5rem; margin-top: .25rem;
    border-top: 1px solid var(--pico-muted-border-color);
    background: var(--pico-dropdown-background-color);
}
.owner-picker .owner-apply button { width: 100%; margin: 0; padding: .3rem; font-size: .85em; }

/* A project that is open to everybody still lists who its viewers would be,
   dimmed, so that the effect of ticking the box can be read before it is. */
.visibility-form:has(input[name="private"]:not(:checked)) .viewer-list {
    opacity: .45;
}
.add-project > small { display: block; margin-bottom: var(--pico-spacing); }

/* The table has six columns and two of them are now controls rather than
   text, which is more than a phone has room for. The example of a number is
   the one column that can go: the prefix beside it already says what a
   to-do here will be called. The table is deliberately not put in a box that
   scrolls sideways, which is the usual answer, because the owners dropdown
   opens out of the cell and a box that scrolls would cut it off. */
@media (max-width: 900px) {
    .projects th:nth-child(3), .projects td:nth-child(3) { display: none; }
}
@media (max-width: 600px) {
    .projects { font-size: .9rem; }
    .projects th, .projects td { padding-inline: .35rem; }
    .cell-edit, .owner-picker summary { padding-inline: .2rem; }
    .owner-picker ul { min-width: 11rem; right: 0; left: auto; }
}
/* One project's part of a week. */
.week-project { margin-bottom: 1.25rem; }
.week-project > h3 { font-size: 1rem; margin-bottom: .5rem; }
.week-user h5, .week-project-panel h5 { font-size: .85rem; text-transform: uppercase; letter-spacing: .04em;
                color: var(--pico-muted-color); margin: .6rem 0 .2rem; }
/* Navbar items read as one thing each: they may wrap between items on a
   narrow screen, but never inside a word. */
#nav-menu > li > a, #nav-menu > li > details > summary { white-space: nowrap; }
.menu-rule { border-top: 1px solid var(--pico-muted-border-color); margin-top: .25rem; padding-top: .25rem; }
/* The project menu names where you are, and says so when that is somewhere
   in particular rather than everywhere. */
.project-menu > summary.in-project { color: var(--pico-primary); font-weight: 600; }
/* The views menu names the view being looked at, the same way. */
.views-menu > summary.in-view { color: var(--pico-primary); font-weight: 600; }
/* A view's name can run longer than a project's before it needs shortening. */
.views-menu > summary { max-width: 16rem; }
/* The roundup's own project filter, which is separate from whichever project
   the rest of the navbar is in. */
.roundup-scope { align-items: center; gap: .5rem; margin-bottom: .5rem; }
.roundup-scope label { display: flex; align-items: center; gap: .5rem; margin: 0; }
.roundup-scope select { width: auto; margin: 0; }
/* The account page's email switches. Each one is a line: the box, what it is
   called, and what it means underneath. Every cell is placed explicitly, so
   the description cannot land on top of the name it belongs to. */
.pref { display: grid; grid-template-columns: auto 1fr;
        column-gap: .6rem; row-gap: .1rem; margin-bottom: .9rem; }
.pref > input[type=checkbox] { grid-column: 1; grid-row: 1 / span 2; align-self: center; margin: 0; }
.pref > span { grid-column: 2; grid-row: 1; }
.pref > small { grid-column: 2; grid-row: 2; display: block; }
/* A count of hours is a short number, so its field is a short field rather
   than one running the width of the card. */
#settings-completed input[type=number] { width: 8rem; }

/* The "Saved." sits beside the button rather than being a banner that pushes
   the page around every time somebody ticks a box. */
.settings-actions { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
.settings-actions button { width: auto; margin: 0; }
/* The one-time password link an admin gets when there is no mail service to
   send it with: wide enough to select in one go. */
.one-time-link input { font-family: var(--pico-font-family-monospace, monospace); font-size: .8rem; margin: 0; }
/* The handle in the navbar leads to the account page. */
header > nav li.who a { color: inherit; text-decoration: none; }
header > nav li.who a:hover { color: var(--pico-primary); text-decoration: underline; }
/* The form that makes a new API key: the name and the button on one line, so
   the section does not end in a column of widely spaced controls. */
.new-key { display: flex; align-items: flex-end; gap: .6rem; flex-wrap: wrap; }
.new-key label { flex: 1 1 14rem; margin: 0; }
.new-key input[type=text] { margin: 0; }
.new-key button { width: auto; margin: 0; }
/* A key is shown once, so it gets the same wide, monospaced, select-it-all
   field as the one-time password link an admin is handed. */
#settings-keys .one-time-link input { width: 100%; }
#settings-keys td code { font-size: .85rem; }
/* The due dialog's two fields: the day, and the hour beside it. The hour is
   narrow because a time is always five characters wide. */
.due-fields { display: flex; gap: .6rem; align-items: flex-end; }
.due-fields label { margin: 0; flex: 1 1 auto; }
.due-fields label:last-child { flex: 0 0 8.5rem; }
.due-fields input { margin: 0; }

/* --- the admin page --------------------------------------------------- */
/* Each account's tools are one line. pico draws form controls at the size a
   page's main form wants, which in a table cell was wide enough to push the
   buttons onto a second row and out past the table's edge; inside this cell
   they are the compact versions and nothing wraps. */
.user-actions { display: flex; flex-wrap: nowrap; align-items: center; gap: .35rem; }
.user-actions > form { margin: 0; }
.user-actions button { width: auto; margin: 0; padding: .35rem .7rem;
                       font-size: .8rem; white-space: nowrap; }
.user-actions input[type=text] { width: 9rem; margin: 0; padding: .35rem .6rem;
                                 font-size: .8rem; }
/* A window too narrow to fit that line is the one case the row cannot be
   made to work: the table scrolls sideways rather than the buttons stacking
   or spilling over the edge of it. */
.admin-table { overflow-x: auto; }
.admin-table table { margin-bottom: 0; }
/* The roundup's three settings read as one sentence, so they stay on one
   line down to a narrow window rather than each taking a third of a wide one. */
#admin-roundup .grid { align-items: end; }
#admin-roundup select, #admin-roundup input[type=text] { margin: 0; }

/* --- stepping through the roundup's weeks ----------------------------- */
/* The arrows, the week's name and the date field on one line, with the name
   taking whatever room is left so the arrows stay at the ends. */
.roundup-weeks { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
                 margin-bottom: .35rem; }
/* The two arrows stay either side of the name they move, rather than being
   pushed to opposite ends of the bar; what goes to the right is the way of
   leaving the sequence altogether. */
.roundup-weeks .week-name { flex: 0 1 auto; margin: 0; font-size: 1.3rem; }
.roundup-weeks .week-jump { margin-left: auto; }
.week-step { width: auto; margin: 0; padding: .3rem .8rem; font-size: 1.1rem; line-height: 1;
             text-decoration: none; }
/* The step forward at the week in progress: still there, so the row does not
   jump about as the reader moves, but plainly not a way on. */
.week-step[aria-disabled="true"] { opacity: .35; cursor: not-allowed; }
.roundup-weeks .week-jump label { display: flex; align-items: center; gap: .4rem;
                                  margin: 0; white-space: nowrap; }
.roundup-weeks .week-jump input[type=date] { width: auto; margin: 0; padding: .3rem .5rem; }
.roundup-weeks a[role="button"].secondary { width: auto; margin: 0; padding: .3rem .8rem; }
.week-boundary { margin-bottom: 1rem; }
@media (max-width: 640px) {
    /* The name goes on a line of its own rather than squeezing the controls
       off the edge. */
    .roundup-weeks .week-name { flex: 1 0 100%; order: -1; }
    .roundup-weeks .week-jump { margin-left: 0; }
}

/* --- choosing who a to-do is assigned to ------------------------------ */
/* One account to a line: the box, the handle, and the address beside it.
   The address used to sit underneath, where the next row cut it off. */
.assignee-list label { display: flex; align-items: center; gap: .4rem; margin-bottom: .35rem; }
.assignee-list label input[type=checkbox] { flex: 0 0 auto; margin: 0; }
.assignee-list .assignee-handle { flex: 0 0 auto; }
/* The address gives way first: a long one is trimmed rather than pushing the
   handle it belongs to out of the dialog. */
.assignee-list .assignee-email { flex: 0 1 auto; min-width: 0; display: inline-block;
                                 overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* The due dialog's Clear sits away from Cancel and Save, since it does
   something to the to-do rather than to the dialog. */
#modal footer .clear-due { margin-right: auto; }
