/**
 * VacPlan — monochrome, hairline, quiet.
 *
 * The design rule is simple: the vacation bars carry the weight. Rules, weekday
 * letters, headings and chrome all recede to grey so that scanning "who is away
 * when" needs no effort.
 *
 * Exactly two colours are spent, and each answers a different question:
 * petrol says "this person is away", red says "nobody works that day". Because
 * they never appear in the same cell — a holiday cannot hold vacation — there is
 * no ambiguity to resolve, and the grid stays otherwise achromatic.
 *
 * One typeface throughout with tabular figures, rather than a display face plus
 * a mono for numbers: fewer moving parts reads as calmer, and tabular-nums
 * already gives the column alignment a monospace was there to provide.
 *
 * No web fonts. This runs on an intranet and must not wait on, or leak to, an
 * external host.
 */

/*
 * Three themes, chosen on <html data-theme> by theme-boot.js before first paint:
 * light (the default below), dim and dark. Every colour on the page comes from
 * these tokens, so a theme is nothing more than a different set of values.
 */
:root {
  --font: 'Segoe UI Variable Text', 'Segoe UI', -apple-system, BlinkMacSystemFont,
          'Helvetica Neue', system-ui, sans-serif;

  /* Native controls — scrollbars, the month picker — follow the theme too. */
  color-scheme: light;

  --bg: #ffffff;
  --ink: #14161a;
  /* Secondary and tertiary greys are held at roughly 7:1 and 4.6:1 against the
     ground, so nothing on the page drops below the readable threshold — a grid
     this dense punishes low contrast more than a page of prose does. */
  --ink-2: #464b52;
  --ink-3: #6e747c;
  --rule: #e6e8ec;    /* hairline between cells */
  --rule-2: #ccd1d7;  /* structural separators */
  --weekend: #f4f5f7;

  /* Public holidays get their own hue. Red is what a Czech wall calendar uses
     for them, and it sits far enough from the vacation petrol that the two can
     never be read as the same mark. */
  --holiday: #fdeae8;
  --holiday-mark: #c0392b;
  --holiday-ink: #9c2f22;

  --accent: #1b5e7e;          /* a marked day */
  --accent-soft: #e3edf2;     /* hover on an empty workday */
  --preview: #7fa9bd;         /* drag preview */

  --cell-w: 2rem;
  --cell-h: 1.95rem;
  --month-w: 6rem;
  --name-w: 9rem;
  --sum-w: 3.4rem;
  --radius: 2px;
}

/* Dark: near-black ground, full contrast, for a dark room or an OLED screen. */
:root[data-theme="dark"] {
  color-scheme: dark;

  --bg: #121417;
  --ink: #eceef1;
  --ink-2: #adb3bb;
  --ink-3: #868d96;
  --rule: #262a30;
  --rule-2: #383e46;
  --weekend: #1a1d22;

  --holiday: #2f1e1c;
  --holiday-mark: #e0654f;
  --holiday-ink: #f0907c;

  --accent: #4b9ec2;
  --accent-soft: #1b262d;
  --preview: #2f5669;
}

/*
 * Dim: a slate ground and softer text, for long sessions where white glares
 * and true black feels harsh. Contrast is lowered but never below the floor the
 * light theme keeps: the tertiary grey still clears 4.5:1 on the weekend tint.
 */
:root[data-theme="dim"] {
  color-scheme: dark;

  --bg: #22272e;
  --ink: #d3dbe4;
  --ink-2: #a8b3bf;
  --ink-3: #8f9aa7;
  --rule: #313840;
  --rule-2: #454e59;
  --weekend: #2a3038;

  --holiday: #3b2c2e;
  --holiday-mark: #e07a6b;
  --holiday-ink: #f0a294;

  --accent: #5a9fc0;
  --accent-soft: #2b3743;
  --preview: #3e6278;
}

* { box-sizing: border-box; }

/* The attribute must win over a display value set by a class. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.55;
  font-variant-numeric: tabular-nums lining-nums;
  -webkit-font-smoothing: antialiased;
}

:where(button, input, select, [tabindex]):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-radius: var(--radius);
}

/* ============================== toolbar ============================== */

.toolbar {
  position: sticky;
  top: 0;
  z-index: 30;
  background: var(--bg);
  border-bottom: 1px solid var(--rule-2);
}

