:root {
  --bg: #f6f5f2;
  --surface: #ffffff;
  --ink: #1d1f23;
  --muted: #6a6f78;
  --line: #dddad3;
  --accent: #1f5fbf;
  --accent-ink: #ffffff;
  --warn-bg: #fdecea;
  --warn-ink: #8a1c13;
  --post: #fffbe8;
  --post-line: #e9dfb0;
  color-scheme: light dark;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #15171a;
    --surface: #1e2125;
    --ink: #e8e6e1;
    --muted: #9a9fa8;
    --line: #33373d;
    --accent: #7fb0ff;
    --accent-ink: #0d1524;
    --warn-bg: #3a1a17;
    --warn-ink: #ffb4ab;
    --post: #2a281d;
    --post-line: #4a4632;
  }
}
* { box-sizing: border-box; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 16px/1.5 system-ui, -apple-system, "Segoe UI", sans-serif;
}
a { color: var(--accent); }
.bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1.25rem;
  padding: 0.75rem 1rem;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}
.brand { font-weight: 700; color: var(--ink); text-decoration: none; }
/* On a narrow screen the tabs and the name wrap onto further lines; nothing in the
   bar may be wider than the screen, or the whole page scrolls sideways. */
.bar nav { display: flex; flex-wrap: wrap; gap: 0.25rem 1rem; flex: 1 0 auto; max-width: 100%; }
.bar nav a { text-decoration: none; white-space: nowrap; }
.who { display: flex; flex-wrap: wrap; align-items: center; gap: 0.25rem 0.75rem; margin: 0; min-width: 0; max-width: 100%; color: var(--muted); white-space: nowrap; }
main { max-width: 64rem; margin: 0 auto; padding: 1rem; }
.narrow { max-width: 24rem; margin: 3rem auto; }
h1 { font-size: 1.5rem; margin: 0.5rem 0 1rem; }
h2 { font-size: 1.05rem; margin: 0 0 0.5rem; }
section { margin: 2rem 0; }
.hint, .empty, small { color: var(--muted); }
.hint { font-size: 0.9rem; max-width: 44rem; }
.flash {
  background: var(--warn-bg);
  color: var(--warn-ink);
  padding: 0.6rem 0.8rem;
  border-radius: 6px;
}
.scroll {
  overflow-x: auto;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
  margin: 0.5rem 0 1rem;
}
table { width: 100%; border-collapse: collapse; }
th, td { padding: 0.5rem 0.75rem; text-align: left; border-bottom: 1px solid var(--line); vertical-align: middle; }
tbody tr:last-child td, tbody tr:last-child th { border-bottom: 0; }
th { font-size: 0.8rem; font-weight: 600; color: var(--muted); white-space: nowrap; }
.num { text-align: right; font-variant-numeric: tabular-nums; }
.muted td { color: var(--muted); }
td, th { white-space: nowrap; }
/* Every control looks the same wherever it sits: a label's small grey text is for the
   label, not for what is typed or chosen inside it. */