.bar {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  flex-wrap: wrap;
  padding: 0.85rem 1.5rem;
}

.bar__brand { margin-right: auto; }

.bar__title {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: -0.005em;
}

/* Year tabs: plain text, the current one simply underlined. */
.years { display: flex; align-items: center; gap: 0.15rem; }

.years__tab,
.years__add {
  border: 0;
  background: none;
  color: var(--ink-3);
  font: inherit;
  font-variant-numeric: tabular-nums;
  padding: 0.2rem 0.5rem;
  cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: color 100ms;
}

.years__tab:hover,
.years__add:hover { color: var(--ink); }

.years__tab.is-current {
  color: var(--ink);
  font-weight: 600;
  border-bottom-color: var(--ink);
}

.years__add { font-size: 1.15rem; line-height: 1; padding-inline: 0.45rem; }

/*
 * Theme toggle. The three icons ride on a wheel whose hub sits below the
 * button, so only the top spoke shows through the round window. Turning the
 * wheel a third swings the next icon in over the top as the last one drops
 * away to the left; a slight overshoot lets it settle like a dial.
 */
.theme-toggle {
  --wheel-r: 1.5rem;

  position: relative;
  flex-shrink: 0;
  width: 2.2rem;
  height: 2.2rem;
  padding: 0;
  border: 1px solid var(--rule-2);
  border-radius: 50%;
  background: none;
  color: var(--ink-2);
  cursor: pointer;
  overflow: hidden;
  transition: border-color 100ms, color 100ms;
}

.theme-toggle:hover { border-color: var(--ink-2); color: var(--ink); }

/* A zero-size box at the hub; the icons hang off it on their spokes. */
.theme-toggle__wheel {
  position: absolute;
  left: 50%;
  top: calc(50% + var(--wheel-r));
  transition: transform 560ms cubic-bezier(0.34, 1.45, 0.64, 1);
}

.theme-toggle__icon {
  position: absolute;
  left: -0.575rem;
  top: -0.575rem;
  width: 1.15rem;
  height: 1.15rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
  transform: rotate(var(--spoke)) translateY(calc(-1 * var(--wheel-r)));
}

@media (prefers-reduced-motion: reduce) {
  .theme-toggle__wheel { transition: none; }
}

.bar__tools { display: flex; gap: 0.4rem; }

/* The account menu: the logged-in name, opening a small list below it. */
.account { position: relative; }

.account__toggle {
  max-width: 12rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.account__menu {
  position: absolute;
  top: calc(100% + 0.3rem);
  right: 0;
  z-index: 40;
  min-width: 11rem;
  display: flex;
  flex-direction: column;
  padding: 0.3rem;
  background: var(--bg);
  border: 1px solid var(--rule-2);
  border-radius: 4px;
  box-shadow: 0 12px 30px -18px rgb(0 0 0 / 45%);
}

.account__item {
  font: inherit;
  text-align: left;
  padding: 0.4rem 0.6rem;
  border: 0;
  border-radius: var(--radius);
  background: none;
  color: var(--ink);
  cursor: pointer;
}

.account__item:hover { background: var(--accent-soft); }

.btn {
  border: 1px solid var(--rule-2);
  border-radius: var(--radius);
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: 0.9rem;
  padding: 0.34rem 0.75rem;
  cursor: pointer;
  transition: border-color 100ms, background 100ms, color 100ms;
}

.btn:hover { border-color: var(--ink-2); }
.btn:disabled { opacity: 0.55; cursor: default; }
.btn--solid { background: var(--ink); border-color: var(--ink); color: var(--bg); }
.btn--solid:hover { background: var(--ink-2); border-color: var(--ink-2); }
.btn--danger:hover { border-color: var(--ink); }
.btn--tiny { font-size: 0.83rem; padding: 0.16rem 0.5rem; color: var(--ink-2); }
.btn--tiny:hover { color: var(--ink); }

/* ============================== legend ============================== */

.legend {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  padding: 0 1.5rem 0.8rem;
  font-size: 0.85rem;
  color: var(--ink-3);
}

.legend__item { display: inline-flex; align-items: center; gap: 0.35rem; }

.legend__swatch {
  width: 1.4rem;
  height: 0.75rem;
  border-radius: var(--radius);
  border: 1px solid var(--rule-2);
}

.legend__swatch.is-vacation { background: var(--accent); border-color: var(--accent); }
.legend__swatch.is-weekend { background: var(--weekend); }
.legend__swatch.is-holiday { background: var(--holiday); border-color: var(--holiday-mark); border-top-width: 3px; }
.legend__hint { margin-left: auto; }

.notice {
  margin: 0 1.5rem 0.75rem;
  padding: 0.4rem 0.65rem;
  border: 1px solid var(--rule-2);
  border-left-width: 2px;
  border-left-color: var(--ink);
  border-radius: var(--radius);
  font-size: 0.88rem;
  color: var(--ink-2);
}

/* ============================ people panel ============================ */

.people {
  padding: 0.9rem 1.5rem 1.1rem;
  border-top: 1px solid var(--rule);
  /* The panel lives in the sticky toolbar: with a big team it must scroll on
     its own rather than push the calendar off the screen. */
  max-height: 60vh;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.people__title {
  margin: 0 0 0.6rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--ink-2);
}

.people__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
  gap: 0 1.75rem;
}

.people__item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem 0.75rem;
  padding: 0.35rem 0;
  border-bottom: 1px solid var(--rule);
}

.people__item.is-inactive .people__name { color: var(--ink-3); }
.people__info { display: flex; flex-direction: column; margin-right: auto; min-width: 0; }
.people__name { font-weight: 500; }
.people__note { font-size: 0.8rem; color: var(--ink-3); }
.people__controls { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 0.2rem; }
.people__account { font-size: 0.8rem; color: var(--ink-2); }
.people__account-controls { flex-basis: 100%; display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 0.2rem; }
.people__outside { margin-top: 1.1rem; }

.people__picker {
  font: inherit;
  font-size: 0.83rem;
  padding: 0.12rem 0.3rem;
  border: 1px solid var(--rule-2);
  border-radius: var(--radius);
  background: var(--bg);
  color: var(--ink);
}
.people__empty { margin: 0; color: var(--ink-3); }

/* ============================== calendar ============================== */

.calendar { padding: 1.5rem; display: flex; flex-direction: column; gap: 2rem; }

.placeholder {
  padding: 4rem 0;
  text-align: center;
  color: var(--ink-3);
}

.month { animation: reveal 260ms ease-out both; animation-delay: var(--reveal-delay, 0ms); }

@keyframes reveal {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .month { animation: none; }
}

/* The whole year scrolls sideways as one piece, never month by month. */
.board { overflow-x: auto; }

/* As wide as the months themselves — all equally wide, being padded to 31
   days — so a month's separator rule spans exactly its table. */
.board__months { width: max-content; }

/* Months follow each other with no gap; a heavier rule says where one ends. */
.month + .month .grid { border-top: 2px solid var(--rule-2); }

/* The month, said once down the left edge of its block. */
.month__cell {
  position: sticky;
  left: 0;
  z-index: 2;
  width: var(--month-w);
  min-width: var(--month-w);
  max-width: var(--month-w);
  padding: 0.4rem 0.75rem 0.4rem 0;
  vertical-align: top;
  text-align: left;
  font-weight: 400;
  white-space: nowrap;
  background: var(--bg);
}

.month__name {
  display: block;
  font-size: 1.05rem;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.01em;
}

.month__meta {
  display: block;
  font-size: 0.78rem;
  line-height: 1.3;
  color: var(--ink-3);
}

/* An empty month has no day columns to set its width, so its note takes the
   width they would have; the separator rule then spans like any other. */
.month__empty {
  width: calc(var(--name-w) + 31 * var(--cell-w) + var(--sum-w));
  padding: 0.45rem 0;
  font-size: 0.9rem;
  color: var(--ink-3);
}

.grid {
  border-collapse: separate;
  border-spacing: 0;
  /* The gesture is a drag, so never let it start a text selection. */
  user-select: none;
  -webkit-user-select: none;
}

.grid__corner {
  position: sticky;
  left: var(--month-w);
  z-index: 2;
  width: var(--name-w);
  min-width: var(--name-w);
  background: var(--bg);
}

.grid__wd,
.grid__dn {
  width: var(--cell-w);
  min-width: var(--cell-w);
  font-weight: 400;
  text-align: center;
  color: var(--ink-3);
}