input, select, textarea, button {
  font-family: inherit;
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.5;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 0.4rem 0.55rem;
}
/* Fields and drop-downs are exactly as tall as a button, so a row of them lines up. */
input:not([type="checkbox"], [type="radio"], [type="hidden"]), select { height: calc(2.3rem + 2px); }
textarea { width: 100%; }
input:focus-visible, select:focus-visible, textarea:focus-visible, button:focus-visible, a:focus-visible, summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
button {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: var(--accent);
  font-weight: 600;
  cursor: pointer;
}
button.quiet { background: none; color: var(--accent); border-color: transparent; font-weight: 400; padding: 0.2rem 0.3rem; }
label { display: grid; gap: 0.2rem; font-size: 0.85rem; color: var(--muted); }
label.check { display: flex; align-items: center; gap: 0.35rem; color: var(--ink); font-size: 1rem; }
.stack { display: grid; gap: 0.8rem; margin: 1rem 0; }
.stack button { justify-self: start; }
.row { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: end; margin: 0.75rem 0; }
.row input:not([type="checkbox"]) { width: 10rem; max-width: 100%; }
.row input[type="number"] { width: 6rem; }
details summary { cursor: pointer; color: var(--accent); }
details[open] summary { margin-bottom: 0.5rem; }
.narrow.wide { max-width: 36rem; }
.copy { width: 100%; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
td form { display: inline; }
code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.flash.note { background: var(--surface); color: var(--ink); border: 1px solid var(--line); }
.actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0.75rem 0; }
.actions form { margin: 0; }
button.plain { background: none; color: var(--accent); border-color: var(--line); font-weight: 500; }
.tag { display: inline-block; border: 1px solid var(--line); border-radius: 999px; padding: 0 0.5rem; font-size: 0.8rem; color: var(--muted); }
.narrow.dev { margin-bottom: 0; border-bottom: 1px dashed var(--line); padding-bottom: 1rem; }
.narrow.dev + .narrow { margin-top: 1.5rem; }
.account { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; margin: 0; }
.list { list-style: none; padding: 0; margin: 0.5rem 0; display: grid; gap: 0.5rem; }
.list li { background: var(--surface); border: 1px solid var(--line); border-radius: 8px; padding: 0.6rem 0.8rem; }
.list small { display: block; }
.account button { white-space: nowrap; }
.checks { display: flex; flex-wrap: wrap; gap: 0.25rem 1.25rem; border: 0; padding: 0; margin: 0; }
.checks legend { font-size: 0.85rem; color: var(--muted); padding: 0; margin-bottom: 0.2rem; }
.stack .row { margin: 0; }
form.inline { display: flex; gap: 0.4rem; align-items: center; }
.who form { margin: 0; }
.menu { position: relative; }
.menu summary { list-style: none; color: var(--accent); cursor: pointer; padding: 0.2rem 0.3rem; }
.menu summary::-webkit-details-marker { display: none; }
.menu summary::after { content: " ▾"; }
.menu[open] summary { margin-bottom: 0; }
.menu-list { position: absolute; right: 0; top: calc(100% + 0.4rem); z-index: 10; display: grid; gap: 0.1rem; min-width: min(16rem, calc(100vw - 2rem)); max-width: calc(100vw - 2rem); padding: 0.5rem; background: var(--surface); border: 1px solid var(--line); border-radius: 8px; box-shadow: 0 6px 20px rgb(0 0 0 / 12%); }
.menu-list small { padding: 0 0.3rem 0.3rem; }
.menu-list button { width: 100%; text-align: left; white-space: nowrap; }
.menu-list button.switch { color: var(--ink); }
.menu-list button:disabled { color: var(--muted); cursor: default; }
.menu-list button:not(:disabled):hover { background: var(--bg); }
.menu-list .last { border-top: 1px solid var(--line); margin-top: 0.3rem; padding-top: 0.3rem; }
.checks:not(:has(input[name="is_head_office"]:checked)) .needs-head-office { display: none; }
td .actions { margin: 0; flex-wrap: nowrap; }
td form.inline input { width: 9rem; }
/* A warning wraps to the width of its field instead of widening the row. */
.warn { color: var(--warn-ink); width: 0; min-width: 100%; }
.row:has(.warn) { align-items: start; }
h3 { font-size: 0.95rem; margin: 1.25rem 0 0.25rem; }
table.week { table-layout: fixed; min-width: 34rem; }
table.week th:first-child { width: 5.5rem; }
table.week thead th { text-align: center; color: var(--ink); }
table.week thead th:first-child { text-align: left; color: var(--muted); }
table.week thead th.past { color: var(--muted); font-weight: 400; }
table.week td { text-align: center; font-variant-numeric: tabular-nums; }
table.week td input { width: 100%; min-width: 3rem; text-align: center; padding: 0.3rem 0.2rem; }
table.week + button, .scroll + button { margin-top: 0.25rem; }
/* In a top-aligned row, a button sits level with the fields, below their label line. */
.row:has(.warn) > button { margin-top: calc(0.85rem * 1.5 + 0.2rem); }
/* A roster as a calendar: a row per week, months shaded in turn with a line between. */
table.calendar { table-layout: fixed; min-width: 40rem; }
table.calendar thead th { text-align: center; color: var(--ink); }
table.calendar td.day { padding: 0.4rem 0.5rem 0.5rem; vertical-align: top; white-space: normal; border: 1px solid var(--line); }
table.calendar td.day.alternate { background: var(--bg); }
table.calendar td.day.month-left { border-left: 3px solid var(--accent); }
table.calendar td.day.month-above { border-top: 3px solid var(--accent); }
table.calendar .date { font-weight: 700; margin-bottom: 0.3rem; }
table.calendar .date .month { font-weight: 600; color: var(--accent); }
table.calendar td.past .date, table.calendar td.past .date .month { color: var(--muted); font-weight: 400; }
table.calendar label, table.calendar .need { display: flex; align-items: center; justify-content: space-between; gap: 0.3rem; margin: 0.2rem 0 0; font-size: 0.75rem; color: var(--muted); }
table.calendar label input { width: 3.2rem; height: auto; padding: 0.2rem; text-align: center; font-size: 0.95rem; }
table.calendar .need .n { font-size: 0.95rem; color: var(--ink); font-variant-numeric: tabular-nums; min-width: 1.5rem; text-align: center; }
/* A two-step confirmation on the page itself; browser dialogs are not always shown. */
.confirm summary { display: inline-block; list-style: none; border: 1px solid var(--line); border-radius: 6px; padding: 0.4rem 0.55rem; background: var(--surface); font-weight: 500; }
.confirm summary::-webkit-details-marker { display: none; }
.confirm[open] summary { margin-bottom: 0.5rem; }
.confirm form { background: var(--warn-bg); color: var(--warn-ink); border-radius: 8px; padding: 0.6rem 0.8rem; max-width: 30rem; }
.confirm form p { margin: 0 0 0.5rem; }
button.danger { background: var(--warn-ink); border-color: var(--warn-ink); color: var(--warn-bg); }
/* The weekday picker: a calendar where only the allowed weekday can be chosen. */
.datepick { position: relative; }
.datepick-button { background: var(--surface); color: var(--ink); border-color: var(--line); font-weight: 400; font-size: 1rem; min-width: 10.5rem; text-align: left; }
.datepick-button::after { content: " ▾"; color: var(--muted); float: right; }
.datepick-popup { position: absolute; z-index: 10; top: calc(100% + 0.3rem); left: 0; padding: 0.6rem; background: var(--surface); border: 1px solid var(--line); border-radius: 8px; box-shadow: 0 6px 20px rgb(0 0 0 / 12%); color: var(--ink); font-size: 0.9rem; }
.datepick-head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-bottom: 0.3rem; }
.datepick-head button { background: none; color: var(--accent); border-color: var(--line); padding: 0.1rem 0.6rem; }
.datepick-popup button { font-size: inherit; }
.datepick-popup table { width: auto; }
.datepick-popup th, .datepick-popup td { padding: 0.1rem; border: 0; text-align: center; }
.datepick-popup .day { display: block; width: 2.1rem; padding: 0.3rem 0; border-radius: 6px; text-align: center; }
.datepick-popup button.day { background: none; color: var(--ink); border: 1px solid var(--accent); font-weight: 600; }
.datepick-popup button.day:hover, .datepick-popup button.day.chosen { background: var(--accent); color: var(--accent-ink); }
.datepick-popup .day.off { color: var(--muted); opacity: 0.45; cursor: not-allowed; }
.datepick-note { margin: 0.4rem 0 0; font-size: 0.8rem; color: var(--muted); }
/* The arrival times that open under a week of the roster calendar. */
table.calendar tr.week { cursor: pointer; }
table.calendar tr.week label, table.calendar tr.week input { cursor: auto; }
table.calendar tr.week.open td.day { border-bottom-color: var(--accent); }
table.calendar tr.slots td { padding: 0.15rem 0.5rem; height: 1.7rem; }
table.calendar tr.slots.head td { background: var(--bg); font-weight: 600; font-size: 0.85rem; border: 1px solid var(--line); white-space: nowrap; }
table.calendar td.slot { border: 1px solid var(--line); }
table.calendar td.slot.needed { background: var(--surface); }
table.calendar td.slot .at { font-size: 0.8rem; color: var(--muted); font-variant-numeric: tabular-nums; }
table.calendar td.slot.spare { background: #e6b8af; }
@media (prefers-color-scheme: dark) { table.calendar td.slot.spare { background: #5a3530; } }
/* Timetable editors: a start time and one arrival time per person. */
.pair { display: flex; flex-wrap: wrap; gap: 1rem 2.5rem; align-items: flex-start; }
.timetable h3 { margin-top: 0.25rem; }
.timetable label input { width: 8rem; }
.arrivals-title { margin: 0.75rem 0 0.2rem; font-size: 0.85rem; color: var(--muted); }
.arrivals { margin: 0; padding-left: 2rem; font-variant-numeric: tabular-nums; }
.arrivals li { padding: 0.12rem 0; color: var(--muted); }
.arrivals li input { width: 8rem; }
.arrivals.readonly { columns: 3 6rem; max-width: 26rem; }
.arrivals.readonly li { color: var(--ink); }
.no-arrivals { margin: 0.2rem 0 0; font-size: 0.9rem; }
.timetable:has(.arrivals li) .no-arrivals { display: none; }
/* A contract's rules: each row reads as a sentence, "3 evening shifts every 2 weeks on…". */
.rules { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.4rem; }
.rule { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem 0.6rem; padding: 0.5rem 0.6rem; background: var(--surface); border: 1px solid var(--line); border-radius: 8px; }
.rule input[type="number"] { width: 4.5rem; text-align: center; }
.rule .on { color: var(--muted); }
.rule .days { display: flex; flex-wrap: wrap; gap: 0.2rem 0.8rem; }
.rule [data-remove-row] { margin-left: auto; }
.no-rules { margin: 0.2rem 0 0; font-size: 0.9rem; }
form:has(.rules li) .no-rules { display: none; }
.rules-words { margin: 0; padding-left: 1.1rem; }
td.wrap { white-space: normal; }
td.wrap .empty { margin: 0; }
/* A tick box in a row of fields is as tall as a field, so it centres on the fields. */
.row > label.check { height: calc(2.3rem + 2px); }
/* Lists: the search box above a table, and headings that order it when clicked. */
.list-search { display: flex; align-items: center; gap: 0.6rem; margin: 0.5rem 0 0; }
.list-search input { width: 16rem; max-width: 100%; }
.list-search + .scroll { margin-top: 0.4rem; }
th button.sort { background: none; border: 0; border-radius: 4px; padding: 0; font-size: inherit; font-weight: inherit; line-height: inherit; color: inherit; cursor: pointer; }
th button.sort::after { content: " ↕"; opacity: 0.45; }
th[aria-sort] button.sort { color: var(--ink); }
th[aria-sort="ascending"] button.sort::after { content: " ▲"; opacity: 1; }
th[aria-sort="descending"] button.sort::after { content: " ▼"; opacity: 1; }
tr[hidden] { display: none; }
/* A list searched on the server: its controls, and the count and page buttons below. */
.list-form { margin: 0; }
.list-form > .row { margin-bottom: 0.4rem; }
.list-form > .row input[type="search"] { width: 16rem; }
.pager { display: flex; align-items: center; gap: 0.6rem; margin: -0.5rem 0 1rem; min-height: 2.4rem; }
/* DataTables, dressed like the other tables. Its own stylesheet loads first; these put
   the app's colours, spacing and frame back, in light and in dark. */
.scroll:has(> .dt-container) { overflow: visible; border: 0; background: none; }
.dt-container .dt-layout-row { margin: 0 !important; }
.dt-container .dt-layout-row.dt-layout-table { overflow-x: auto; background: var(--surface); border: 1px solid var(--line); border-radius: 8px; }
.dt-container .dt-layout-row:not(.dt-layout-table) { align-items: center; min-height: 2.6rem; }
table.dataTable { margin: 0 !important; }
table.dataTable > thead > tr > th, table.dataTable > tbody > tr > td { padding: 0.5rem 0.75rem; }
table.dataTable > thead > tr > th { border-bottom: 1px solid var(--line); }
.dt-container.dt-empty-footer table.dataTable > tbody > tr:last-child > * { border-bottom: 0; }
table.dataTable > tbody > tr > td.dt-empty { color: var(--muted); text-align: left; }
.dt-container .dt-info { color: var(--muted); font-size: 0.85rem; padding: 0 !important; }
.dt-container .dt-paging .dt-paging-button { color: var(--accent) !important; background: none !important; border: 1px solid transparent !important; border-radius: 6px; padding: 0.25rem 0.65rem; font-weight: 500; box-shadow: none !important; }
.dt-container .dt-paging .dt-paging-button:not(.disabled):hover { background: var(--surface) !important; border-color: var(--line) !important; }
.dt-container .dt-paging .dt-paging-button.current { color: var(--ink) !important; background: var(--surface) !important; border-color: var(--line) !important; }
.dt-container .dt-paging .dt-paging-button.disabled { color: var(--muted) !important; opacity: 0.5; cursor: default; }
.dt-container .dt-processing { background: var(--surface); color: var(--muted); border: 1px solid var(--line); border-radius: 8px; }
/* Availability: a roster's calendar with a person's answer for each shift. */
/* Three answer buttons side by side need a wider column than the roster's calendar, so
   this page may use more of a wide screen. */
main:has(table.calendar.availability) { max-width: 82rem; }
table.calendar.availability { min-width: 72rem; }
table.calendar.availability .shift { display: grid; gap: 0.25rem; margin-top: 0.35rem; padding: 0.2rem; border-radius: 6px; border: 1px solid transparent; }
/* A faint line under every evening shift, running the width of the day, so that each
   week reads as an evening band over a lunch band, empty on days with no lunch shift. */
table.calendar.availability .shift + .shift { margin-top: 0.9rem; }
table.calendar.availability .shift[data-daypart="evening"] { position: relative; }
table.calendar.availability .shift[data-daypart="evening"]::after { content: ""; position: absolute; left: calc(-0.5rem - 1px); right: calc(-0.5rem - 1px); bottom: calc(-0.45rem - 2px); border-top: 1px solid var(--line); pointer-events: none; }
table.calendar.availability .part { font-size: 0.75rem; color: var(--muted); }
/* The answers: a row of buttons, one pressed at a time. Each is a radio button's label,
   so the form still works without the script. */
table.calendar.availability .answers { display: flex; border: 1px solid var(--line); border-radius: 6px; overflow: hidden; background: var(--surface); }
table.calendar.availability .answers label,
table.calendar.availability .answers button { flex: 1 1 auto; display: block; margin: 0; padding: 0.3rem 0.2rem; border: 0; border-radius: 0; border-left: 1px solid var(--line); background: none; color: var(--ink); font-size: 0.72rem; font-weight: 500; line-height: 1.3; text-align: center; white-space: nowrap; cursor: pointer; }
table.calendar.availability .answers > :first-child { border-left: 0; }
table.calendar.availability .answers input { position: absolute; opacity: 0; pointer-events: none; }
table.calendar.availability .answers label:has(input:focus-visible),
table.calendar.availability .answers button:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
table.calendar.availability .answers label:hover, table.calendar.availability .answers button:hover { background: var(--bg); }
table.calendar.availability .answers label:has(input[value="want"]:checked),
table.calendar.availability .answers button[data-set="want"][aria-pressed="true"] { background: var(--want-line); font-weight: 700; }
table.calendar.availability .answers label:has(input[value="if_needed"]:checked),
table.calendar.availability .answers button[data-set="if_needed"][aria-pressed="true"] { background: var(--maybe-line); font-weight: 700; }
table.calendar.availability .answers label:has(input[value="cannot"]:checked),
table.calendar.availability .answers button[data-set="cannot"][aria-pressed="true"] { background: var(--cannot-line); font-weight: 700; }
/* "No answer" is a button only without the script; with it, pressing the chosen answer
   again does the same. */
form.live .answers label.none { display: none; }
form.live .answers label.none + label { border-left: 0; }
table.calendar.availability .shift[data-answer="want"] { background: var(--want-bg); border-color: var(--want-line); }
table.calendar.availability .shift[data-answer="if_needed"] { background: var(--maybe-bg); border-color: var(--maybe-line); }
table.calendar.availability .shift[data-answer="cannot"] { background: var(--warn-bg); border-color: var(--cannot-line); }
table.calendar.availability select { width: 100%; height: auto; padding: 0.2rem 0.3rem; font-size: 0.9rem; }
/* Once the script is running, a time shows only beside an answer to work. */
form.live .shift:not([data-answer="want"], [data-answer="if_needed"], [data-every]) .from { visibility: hidden; }
table.calendar.availability label.from { margin: 0; gap: 0.35rem; cursor: auto; }
table.calendar.availability label.from select { width: auto; flex: 1; min-width: 0; text-align: left; }
table.calendar.availability button.clear { justify-self: start; font-size: 0.75rem; padding: 0 0.2rem; }
/* The every-week row is a tool, not a week: a pale tint of the accent colour sets it
   apart from the days below. */
table.calendar.availability tr.every td.day { background: color-mix(in srgb, var(--accent) 9%, var(--surface)); }
/* The every-week row stands apart from the weeks themselves. */
table.calendar.availability tr.gap td { height: 0.75rem; padding: 0; border: 0; background: var(--bg); }
/* Days are divided a little more firmly than the two shifts inside a day: a thicker,
   slightly darker line. The line where a month begins keeps its own weight and colour. */
table.calendar.availability td.day { border: 2px solid var(--day-line); background: var(--surface); }
table.calendar.availability td.day.alternate { background: var(--bg); }
table.calendar.availability thead th { border: 2px solid var(--day-line); background: var(--surface); }
/* The frame around the table is the cells' own, not the scrolling box's, so that the
   gap under the every-week row is a clean break with no line down either side. */
.scroll:has(> table.calendar.availability) { border: 0; border-radius: 0; background: none; }
/* The calendar is part of the page, not a box that scrolls within it: nothing scrolls
   but the page itself, down through the weeks and, on a screen too narrow for seven
   days, sideways across them. So the box around it does not scroll, and the weekday
   names can stick to the top of the screen. Borders of a collapsed table do not travel
   with a stuck cell, and what scrolls beneath would show through where they were, so
   each heading carries a backing that covers its borders and draws their lines. */
.scroll:has(> table.calendar.availability) { overflow: visible; }
table.calendar.availability thead th { position: sticky; top: 0; z-index: 3; }
table.calendar.availability thead th::before { content: ""; position: absolute; inset: -2px; z-index: -1; background: var(--surface); border: 2px solid var(--day-line); }
/* On a narrow screen the page is made as wide as the calendar, and everything that is
   not the calendar stays at the left of the screen, a screen wide, while the page is
   scrolled sideways: the top bar, the headings and text, and the form's own button. */
@media (max-width: 76rem) {
  body:has(table.calendar.availability) { min-width: 74rem; }
  /* Everything stuck in place is a layer of its own, and a later one paints over an
     earlier one. The top bar comes first and its menu opens downwards over the page,
     so it is lifted above the rest. */
  body:has(table.calendar.availability) .bar { position: sticky; left: 0; width: 100vw; max-width: 100%; z-index: 20; }
  body:has(table.calendar.availability) main > :not(:has(table.calendar.availability)),
  body:has(table.calendar.availability) main :has(table.calendar.availability) > :not(:has(table.calendar.availability), table.calendar.availability) { position: sticky; left: 1rem; max-width: min(var(--cap, 100vw), calc(100vw - 2rem)); }
  /* A hint keeps its own narrower measure. */
  .hint { --cap: 44rem; }
}
table.calendar.availability td.day.month-left { border-left: 3px solid var(--accent); }
table.calendar.availability td.day.month-above { border-top: 3px solid var(--accent); }
table.calendar.availability tr.every .date { color: var(--muted); font-weight: 600; }
:root { --day-line: #c9c5bc; --want-bg: #e3f4e6; --want-line: #9fcfa8; --maybe-bg: #fdf3d6; --maybe-line: #e3c46e; --cannot-line: #e7a59e; }
@media (prefers-color-scheme: dark) {
  :root { --day-line: #474c54; --want-bg: #1c3523; --want-line: #3d6b49; --maybe-bg: #3a3116; --maybe-line: #77632a; --cannot-line: #7a3a34; }
}
/* The contract status on a sheet: each rule, how it stands, and a line per stretch it
   is counted over. */
.checks-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.5rem; }
.checks-list .check { background: var(--surface); border: 1px solid var(--line); border-left-width: 4px; border-radius: 8px; padding: 0.5rem 0.75rem; }
.checks-list .check.met { border-left-color: var(--want-line); }
.checks-list .check.short { border-left-color: var(--warn-ink); }
.checks-list .check .words { font-weight: 600; margin-right: 0.4rem; }
.checks-list .check.met .verdict { background: var(--want-bg); border-color: var(--want-line); color: var(--ink); }
.checks-list .check.short .verdict { background: var(--warn-bg); border-color: var(--cannot-line); color: var(--warn-ink); }
.stretches { list-style: none; margin: 0.35rem 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.3rem 0.4rem; font-size: 0.8rem; color: var(--muted); }
.stretches li { border: 1px solid var(--line); border-radius: 6px; padding: 0.05rem 0.45rem; white-space: nowrap; font-variant-numeric: tabular-nums; }
/* Each stretch's border says how it stands: green met, amber unknown, red short. */
.stretches li.met { border-color: var(--want-line); }
.stretches li.met b { color: var(--ink); }
.stretches li.unknown { border-color: var(--maybe-line); }
.stretches li.short { background: var(--warn-bg); border-color: var(--cannot-line); color: var(--warn-ink); }
/* How the contract stands and whether the last change was saved stay at the bottom of
   the screen while the sheet is in view. */
.savebar { position: sticky; bottom: 0; z-index: 4; display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 1rem; margin-top: 0.75rem; padding: 0.6rem 0; background: var(--bg); border-top: 1px solid var(--line); box-shadow: 1rem 0 0 var(--bg), -1rem 0 0 var(--bg); }
.save-state { color: var(--muted); font-size: 0.9rem; }
.save-state.unsaved { color: var(--warn-ink); }
/* The same, in a line under a form that is not a whole page. */
.saveline { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 1rem; margin-top: 0.6rem; min-height: 1.5rem; }
.savebar a { font-size: 0.9rem; }
/* A verdict that explains itself when pointed at. */
.checks-list [title] { cursor: help; }
/* The buttons that answer the shifts not yet answered, with how many there are. */
.sheet-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem 0.6rem; margin: 0.75rem 0 1.25rem; }
.sheet-actions .hint { font-size: 0.85rem; margin-left: 0.2rem; }
/* A link that looks like a button, for leaving a page where everything is saved. */
a.button { display: inline-block; padding: 0.4rem 0.55rem; border: 1px solid var(--accent); border-radius: 6px; background: var(--accent); color: var(--accent-ink); font-weight: 600; line-height: 1.5; text-decoration: none; }
.savebar a.button { font-size: 1rem; }
/* How a contract stands over a roster, in a list of rosters. */
.tag.standing.met { background: var(--want-bg); border-color: var(--want-line); color: var(--ink); }
.tag.standing.short { background: var(--warn-bg); border-color: var(--cannot-line); color: var(--warn-ink); }

/* Locking: the roster's status line, the strategies, and who was given each row. */
.lock .tag { margin-right: 0.3rem; }
form.lock { align-items: center; }
form.lock label { display: flex; align-items: center; gap: 0.5rem; }
.lock .flash { max-width: 44rem; }
.tag.standing.complete { background: var(--bg); border-color: var(--line); color: var(--muted); }
.tag.standing.locked { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.strategy p { max-width: 44rem; }
.strategies .strategy { border: 1px solid var(--line); border-radius: 8px; background: var(--surface); padding: 0.6rem 0.8rem; margin: 0 0 0.8rem; max-width: 46rem; }
.strategies .strategy label { font-weight: 600; }
.strategies .strategy p { margin: 0.5rem 0 0; font-size: 0.92rem; }
table.calendar .need.short, table.calendar .need.short .n { color: var(--warn-ink); font-weight: 600; }
table.calendar .need.short .n { white-space: nowrap; }
table.calendar td.slot .who { font-size: 0.85rem; }
table.calendar td.slot.unfilled { background: var(--maybe-bg); }
table.calendar td.slot.unfilled .who { color: var(--muted); font-style: italic; }
fieldset.sheet { border: 0; margin: 0; padding: 0; min-width: 0; }
fieldset.sheet:disabled .every, fieldset.sheet:disabled .gap { display: none; }
table.standings td.none { color: var(--warn-ink); font-weight: 600; }
/* A tag with more to say: the pane opens while it is pointed at or has the focus. The
   script places it; without the script it opens where it stands. */
.detail { cursor: help; border-radius: 999px; }
.detail .pane { display: none; position: fixed; z-index: 30; width: min(26rem, calc(100vw - 1.5rem)); padding: 0.6rem 0.75rem; background: var(--surface); color: var(--ink); border: 1px solid var(--line); border-radius: 8px; box-shadow: 0 6px 20px rgb(0 0 0 / 0.18); white-space: normal; cursor: auto; text-align: left; }
.detail:hover .pane, .detail:focus .pane, .detail:focus-within .pane { display: block; }
.detail .pane .checks-list { margin: 0.4rem 0 0; }
/* The window over one arrival row of a locked roster: who has it, and changing that. */
table.calendar.opens-slots td.slot.needed { cursor: pointer; }
table.calendar.opens-slots td.slot.needed:hover, table.calendar.opens-slots td.slot.needed:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
dialog.slot { width: min(26rem, calc(100vw - 1.5rem)); padding: 0.9rem 1rem 1rem; background: var(--surface); color: var(--ink); border: 1px solid var(--line); border-radius: 10px; box-shadow: 0 10px 30px rgb(0 0 0 / 0.25); }
dialog.slot::backdrop { background: rgb(0 0 0 / 0.35); }
dialog.slot h2 { margin: 0 3.5rem 0.1rem 0; font-size: 1.1rem; }
dialog.slot .shut { position: absolute; top: 0.6rem; right: 0.7rem; }
dialog.slot dl { display: grid; grid-template-columns: auto 1fr; gap: 0.25rem 0.9rem; align-items: baseline; margin: 0.8rem 0; }
dialog.slot dt { color: var(--muted); font-size: 0.85rem; }
dialog.slot dd { margin: 0; }
dialog.slot form.row { align-items: end; }
dialog.slot select { max-width: 100%; }
dialog.slot .hint { margin-bottom: 0; }
/* A person's side of a locked roster: their shifts, and everyone's. */
table.given { width: auto; }
table.calendar.everyone .need.mine { background: var(--want-bg); border: 1px solid var(--want-line); border-radius: 6px; padding: 0.1rem 0.35rem; color: var(--ink); }
table.calendar.everyone td.day { height: 4.2rem; }
table.calendar td.slot.mine { background: var(--want-bg); }
table.calendar td.slot.mine .who { font-weight: 600; }
details.answered > summary { cursor: pointer; font-weight: 600; margin: 1rem 0 0.5rem; }
/* Opening a week of a roster calendar: its rows slide down. Closing it: they slide
   shut, and the script takes them away after the same 220ms. */
@keyframes slot-row-out { to { height: 0; padding-top: 0; padding-bottom: 0; } }
@keyframes slot-out { from { max-height: 3.5rem; opacity: 1; } to { max-height: 0; opacity: 0; } }
table.calendar tr.slots.closing td { animation: slot-row-out 220ms ease-in forwards; }
table.calendar tr.slots.closing td > .in { overflow: hidden; animation: slot-out 220ms ease-in forwards; }
@keyframes slot-row { from { height: 0; padding-top: 0; padding-bottom: 0; } }
@keyframes slot-in { from { max-height: 0; opacity: 0; } to { max-height: 3.5rem; opacity: 1; } }
table.calendar tr.slots.slide td { animation: slot-row 220ms ease-out; }
table.calendar tr.slots.slide td > .in { overflow: hidden; animation: slot-in 220ms ease-out; }
@media (prefers-reduced-motion: reduce) {
  table.calendar tr.slots.slide td, table.calendar tr.slots.slide td > .in { animation: none; }
}
/* Development: the clock set by hand, in the sign-out menu and beside the name. */
.menu-list small.next { margin-top: 0.4rem; padding-top: 0.5rem; border-top: 1px solid var(--line); }
.menu-list form.clock { display: flex; gap: 0.3rem; align-items: center; padding: 0 0.3rem; }
.menu-list form.clock input, .menu-list form.clock select { flex: 1; min-width: 0; }
.dev form.clock { display: flex; gap: 0.5rem; align-items: center; }
.dev form.clock select { flex: 1; min-width: 0; }
.menu-list form.clock button { width: auto; }
.tag.pretend { background: var(--maybe-bg); border-color: var(--maybe-line); color: var(--ink); white-space: nowrap; }

/* Notices. Reading and posting are two things, kept visibly apart by a line: a board is
   a white box, under a row of tabs when someone reads several, with its notices one
   under another inside; the form to post comes after it, under a heading of its own. */
.reading, .posting { border-top: 1px solid var(--line); padding-top: 1.5rem; }
h1 + .reading { border-top: 0; padding-top: 0; margin-top: 1rem; }
form.notice-form { max-width: 44rem; }
.boards { display: flex; flex-wrap: wrap; gap: 0.25rem; margin: 0.75rem 0 0; position: relative; z-index: 1; }
.boards a { padding: 0.4rem 0.8rem; text-decoration: none; border: 1px solid transparent; border-bottom: 0; border-radius: 8px 8px 0 0; margin-bottom: -1px; }
.boards a[aria-current] { background: var(--surface); border-color: var(--line); color: var(--ink); font-weight: 600; }
.board { background: var(--surface); border: 1px solid var(--line); border-radius: 8px; padding: 0 1rem; }
.board.tabbed { border-top-left-radius: 0; }
.board > .empty { margin: 0; padding: 1rem 0; }
.notice { padding: 1rem 0; }
.notice > * { max-width: 44rem; }
.notice + .notice, .board > details.expired { border-top: 1px solid var(--line); }
.notice h3 { margin: 0 0 0.3rem; font-size: 1.05rem; }
.notice .words { white-space: pre-wrap; overflow-wrap: anywhere; margin: 0; }
.notice .byline { color: var(--muted); font-size: 0.85rem; margin: 0.5rem 0 0; }
.about { display: flex; flex-wrap: wrap; gap: 0.3rem; margin: 0.5rem 0 0; }
.notice .actions { align-items: start; margin: 0.6rem 0 0; }
.notice .hint { margin: 0.5rem 0 0; }
.board > details.expired { padding: 0.75rem 0; }
.board > details.expired > summary { margin: 0; }
.board > details.expired[open] > summary { margin-bottom: 0.5rem; }
.notice.expired { color: var(--muted); }
a.button.plain { background: none; color: var(--accent); border-color: var(--line); font-weight: 500; }
/* On the home page a board looks like one: its notices are rectangular posts, tiled
   side by side, each as tall as what it says and no taller than a long one scrolls. */
.board.tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(15rem, 100%), 1fr)); gap: 0.9rem; align-items: start; padding: 1rem; }
.board.tiles .notice { padding: 0.75rem 0.85rem; max-height: 22rem; overflow-y: auto; background: var(--post); border: 1px solid var(--post-line); border-radius: 2px; box-shadow: 0 1px 3px rgb(0 0 0 / 0.12); }
.board.tiles > .empty { grid-column: 1 / -1; padding: 0; }
/* A row changed since the lock is marked, and its window lists what happened. */
table.calendar td.slot .changed { font-size: 0.7rem; color: var(--warn-ink); background: var(--warn-bg); border-radius: 999px; padding: 0 0.35rem; white-space: nowrap; }
dialog.slot h3 { font-size: 0.85rem; color: var(--muted); font-weight: 600; margin: 1rem 0 0.3rem; }
dialog.slot .history { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.35rem; }
dialog.slot .history .when { display: block; font-size: 0.8rem; color: var(--muted); }
/* An offer of a shift: a post of another colour on a board, with its buttons. */
.notice.offer h3 { color: var(--accent); }
.board.tiles .notice.offer { background: color-mix(in srgb, var(--accent) 8%, var(--surface)); border-color: color-mix(in srgb, var(--accent) 35%, var(--line)); }
.notice.offer .with, .notice.offer .said { margin: 0.4rem 0 0; }
.notice.offer .said { font-style: italic; }
.notice.offer .actions form { margin: 0; }
dialog.slot .offered { list-style: none; padding: 0; margin: 0; display: grid; gap: 0.4rem; }
dialog.slot .offered li { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; }
dialog.slot .offered small { display: block; }
dialog.slot .offered form { margin: 0; }
dialog.slot form.offering { margin: 0.3rem 0 0.6rem; }
dialog.slot form.offering .row input:not([type="checkbox"]) { width: 9rem; }
dialog.slot { max-height: calc(100vh - 2rem); overflow-y: auto; }
.board.tiles .notice.offer { max-height: none; overflow: visible; }
.notice.offer .confirm:not([open]) summary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); font-weight: 600; }
.notice.offer .confirm form { max-width: none; }
/* Swaps: what you give and what you get, and a form folded under a button. */
dl.swap { display: grid; grid-template-columns: auto 1fr; gap: 0.15rem 0.6rem; align-items: baseline; margin: 0.2rem 0 0; }
dl.swap dt { color: var(--muted); font-size: 0.85rem; white-space: nowrap; }
dl.swap dd { margin: 0; }
.notice.offer .flash { margin: 0.5rem 0 0; font-size: 0.9rem; }
details.fold > summary { display: inline-block; list-style: none; border: 1px solid var(--line); border-radius: 6px; padding: 0.4rem 0.55rem; background: var(--surface); font-weight: 500; }
details.fold > summary::-webkit-details-marker { display: none; }
details.fold[open] > summary { margin-bottom: 0.5rem; }
details.fold > form { margin: 0; padding: 0.6rem 0.7rem; border: 1px dashed var(--line); border-radius: 8px; background: var(--surface); }
.notice.offer details.fold select, .notice.offer details.fold input, dialog.slot form.offering select { max-width: 100%; width: 100%; }
.notice.offer details[open] { flex-basis: 100%; }

/* Inside Telegram a pull past the top of the page must not travel on to the window
   that holds the app, which would start closing it. */
html.in-telegram, html.in-telegram body { overscroll-behavior-y: none; }