.grid__wd { font-size: 0.75rem; line-height: 1.2; padding-top: 0.4rem; }
.grid__dn { font-size: 0.88rem; line-height: 1.3; padding-bottom: 0.2rem; color: var(--ink-2); }

/* Filler after a short month's last day: holds the totals column in place and
   is otherwise invisible. */
.grid__pad { width: var(--cell-w); min-width: var(--cell-w); padding: 0; }

/* Weekend and holiday tinting runs through the header so the column reads as
   one continuous strip from its label down to the last person. */
.grid__wd.is-weekend, .grid__dn.is-weekend { background: var(--weekend); }

/* A holiday column is capped with a solid red rule and its number set in red,
   so it is findable from across the room without hunting for the tooltip. */
.grid__wd.is-holiday,
.grid__dn.is-holiday {
  background: var(--holiday);
  color: var(--holiday-ink);
  cursor: help;
}

.grid__wd.is-holiday { box-shadow: inset 0 3px 0 var(--holiday-mark); font-weight: 600; }
.grid__dn.is-holiday { font-weight: 700; }

.grid__sum-head {
  width: var(--sum-w);
  min-width: var(--sum-w);
  font-size: 0.78rem;
  font-weight: 400;
  text-align: right;
  padding-right: 0.2rem;
  color: var(--ink-3);
}

.grid__person {
  position: sticky;
  left: var(--month-w);
  z-index: 1;
  width: var(--name-w);
  min-width: var(--name-w);
  max-width: var(--name-w);
  padding-right: 0.75rem;
  text-align: left;
  font-weight: 500;
  font-size: 0.95rem;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  background: var(--bg);
}

.cell {
  height: var(--cell-h);
  width: var(--cell-w);
  min-width: var(--cell-w);
  padding: 0;
  background: var(--bg);
  /* A single hairline per cell, drawn on two sides only, so the grid is a
     suggestion of structure rather than a cage. */
  border-right: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
}

.grid__days + .grid__row .cell { border-top: 1px solid var(--rule); }

.cell.is-weekend { background: var(--weekend); }

/* The tint carries all the way down the column, and a hairline in the holiday
   red on both flanks keeps the strip legible even in the middle of a long row. */
.cell.is-holiday {
  background: var(--holiday);
  border-right-color: color-mix(in srgb, var(--holiday-mark) 30%, transparent);
}

.cell.is-workday { cursor: pointer; }
.cell.is-workday:hover { background: var(--accent-soft); }

/*
 * The bar. A run of marked days shares one fill with no internal rules and only
 * its outer ends rounded, so a week off reads as a single mark instead of five
 * squares. shared/runs.js decides where each run begins and ends.
 */
.cell.is-vacation {
  background: var(--accent);
  border-right-color: var(--accent);
  border-bottom-color: var(--accent);
}

.cell.is-vacation.run-start {
  border-top-left-radius: var(--radius);
  border-bottom-left-radius: var(--radius);
}

.cell.is-vacation.run-end {
  border-top-right-radius: var(--radius);
  border-bottom-right-radius: var(--radius);
  border-right-color: var(--rule);
}

.cell.is-vacation:hover { background: color-mix(in srgb, var(--accent) 82%, var(--bg)); }

.cell.is-preview { background: var(--preview); border-right-color: var(--preview); }
.cell.is-preview-off { background: var(--bg); box-shadow: inset 0 0 0 1px var(--preview); }

/* Rows the viewer may not change: no hover, no pointer — nothing to promise. */
.grid__row.is-readonly .cell.is-workday { cursor: default; }
.grid__row.is-readonly .cell.is-workday:not(.is-vacation):hover { background: var(--bg); }
.grid__row.is-readonly .cell.is-vacation:hover { background: var(--accent); }

/* The viewer's own row: an accent rule down the name. */
.grid__row.is-own .grid__person {
  box-shadow: inset 3px 0 0 var(--accent);
  padding-left: 0.45rem;
  font-weight: 600;
}

/* The per-person total, at the end of their own row. */
.grid__sum {
  width: var(--sum-w);
  min-width: var(--sum-w);
  padding: 0 0.15rem 0 0.6rem;
  text-align: right;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--ink);
  border-bottom: 1px solid var(--rule);
}

.grid__days + .grid__row .grid__sum { border-top: 1px solid var(--rule); }
.grid__sum.is-zero { color: var(--ink-3); font-weight: 400; }

/* ============================ year summary ============================ */

.summary { border-top: 1px solid var(--rule-2); padding-top: 1rem; }

.summary__head {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  margin-bottom: 0.5rem;
}

.summary__title { margin: 0; font-size: 1.1rem; font-weight: 600; }
.summary__meta { font-size: 0.85rem; color: var(--ink-3); }
.summary__scroll { overflow-x: auto; }
.summary__table { border-collapse: separate; border-spacing: 0; }

.summary__corner,
.summary__person {
  position: sticky;
  left: 0;
  z-index: 1;
  width: var(--name-w);
  min-width: var(--name-w);
  max-width: var(--name-w);
  text-align: left;
  font-weight: 400;
  padding: 0.2rem 0.75rem 0.2rem 0;
  background: var(--bg);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  border-bottom: 1px solid var(--rule);
}

.summary__month,
.summary__total-head {
  min-width: 3rem;
  padding: 0 0.5rem 0.3rem;
  font-size: 0.78rem;
  font-weight: 400;
  text-align: right;
  color: var(--ink-3);
  border-bottom: 1px solid var(--rule-2);
}

.summary__cell,
.summary__total {
  padding: 0.3rem 0.55rem;
  text-align: right;
  font-size: 0.92rem;
  color: var(--ink-3);
  border-bottom: 1px solid var(--rule);
}

.summary__cell.is-active { color: var(--ink); font-weight: 600; }

/* A month before the person joined stays blank: "not in the plan yet" is not
   the same fact as "took nothing", and a 0 would claim the second. */
.summary__cell.is-absent { background: var(--weekend); }

.summary__total,
.summary__total-head {
  padding-left: 1rem;
  color: var(--ink);
  font-weight: 600;
}

.summary__table tbody tr:last-child :where(td, th) { border-bottom: 0; }

/* ============================== dialog ============================== */

.dialog {
  border: 1px solid var(--rule-2);
  border-radius: 4px;
  background: var(--bg);
  color: var(--ink);
  padding: 0;
  max-width: min(22rem, 92vw);
  box-shadow: 0 16px 40px -20px rgb(0 0 0 / 40%);
}

.dialog::backdrop { background: rgb(16 18 20 / 35%); }
.dialog__form { display: flex; flex-direction: column; gap: 0.6rem; padding: 1.15rem; }
.dialog__title { margin: 0; font-size: 1rem; font-weight: 600; }
.dialog__text { margin: 0; font-size: 0.88rem; color: var(--ink-2); }

.dialog__input {
  font: inherit;
  font-size: 0.95rem;
  padding: 0.45rem 0.6rem;
  border: 1px solid var(--rule-2);
  border-radius: var(--radius);
  background: var(--bg);
  color: var(--ink);
}

.dialog__buttons { display: flex; justify-content: flex-end; gap: 0.4rem; margin-top: 0.3rem; }
.dialog__fields { display: flex; flex-direction: column; gap: 0.6rem; }
.dialog__field { display: flex; flex-direction: column; gap: 0.2rem; }
.dialog__label { font-size: 0.85rem; color: var(--ink-2); }
.dialog__copy { display: flex; gap: 0.4rem; }
.dialog__copy .dialog__input { flex: 1; min-width: 0; }

/* ============================ login pages ============================ */

body.auth {
  min-height: 100vh;
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: 1rem;
}

.auth__card {
  width: min(22rem, 100%);
  padding: 1.5rem;
  border: 1px solid var(--rule-2);
  border-radius: 4px;
}

.auth__title { margin: 0 0 1rem; font-size: 1.1rem; font-weight: 600; }
.auth__note { margin: 0 0 1rem; font-size: 0.88rem; color: var(--ink-2); }
.auth__form { display: flex; flex-direction: column; gap: 0.8rem; }

.auth__label {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  font-size: 0.88rem;
  color: var(--ink-2);
}

.auth__error { margin: 0; font-size: 0.88rem; color: var(--holiday-ink); }
.auth__submit { align-self: flex-start; }
.auth .dialog__input { font-size: 1rem; } /* 16px: iOS zooms into smaller fields */

@media (max-width: 640px) {
  :root { --name-w: 6.5rem; --month-w: 4.5rem; }
  .calendar, .bar, .legend, .people { padding-inline: 1rem; }
  .legend__hint { display: none; }
  .month__cell { padding-right: 0.5rem; }
  .month__name { font-size: 0.9rem; }
  .month__meta { display: none; }
}

/* ================================ print ================================ */

/* Shown only on paper: the toolbar carries this information on screen. */
.print-header { display: none; }

@media print {
  /*
   * A 31-day month needs 272mm at these sizes (16 + 26 + 31 × 7.1 + 10), which
   * fits the 277mm of usable width on A4 landscape with a little to spare.
   */
  @page {
    size: A4 landscape;
    margin: 12mm 10mm;
  }

  /* Paper is always light, whatever theme the screen is in. The attribute
     selector matches the specificity of the theme rules, and coming later it
     wins. */
  :root,
  :root[data-theme] {
    color-scheme: light;

    --cell-w: 7.1mm;
    --cell-h: 5.2mm;
    --month-w: 16mm;
    --name-w: 26mm;
    --sum-w: 10mm;

    /* Ink on paper: lighten the tints so they stay readable when a printer
       renders them, and darken the rules so hairlines do not vanish. */
    --bg: #fff;
    --ink: #000;
    --ink-2: #333;
    --ink-3: #555;
    --rule: #c8c8c8;
    --rule-2: #8a8a8a;
    --weekend: #ededed;
    --holiday: #fbdedb;
    --holiday-mark: #b3271a;
    --holiday-ink: #8c1f14;
    --accent: #1b5e7e;
  }

  /*
   * Browsers drop background colours when printing unless told otherwise, and
   * here the backgrounds ARE the data - without this the vacation bars would
   * print as blank cells.
   */
  *,
  *::before,
  *::after {
    -webkit-print-color-adjust: exact !important;
    print-color-adjust: exact !important;
  }

  body {
    background: #fff;
    font-size: 8pt;
  }

  /* Screen-only chrome. */
  .toolbar,
  .legend,
  .people,
  .notice,
  .dialog,
  .placeholder { display: none !important; }

  /* Set by print.js when printing a single person. */
  .is-print-hidden { display: none !important; }

  .print-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding-bottom: 2mm;
    margin-bottom: 4mm;
    border-bottom: 0.6mm solid #000;
  }

  .print-header__title { margin: 0; font-size: 13pt; font-weight: 700; }
  .print-header__meta { margin: 0; font-size: 8.5pt; color: #333; }

  .calendar { padding: 0; gap: 5mm; }

  /* Never split a month across a page boundary; a half-table is unreadable. */
  .month {
    animation: none;
    break-inside: avoid;
    page-break-inside: avoid;
  }

  .month__cell { padding: 1mm 2mm 1mm 0; }
  .month__name { font-size: 10pt; }
  .month__meta { font-size: 7pt; }

  /* Sticky columns are meaningless on paper and can mis-render. */
  .board,
  .summary__scroll { overflow: visible; }

  .month__cell,
  .grid__corner,
  .grid__person,
  .summary__corner,
  .summary__person {
    position: static;
    background: transparent;
  }

  .grid__wd { font-size: 5.5pt; }
  .grid__dn { font-size: 6.5pt; }
  .grid__sum-head { font-size: 6pt; }
  .grid__person { font-size: 8pt; }
  .grid__sum { font-size: 8pt; }

  .cell { border-right: 0.2mm solid var(--rule); border-bottom: 0.2mm solid var(--rule); }
  .cell.is-workday { cursor: default; }

  /* Hover and drag states have no meaning on paper. */
  .cell.is-preview,
  .cell.is-preview-off { background: var(--bg); box-shadow: none; }

  /* Paper shows the plan, not who printed it. */
  .grid__row.is-own .grid__person { box-shadow: none; padding-left: revert; font-weight: 500; }

  /* The year summary is the end-of-year statistic; give it a page of its own. */
  .summary {
    break-before: page;
    page-break-before: always;
    break-inside: avoid;
    border-top: 0;
    padding-top: 0;
  }

  .summary__title { font-size: 11pt; }
  .summary__cell,
  .summary__total { font-size: 8pt; }
}
