/* Events Calendar */
/* =============== */
/*
  Week-grouped calendar view of events. Mobile-first: the base rules are the phone
  layout, and the >=768px block reflows to the wide layout (centred column, roomier
  cards, inline gear dots, centred modal instead of a bottom sheet).

  The design handoff specifies a fixed dark palette; it is expressed here through the
  app's theme variables so the page follows the user's chosen theme like every other
  page (under a dark theme the result lands very close to the handoff values):

    page background   #14161b  ->  --bs-body-bg
    week card         #1c1f26  ->  --bs-tertiary-bg
    event card        #20232a  ->  --bs-secondary-bg
    dividers          #24262c  ->  --bs-border-color / --bs-border-color-translucent
    primary text      #f0f1f3  ->  --bs-emphasis-color
    muted text        rgba(..) ->  --bs-secondary-color / --bs-tertiary-color
    accent            #f2b90f  ->  --pg-accent (+ --pg-accent-contrast for text on it)
    danger            #ef6a6a  ->  --bs-danger-text-emphasis
*/

.events-calendar {
  display: flex;
  flex-direction: column;
  row-gap: 0.875rem;
}


/* Expand bars */
/* =========== */
/* The head and foot of the grid. Deliberately lighter than a week card - they are the
   edges of the window, not more of its contents, so they sit flat against the page
   rather than reading as another card in the stack. */
.calendar-expand {
  margin: 0;

  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  column-gap: 0.5rem;

  min-height: 2.5rem;

  padding: 0.5rem 0.75rem;

  border: var(--bs-border-width) dashed var(--bs-border-color);
  border-radius: 0.875rem;

  color: var(--bs-secondary-color);

  font-size: 0.8125rem;
  font-weight: 600;

  text-decoration: none;
}

a.calendar-expand:hover,
a.calendar-expand:focus-visible {
  border-style: solid;

  background-color: var(--bs-tertiary-bg);
  color: var(--bs-emphasis-color);
}

/* Nothing that way. Kept in place rather than removed so the grid doesn't shift as the
   reader reaches the end of their events, but muted so it doesn't invite a press. */
.calendar-expand--exhausted {
  border-style: dotted;

  opacity: 0.6;

  font-weight: 500;
  font-style: italic;
}


/* Weeks */
/* ===== */
/* The run of weeks as a whole, styled where each week used to style itself - one
   surface rather than a stack of separate cards, so paging from one week into the
   next reads as turning a page rather than crossing a gap between two boxes. */
.calendar-weeks {
  display: flex;
  flex-direction: column;

  background-color: var(--bs-tertiary-bg);

  border: var(--bs-border-width) solid var(--bs-border-color);
  border-radius: 0.875rem;

  overflow: hidden;
}

/* A week itself carries no box of its own any more (see .calendar-weeks) - what still
   says where one ends and the next begins is its header, marked out below.

   Sized and coloured as a label rather than a heading: on its own card a week's range
   was the biggest thing on it and could afford to read as a title, but inline among
   the day rows a heading-sized one looks like a stray paragraph dropped into a table.
   A tinted strip the weight of the weekday labels it sits above reads as wayfinding
   instead - present enough to find while scrolling, quiet enough not to compete with
   the events actually on the page. */
.calendar-week__header {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  column-gap: 0.5rem;

  padding: 0.4375rem 0.75rem;

  background-color: var(--bs-secondary-bg);

  border-bottom: var(--bs-border-width) solid var(--bs-border-color);
}

/* The seam between two weeks - the one place the continuous sheet still has to say
   "new week starts here". Twice the day rows' own hairline: those only have to
   separate one date from the next, so they stay soft and translucent, but this is the
   line doing the one job that used to belong to a whole gap between cards, and it
   reads better carrying a little more weight than the ordinary rhythm it interrupts.
   Skipped on the very first header, which already has the sheet's own top edge to sit
   against. */
.calendar-week + .calendar-week .calendar-week__header {
  border-top: calc(var(--bs-border-width) * 2) solid var(--bs-border-color);
}

.calendar-week__range {
  margin: 0;

  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;

  color: var(--bs-secondary-color);
}


/* Day row */
/* ======= */
.calendar-day {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  column-gap: 0.5rem;

  padding: 0.625rem 0.375rem;

  border-bottom: var(--bs-border-width) solid var(--bs-border-color-translucent, var(--bs-border-color));
}

.calendar-day:last-child {
  border-bottom: none;
}

/* A day with no events collapses to a slim single line */
.calendar-day--empty {
  align-items: center;

  padding: 0.25rem 0.375rem;
}

.calendar-day__label {
  flex: 0 0 auto;

  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  row-gap: 0.125rem;

  width: 2.375rem;

  padding-top: 0.25rem;
}

.calendar-day--empty .calendar-day__label {
  padding-top: 0;
}

.calendar-day__weekday {
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.04em;

  color: var(--bs-secondary-color);
}

.calendar-day__date {
  display: flex;
  align-items: center;
  justify-content: center;

  font-size: 0.9375rem;
  font-weight: 800;

  color: var(--bs-body-color);
}

/* Today's date sits in a filled accent circle */
.calendar-day__date--today {
  width: 1.5rem;
  height: 1.5rem;

  border-radius: 999px;

  background-color: var(--pg-accent);
  color: var(--pg-accent-contrast);
}

.calendar-day__events {
  flex: 1 1 auto;

  min-width: 0;

  display: flex;
  flex-direction: column;
  row-gap: 0.375rem;
}

.calendar-day__no-events {
  font-size: 0.75rem;
  font-weight: 600;
  font-style: italic;

  color: var(--bs-tertiary-color);
}


/* Event card */
/* ========== */
/* The event's colour is the card's left edge rather than a bar sitting inside it: the
   whole height of the row is coloured, so a column of cards reads as a column of
   colours down the margin - and an event with no colour keeps a neutral edge rather
   than a hole where one would be. */
.calendar-event {
  display: flex;
  flex-direction: row;
  align-items: center;
  column-gap: 0.625rem;

  min-height: 3.25rem;
  min-width: 0;

  padding: 0.5rem 0.625rem;

  background-color: var(--bs-secondary-bg);
  /* --bs-border-color rather than --bs-secondary-color: a structural line colour with
     no tint of its own, so the neutral edge reads as a border rather than as a pale
     colour someone picked. (A dashed edge was tried here too, to match the "no colour"
     mark the two dialogs use, but border-radius plus this card's own overflow:hidden
     mangles a dashed border into a stray mark instead of a clean line - solid stays.) */
  border-left: 0.375rem solid var(--calendar-event-colour, var(--bs-border-color));
  border-radius: 0.625rem;

  overflow: hidden;
}

.calendar-event--completed {
  opacity: 0.65;
}

/* The card body is the overlay's hit target; the completed toggle is a sibling of
   it, so tapping the toggle can never also open the overlay. */
.calendar-event__main {
  flex: 1 1 auto;

  display: flex;
  flex-direction: row;
  align-items: center;
  column-gap: 0.625rem;

  min-width: 0;

  cursor: pointer;
}

.calendar-event__main:focus-visible {
  outline: 0;

  border-radius: 0.375rem;
  box-shadow: 0 0 0 0.2rem rgba(var(--bs-primary-rgb), 0.4);
}

.calendar-event__text {
  flex: 1 1 auto;

  min-width: 0;

  display: flex;
  flex-direction: column;
  row-gap: 0.125rem;

  text-align: left;
}

.calendar-event__title {
  font-size: 0.875rem;
  font-weight: 700;

  color: var(--bs-emphasis-color);

  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.calendar-event--completed .calendar-event__title {
  color: var(--bs-secondary-color);
  text-decoration: line-through;
}

.calendar-event__meta {
  display: flex;
  flex-direction: row;
  align-items: center;
  column-gap: 0.375rem;

  min-width: 0;

  font-size: 0.75rem;
  font-weight: 700;

  color: var(--bs-secondary-color);
}

.calendar-event__location {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* "18:00", when the event has one - the same shape as the day-count pill beside
   it (below): both are short, scannable facts about the card, so they read as
   the same kind of thing rather than one being a label and the other a badge. */
.calendar-event__time,
.calendar-event__day-count {
  flex: 0 0 auto;

  padding: 0.05rem 0.35rem;

  border-radius: 999px;

  background-color: var(--bs-tertiary-bg);
  color: var(--bs-tertiary-color);

  font-size: 0.6875rem;
  font-weight: 700;
  white-space: nowrap;
}

/* Weather badge. Rendered by the calendar-forecast controller, so it stays empty
   (and takes no space) until a forecast is available for the day. */
.calendar-event__weather {
  flex: 0 0 auto;

  display: flex;
  flex-direction: row;
  align-items: center;
  column-gap: 0.25rem;

  font-size: 0.75rem;
  font-weight: 700;

  color: var(--bs-secondary-color);
}

.calendar-event__weather:empty {
  display: none;
}

.calendar-event__weather-icon {
  font-size: 0.8125rem;
  line-height: 1;
}


/* Weather tones */
/* ============= */
/*
  The colours a forecast is normally printed in, so a glyph can be read at a glance
  without being read: sun amber, cloud grey, rain blue, snow pale. Set by the forecast
  controller, which picks the tone from the same condition it picks the icon from.

  They are chosen against a dark background, which is what the list view's cards and an
  event's overlay give them. Where the surface is an event's colour instead - a month
  pill, a band - the icon carries a dark chip of its own so the tone still has the
  background it was picked for, rather than being abandoned for a flat contrast colour.
*/
.weather-tone--sun {
  color: #f5a623;
}

.weather-tone--sun-cloud {
  color: #efa940;
}

.weather-tone--cloud {
  color: #97a4b4;
}

.weather-tone--rain {
  color: #4a94dd;
}

.weather-tone--rain-heavy {
  color: #3878bb;
}

.weather-tone--storm {
  color: #7d6fd1;
}

.weather-tone--snow {
  color: #a8d4ee;
}

.weather-tone--sleet {
  color: #79b0d4;
}

.weather-tone--fog {
  color: #9aa3ad;
}

.weather-tone--wind {
  color: #8ba6bd;
}

/* No-items warning */
/* ================= */
/* An event nothing has been packed for yet, marked where the event is drawn rather than
   only inside its overlay - the whole point of it is to be answered without opening
   anything. Amber rather than red: an event with no gear on it isn't broken, it is a
   piece of planning still to do.

   Two halves, because a glyph the size of a full stop is not something a reader scanning
   a month finds: the whole entry takes an amber ring, which is what carries across the
   grid, and the triangle names what the ring means once the eye is there. */
.calendar-event__warning {
  flex: 0 0 auto;

  color: var(--bs-warning);

  font-size: 0.875rem;
  line-height: 1;
}

/* The ring. Drawn around the outside of the card rather than inside it, so it takes in
   the event's colour bar down the left edge instead of starting after it - one ring
   round the whole card, with the colour marker inside it where it belongs.

   A shadow rather than a border, so it costs no layout: a marked card is the same size
   as an unmarked one and the column of them doesn't step in and out. */
.calendar-event--unassigned {
  box-shadow: 0 0 0 2px var(--bs-warning);
}

/* Completed toggle */
.calendar-event__check-form {
  flex: 0 0 auto;

  display: flex;

  margin: 0;
}

.calendar-event__check {
  display: flex;
  align-items: center;
  justify-content: center;

  width: 1.375rem;
  height: 1.375rem;

  padding: 0;

  border: 1.5px solid var(--bs-secondary-color);
  border-radius: 999px;

  background-color: transparent;
  /* The tick is only revealed once complete - the empty circle is the "not yet" state */
  color: transparent;

  font-size: 0.6875rem;
  line-height: 1;

  cursor: pointer;
}

.calendar-event--completed .calendar-event__check {
  border-color: var(--pg-accent);
  background-color: var(--pg-accent);
  color: var(--pg-accent-contrast);
}


/* Dragging an event to another day */
/* ================================ */
/*
  Single-day events can be dragged onto another day of the grid (see the calendar-drag
  controller): the event itself stays put and dims while a copy of it - the ghost -
  follows the pointer, and the day under the pointer lights up as the drop target.

  Both views take the gesture, so these are named for the drag rather than for the
  card or the pill, and the two views differ only where their own shapes require it.
*/

/* Only a movable event offers the grab cursor, so the pointer says which of them take
   the gesture before one is tried. */
.calendar-event[data-calendar-drag-url] .calendar-event__main,
.calendar-month__pill[data-calendar-drag-url] {
  cursor: grab;

  /* Stops the press-and-hold that starts a touch drag from raising the callout menu */
  -webkit-touch-callout: none;
}

/* Held for the whole drag, so the cursor doesn't flicker back to a text caret as the
   pointer passes over the labels between days. */
body.calendar-dragging,
body.calendar-dragging * {
  cursor: grabbing !important;

  user-select: none;
  -webkit-user-select: none;
}

/* Where the event came from - kept in place, so releasing over nothing leaves the grid
   exactly as it was rather than having to put anything back. */
.calendar-drag-source {
  opacity: 0.3;
}

/* Saving. The card is replaced by the turbo stream a moment later; this is only what
   the gap between release and redraw looks like. */
.calendar-drag-saving {
  opacity: 0.5;
}

/* The move didn't save - the card stays on its original day and says so briefly. */
.calendar-drag-failed {
  box-shadow: inset 0 0 0 1.5px var(--bs-danger-text-emphasis);
}

/* The card under the pointer. Fixed to the viewport and out of the way of hit
   testing, so the grid underneath still reports the day being aimed at. */
.calendar-drag-ghost {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 1080;

  pointer-events: none;

  box-shadow: 0 0.75rem 1.5rem rgba(0, 0, 0, 0.45);

  opacity: 0.95;
}

/* The day the event would land on */
.calendar-drop-target {
  background-color: rgba(var(--bs-primary-rgb), 0.1);

  box-shadow: inset 0 0 0 1.5px var(--pg-accent);
}

/* A list-view day row has no border of its own, so the highlight brings a corner with
   it; a month cell already has one and keeps it, so the outline follows the cell. */
.calendar-day.calendar-drop-target {
  border-radius: 0.5rem;
}

.calendar-drop-target .calendar-day__no-events {
  color: var(--bs-secondary-color);
}

/* The month view's ghost is a lone pill, which would otherwise be drawn transparent
   against the page - it takes the pill background with it. */
.calendar-drag-ghost.calendar-month__pill {
  background-color: var(--bs-secondary-bg);
}


/* Detail overlay */
/* ============== */
/*
  One native <dialog> per event, styled as a bottom sheet on mobile and a centred
  modal on wider screens. Builds on the shared dialog.pg-modal base.
*/
dialog.pg-modal.calendar-sheet {
  width: 100%;
  max-width: none;
  /* dvh, not vh - see calendar-form-sheet's own note in calendar_form.css on why
     a sheet pinned to the bottom of the viewport needs its max-height to track
     the phone browser's own chrome instead of assuming it's always collapsed. */
  max-height: 85vh;
  max-height: 85dvh;

  /* auto top + 0 bottom pins the sheet to the bottom of the viewport */
  margin: auto auto 0;

  border-radius: 1.125rem 1.125rem 0 0;

  background-color: var(--bs-tertiary-bg);
}

.calendar-sheet__content {
  padding: 0.625rem 1.125rem 1.125rem;
}

/* Drag-handle affordance - the mobile sheet's dismiss cue */
.calendar-sheet__handle {
  width: 2.25rem;
  height: 0.25rem;

  margin: 0.25rem auto 0.75rem;

  border-radius: 999px;

  background-color: var(--bs-border-color);
}

/* A hairline under the header, matching the plain .pg-modal dialogs elsewhere in the
   app (see components/pg_modal.css's own .modal-header) - a calendar-sheet header
   used to go without one, on the theory that the title-to-first-field gap already
   separated it, but that left it the one kind of dialog header in the app without a
   division line. */
.calendar-sheet__header {
  flex: 0 0 auto;

  display: flex;
  flex-direction: row;
  align-items: center;
  column-gap: 0.625rem;

  padding: 0.125rem 0.25rem 0.75rem;

  border-bottom: var(--bs-border-width) solid var(--bs-border-color);
}

.calendar-sheet__heading {
  flex: 1 1 auto;

  min-width: 0;
}

.calendar-sheet__title {
  margin: 0;

  font-size: 1.0625rem;
  font-weight: 800;

  color: var(--bs-emphasis-color);
}

.calendar-sheet__date {
  margin: 0;

  font-size: 0.8125rem;
  font-weight: 600;

  color: var(--bs-secondary-color);
}

/* The colour bar doubles as the swatch picker's toggle - it is the only route to
   the picker, so it has to read as tappable. */
.calendar-sheet__colour {
  flex: 0 0 auto;
}

.calendar-sheet__colour-bar {
  width: 0.625rem;
  height: 2.25rem;

  padding: 0;

  border: none;
  border-radius: 0.25rem;

  background-color: var(--calendar-event-colour);

  cursor: pointer;
}

/* No colour set - a solid neutral fill, the same treatment (and the same
   --bs-border-color) the list view's own left-edge stripe uses for "no colour" -
   so the two read as the same shade rather than one looking hollow next to the
   other's filled bar. */
.calendar-sheet__colour-bar--none {
  background-color: var(--bs-border-color);
}

/* Sized to its content rather than a fixed width: the swatch grid below is the
   one thing that decides how wide this is, so there's no magic number here to
   keep in sync if the swatch size, gap or column count ever changes. */
.calendar-sheet__colour-menu {
  width: fit-content;
  min-width: 0;
  /* .pg-menu's 10rem min-width would otherwise widen past the swatch grid */

  padding: 0.625rem;
}

/* Column count is set inline per-render (near-square for however many swatches
   the palette holds - see Gear::CalendarHelper#calendar_colour_swatch_columns),
   so the grid - not the menu - fixes the shape, and it self-adjusts if the
   palette's size ever changes. */
.calendar-sheet__swatch-group {
  display: grid;
  grid-template-columns: repeat(var(--calendar-swatch-columns, 4), 1.75rem);
  gap: 0.5rem;

  /* Hug the grid's own columns rather than stretching to the menu's width (which
     "Remove colour" can end up setting) - centred, so any left-over width splits
     evenly either side instead of bunching into a one-sided gap. */
  width: fit-content;
  margin-inline: auto;

  padding-bottom: 0.5rem;
}

.calendar-sheet__swatch-form {
  display: inline-flex;

  margin: 0;
}

.calendar-sheet__swatch {
  width: 1.75rem;
  height: 1.75rem;

  padding: 0;

  border: none;
  border-radius: 999px;

  cursor: pointer;
}

/* Header icon actions - complete, edit and delete. These are the only route to
   those actions, so they sit on the header row rather than in a list. */
.calendar-sheet__tools {
  flex: 0 0 auto;

  display: flex;
  flex-direction: row;
  align-items: center;
  column-gap: 0.375rem;
}

.calendar-sheet__tool-form {
  display: flex;

  margin: 0;
}

/* One outlined square for every control in the header, the close included, so the
   row reads as a single set of buttons. */
.calendar-sheet__tool,
.calendar-sheet__close {
  flex: 0 0 auto;

  display: flex;
  align-items: center;
  justify-content: center;

  width: 2rem;
  height: 2rem;

  padding: 0;

  border: var(--bs-border-width) solid var(--bs-border-color);
  border-radius: 0.5rem;

  background-color: transparent;
  color: var(--bs-secondary-color);

  font-size: 0.875rem;
  line-height: 1;
  text-decoration: none;

  cursor: pointer;
}

.calendar-sheet__tool--danger {
  border-color: rgba(var(--bs-danger-rgb), 0.4);
  color: var(--bs-danger-text-emphasis);
}

/* Completed toggle - the tick is always drawn; it is the filled square that marks
   the event as done, matching the card's toggle in colour if not in shape. */
.calendar-view--completed .calendar-sheet__tool--complete {
  border-color: var(--pg-accent);
  background-color: var(--pg-accent);
  color: var(--pg-accent-contrast);
}

.calendar-sheet__close {
  /* The mobile sheet dismisses by backdrop tap, drag handle or Escape */
  display: none;
}

/* Calendar chrome buttons */
/* ======================= */
/* The page's own controls - "Add Event", "Select", the month arrows and "Today" - are
   .pg-button--chrome, which lives in application/button.css because the packing lists
   wear the same look. Only what is particular to this page's bar is here; the shared
   look is one copy so the two screens cannot drift apart.

   They share a height with the List/Month toggle beside them, which is why the toggle
   below repeats the same metrics. */


/* View toggle */
/* =========== */
/* The List/Month switch in the control bar. A pair of links in a shared trough, the
   active one filled with the accent - the same shape as a segmented control, so the
   two options read as one choice rather than as two separate buttons. */
.calendar-view-toggle {
  display: flex;
  flex-direction: row;
  column-gap: 0.1875rem;

  padding: 0.1875rem;

  background-color: var(--bs-secondary-bg);
  border: var(--bs-border-width) solid var(--bs-border-color);
  border-radius: 0.5625rem;
}

/* The two options share the switch's width equally rather than each taking what its own
   word needs, so the switch is symmetrical about its own centre - which matters once it
   is set to a width of its own below. */
.calendar-view-toggle__option {
  flex: 1 1 0;

  display: flex;
  align-items: center;
  justify-content: center;

  min-height: 1.75rem;
  padding: 0 0.75rem;

  border-radius: 0.4375rem;

  color: var(--bs-secondary-color);

  font-size: 0.75rem;
  font-weight: 700;
  text-decoration: none;
  white-space: nowrap;
}

.calendar-view-toggle__option:hover {
  color: var(--bs-emphasis-color);
}

.calendar-view-toggle__option--active,
.calendar-view-toggle__option--active:hover {
  background-color: var(--pg-accent);
  color: var(--pg-accent-contrast);
}


/* Month view */
/* ========== */
.calendar-month {
  display: flex;
  flex-direction: column;
  row-gap: 1rem;
}

/* Calendar control bar */
/* ==================== */
/* Add Event and the List/Month switch are held to one width, so the two ends of the bar
   balance and the month nav between them reads as centred rather than as nearly so. The
   width is the wider of the two at its natural size (the switch), so neither is
   squeezed; it is one value in one place because its whole purpose is that they match.
   Held on the bar rather than on the controls, so it applies in both views and the
   switch doesn't change size as the reader moves between them. */
.control-bar-container--inline {
  --calendar-bar-control-width: 7.5rem;
}

.control-bar-container--inline .calendar-add-button,
.control-bar-container--inline .calendar-view-toggle {
  min-width: var(--calendar-bar-control-width);
}


/* Month nav */
/* ========= */
/* Lives in the page's control bar between Add Event and the List/Month switch, centred
   there by the spacers either side of it. */
.calendar-month-nav {
  display: flex;
  flex-direction: row;
  align-items: center;
  column-gap: 0.5rem;

  min-width: 0;
}

/* One box holding both arrows and the name, built like the List/Month switch beside it
   - same surface, same border, same radius - because it is the same kind of thing: one
   control, with parts. */
.calendar-month-nav__group {
  display: flex;
  flex-direction: row;
  align-items: center;
  column-gap: 0.1875rem;

  min-width: 0;

  padding: 0.1875rem;

  background-color: var(--bs-secondary-bg);
  border: var(--bs-border-width) solid var(--bs-border-color);
  border-radius: 0.5625rem;
}

/* Segments of that box rather than buttons in their own right, so they carry no border
   or fill of their own until the pointer is on them. Deliberately not the accent: in
   this page a filled accent means the state a thing is in - today, the view showing -
   and an arrow is an action, not a state. */
.calendar-month-nav__button {
  flex: 0 0 auto;

  display: flex;
  align-items: center;
  justify-content: center;

  width: 1.875rem;
  min-height: 1.75rem;
  padding: 0;

  border-radius: 0.4375rem;

  color: var(--bs-secondary-color);

  font-size: 0.875rem;
  line-height: 1;
  text-decoration: none;
}

.calendar-month-nav__button:hover,
.calendar-month-nav__button:focus-visible {
  background-color: var(--bs-tertiary-bg);
  color: var(--bs-emphasis-color);
}

/* Fixed width, so stepping from a short month name to a long one doesn't shift the
   arrows either side of it.

   One step above the bar's labels rather than three: it is the value the arrows change,
   so it is the thing to read first, but it is still a control's text and not a heading
   (which is what it was, above the grid, at the size it used to be). The step is carried
   by weight as much as size. */
.calendar-month-nav__label {
  flex: 0 1 auto;

  margin: 0;

  width: 8.5rem;
  min-width: 0;

  font-size: 0.8125rem;
  font-weight: 800;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;

  color: var(--bs-emphasis-color);
}

/* One of the two names shows at a time - the long one here, the short one on a phone */
.calendar-month-nav__label-short {
  display: none;
}

/* A pair of equal slots, one either side of the arrows. The right one holds Today and
   holds its width whether or not there is anywhere to go back to, so the arrows don't
   shift as the reader steps onto and off the current month; the left one is empty and
   exists only to balance it, so that the arrows and the name between them are what sits
   on the bar's centre line rather than sitting half a button to the left of it. */
.calendar-month-nav__slot {
  flex: 0 0 auto;

  display: flex;

  width: 4.25rem;
}

.calendar-month-nav__today {
  justify-content: flex-end;
}

/* Grid */
/*
  Every cell is the same height, in every month. Grid rows would otherwise size to
  their tallest cell, so a week holding a full cell would stand taller than a quiet
  one and the grid would change shape as the reader steps through months.

  The rows share the screen instead, and the parts of a cell are given fixed sizes
  below so that what a row has left over is a whole number of events rather than an
  awkward remainder. How many events that is is not stated anywhere: it is whatever
  the row turns out to be able to hold, which the calendar-month-capacity controller
  reads back off these same sizes and turns into the day's "+N more" line.

  So changing any of these sizes changes how much a cell shows, and the count beside
  it follows on its own.
*/
.calendar-month__grid {
  display: flex;
  flex-direction: column;
  row-gap: 0.5rem;

  /* Tight, because everything in a cell lines up on it: the date, the bars under it and
     the "+N more" line all start at this edge, and a day only has a seventh of the grid
     to give away. */
  --calendar-cell-padding: 0.25rem;
  --calendar-cell-gap: 0.375rem;
  --calendar-date-height: 1.375rem;
  /* One line of event, which is the unit every event on the sheet is a whole number of:
     a single-day pill, a multi-day band and a pill whose title needs a second line are
     one, one and exactly two of these. The full size where the row allows it, and never
     under the floor; what falls between is --calendar-event-unit. */
  --calendar-event-height: 1.375rem;
  --calendar-event-height-min: 0.9375rem;
  --calendar-pill-gap: 0.25rem;
  --calendar-overflow-height: 0.9375rem;

  /* The line between one day and the next. One value, used as the gap in both the
     header and the weeks, so the two stay in step. */
  --calendar-rule-width: 1px;

  /* However many runs cross a day, it keeps most of itself for its own events */
  --calendar-lanes-max: 3.75rem;
}

/* The weekday header and the weeks are separate grids rather than one, so the header
   doesn't have to be re-stated on every row. Their columns are defined identically,
   which is what keeps the two aligned. */
.calendar-month__weekdays,
.calendar-month__week {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: var(--calendar-rule-width);
}

/* One line of event, sized from the row rather than from the day. Every event on the
   sheet is a whole number of these: a pill, a band and a two-line pill are one, one and
   exactly two, so nothing on the grid is a size of its own.

   The unit is its full height wherever the row allows it, and steps down together
   across the whole grid where a short window doesn't: what a tight row costs is a
   shorter bar everywhere, never a shorter bar on the busy days only. Taken from the
   week's height (100cqh, see the week's container-type) less what the cell's padding,
   its date and the gaps around two pills spend - the arithmetic is the layout's rather
   than a number script measured and might read at the wrong moment.

   Rounded down to whole pixels, so that a row height the browser can only divide into
   fractions doesn't paint one bar a pixel taller than the one beside it.

   Stated on the cell and on the band overlay rather than on the week, since an element
   can't query its own size: both are children of the week, which is the container. The
   band step is stated here too, and not up with the other sizes: a custom property's
   own vars resolve on the element it is declared on, so one written on the grid would
   be looking for a unit that only exists further down. */
.calendar-month__cell,
.calendar-month__bands {
  --calendar-event-unit: round(down,
      clamp(var(--calendar-event-height-min),
        calc((100cqh - (2 * var(--calendar-cell-padding)) - var(--calendar-date-height) - var(--calendar-cell-gap) - var(--calendar-pill-gap)) / 2),
        var(--calendar-event-height)),
      1px);

  /* The space one lane of bands takes at the foot of a cell */
  --calendar-band-step: calc(var(--calendar-event-unit) + var(--calendar-rule-width));
}

.calendar-month__weekdays {
  margin-bottom: 0.375rem;
  padding: 0 var(--calendar-rule-width);
}

/* A month is four, five or six weeks depending on where its days fall, and a month view
   that has to be scrolled to be seen isn't showing a month. So the page is held to the
   viewport and the grid takes what is left of it, with the rows sharing that equally -
   whatever the month's shape, it fills the screen exactly and never overruns it.

   Done in layout rather than by measuring in script, which is the same way the planner
   fills its page: a measured height is a number that can be taken at the wrong moment
   or in the wrong browser, and this one can't. The chain has to be unbroken, so every
   step from the page container down carries min-height: 0 - a flex item's floor is its
   content, and one that keeps it would push the grid past the bottom of the screen. */
#page_container:has(.calendar-month) {
  height: 100dvh;
}

/* The page's own padding is generous, which suits a column of text and not a grid that
   is trying to be a whole month at once. The sheet takes the width instead: every pixel
   it gains is spread across seven days, so the padding is worth more as title. */
#page_content:has(.calendar-month) {
  flex-grow: 1;

  min-height: 0;

  display: flex;
  flex-direction: column;

  padding: 0.5rem 0.625rem 0.625rem;
}

.calendar-month,
.calendar-month__grid,
.calendar-month__cells {
  flex: 1 1 auto;

  min-height: 0;
}

/* One ruled surface rather than a tray of tiles. The rules are the grid's own colour
   showing through the gaps between its cells, which is what gives every day exactly one
   line between it and its neighbour - a border each would double them up, and a day
   would be a card again. The whole is enclosed and clipped, so the corners round once
   at the outside rather than forty-two times within. */
.calendar-month__cells {
  display: flex;
  flex-direction: column;
  row-gap: var(--calendar-rule-width);

  background-color: var(--bs-border-color);
  border: var(--bs-border-width) solid var(--bs-border-color);
  border-radius: 0.625rem;

  overflow: hidden;
}

/* A week shares the height with its siblings, whatever the month's shape */
.calendar-month__week {
  position: relative;

  /* A size container, so a pill can be sized from the row's height rather than from
     what happens to be in one particular day (see --calendar-event-unit). The week
     rather than the cell: every week is the same height, while a cell's own box is
     shorter in a week carrying bands - measuring from the cell would make the pills in
     a busy week smaller than the ones beside them. Safe to contain, since the height
     comes from the grid and never from what the week holds. */
  container-type: size;

  flex: 1 1 0;

  min-height: 0;

  background-color: var(--bs-border-color);
}

.calendar-month__weekday {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-align: center;

  color: var(--bs-secondary-color);
}

/* Drawn back like the cells below them, so the week's shape is legible in the header
   as well as in the grid */
.calendar-month__weekday--weekend {
  color: var(--bs-tertiary-color);
}

/* A day is a box on the sheet, not a card: no border and no corners of its own, since
   the rules between the cells already say where one day ends and the next begins.

   The foot is reserved for whatever bands cross this day - the day itself says how many,
   not its row, since a run two days long in the middle of the week costs Sunday nothing.
   The reservation is capped so that a day carrying an unusual number of runs squeezes
   the bands rather than leaving itself nowhere to put its own events. */
.calendar-month__cell {
  /* What this week's bands cost the foot of the cell. Named rather than written into
     the padding, because the pills have to know it too - it is space they can't use. */
  --calendar-lanes-space: min(calc(var(--calendar-cell-padding) + (var(--calendar-lanes, 0) * var(--calendar-band-step))),
      var(--calendar-lanes-max));

  display: flex;
  flex-direction: column;
  row-gap: var(--calendar-cell-gap);

  min-width: 0;

  padding: var(--calendar-cell-padding);
  padding-bottom: var(--calendar-lanes-space);

  background-color: var(--bs-tertiary-bg);

  overflow: hidden;
}

/* Saturday and Sunday sit a shade back from the working week - recessed rather than
   highlighted, since the point is a rhythm to count along, not a thing to look at. */
.calendar-month__cell--weekend {
  background-color: var(--bs-body-bg);
}

/* A day of a neighbouring month. It keeps its place and its date so the sheet stays a
   whole rectangle, but is sunk back to the page's own colour and carries no events: it
   is a day this month can say nothing about. Stated after the weekend rule, since a day
   outside the month is that first and a Saturday second. */
.calendar-month__cell--outside,
.calendar-month__cell--outside.calendar-month__cell--weekend {
  background-color: var(--bs-body-bg);
}

/* Today. The date already wears the accent; the cell carries a quiet echo of it, so the
   day can be found at a glance in a sheet of forty without shouting over its events.
   An inset line rather than a border - on a ruled sheet a cell has no border to change,
   and a line drawn inside doesn't shift anything around it. */
.calendar-month__cell--today {
  background-color: var(--bs-secondary-bg);

  box-shadow: inset 0 0 0 var(--bs-border-width) var(--pg-accent);
}

/* Square, so the row is the same height whether or not the day is today - the accent
   circle then fills it exactly rather than making that one row taller */
.calendar-month__date {
  flex: 0 0 auto;
  align-self: flex-start;

  display: flex;
  align-items: center;
  justify-content: center;

  width: var(--calendar-date-height);
  height: var(--calendar-date-height);

  font-size: 0.8125rem;
  font-weight: 800;
  line-height: 1;

  /* The cell's anchor, so it reads at least as clearly as the events under it */
  color: var(--bs-emphasis-color);
}

/* A neighbouring month's date: present enough to keep the grid whole, quiet enough to
   be plainly not part of this month */
.calendar-month__cell--outside .calendar-month__date {
  color: var(--bs-tertiary-color);
  opacity: 0.6;
}

/* Today's date sits in a filled accent circle, as it does in the list view */
.calendar-month__date--today {
  border-radius: 999px;

  background-color: var(--pg-accent);
  color: var(--pg-accent-contrast);
}

/* Takes whatever the row has spare, so that what follows it - the "+N more" line and
   any multi-day bands - is held to the foot of the cell however tall the row is.

   No bleed of its own: the cell's padding is the line everything in the day starts on,
   so the bars sit exactly under the date rather than reaching past it. */
.calendar-month__pills {
  flex: 1 1 auto;

  display: flex;
  flex-direction: column;
  row-gap: var(--calendar-pill-gap);

  min-width: 0;
  min-height: 0;

  /* The box isn't held to a whole number of pills here. It used to be, by rounding a
     calc of the row's height down to one - but that sum is fractional, and a row a
     hair short of two pills lost the whole of the second rather than the hair. What
     fits is measured off the laid-out cell instead, and the pills past it are hidden
     rather than cut off (see the calendar-month-capacity controller), so there is
     nothing left for a box of exactly the right size to do.

     The clip stays as the guard for the moment before the controller has run, and for
     a cell it hasn't reached: an event too many is cut off rather than pushing the
     "+N more" line down into the bands below it. */
  overflow: hidden;
}

/* An event in a month cell: too small for the list view's card, so it keeps only the
   colour and the title, and opens the same detail overlay.

   The colour is the box rather than a dot on it, which is the same shape a multi-day
   band takes - one visual language for an event at every width, and the title gets the
   width the dot used to cost. An event with no colour keeps a neutral box. */
.calendar-month__pill {
  /* Neither grows nor shrinks: its height is a whole number of units, and a pill that
     gave way to a crowded day would make the same event a different size from one cell
     to the next. A lone event in a tall cell is a pill with space under it, not a slab;
     two events in a tight cell are two pills of the same height as everyone else's. */
  flex: 0 0 auto;

  display: flex;
  flex-direction: row;
  align-items: center;
  column-gap: 0.25rem;

  min-width: 0;
  /* From the title: one line makes a one-line pill, and the second line - where a cell
     is narrow enough to allow one - makes it exactly twice as tall, since the title's
     line height is the unit and the pill spends nothing above or below it. */
  height: auto;

  /* Roomier than it looks like it needs to be. The corners are square now, so the full
     height of the bar's edge stands right beside the first letter - where a rounded
     corner curved away from it - and a gap that read as generous when they were rounded
     reads as a collision now. */
  padding: 0 0.5rem;

  /* --bs-border-color rather than --bs-secondary-bg: a cell can be any of several
     backgrounds (the ordinary tertiary-bg, a weekend's body-bg, today's own
     secondary-bg), and only a tone lighter than all of them stays visible on every
     one - secondary-bg matched today's cell almost exactly and the pill vanished
     into it. */
  background-color: var(--calendar-event-colour, var(--bs-border-color));
  border: none;
  /* Square, like the bands and the sheet itself. A rounded chip on a ruled grid reads
     as something laid on top of the calendar rather than marked into it. */
  border-radius: 0;

  cursor: pointer;
  overflow: hidden;
}

/* A pill the day hasn't room for. Stated because the rules above give the pill and the
   overflow line a display of their own, which a plain `hidden` attribute would lose to.
   Both are hidden rather than removed: what fits changes with the size of the window,
   and an event that comes back into view is the same element it always was. */
.calendar-month__pill[hidden],
.calendar-month__overflow[hidden] {
  display: none;
}

.calendar-month__pill:focus-visible {
  outline: 0;

  box-shadow: 0 0 0 0.2rem rgba(var(--bs-primary-rgb), 0.4);
}

/* One line, or two where a cell is narrow enough to need the second (see the phone
   block). Long words break rather than push the line out of the cell: a broken word
   still says more than no word. */
.calendar-month__pill-title {
  flex: 1 1 auto;

  display: -webkit-box;
  -webkit-line-clamp: var(--calendar-pill-lines, 1);
  -webkit-box-orient: vertical;

  min-width: 0;

  font-size: 0.6875rem;
  font-weight: 700;
  /* The unit itself, so the pill's height is the line count times the unit exactly */
  line-height: var(--calendar-event-unit);
  text-align: left;

  color: var(--calendar-event-contrast, var(--bs-emphasis-color));

  white-space: normal;
  overflow-wrap: anywhere;
  overflow: hidden;
}

/* The same warning on a pill or a band. Here the surface is the event's own colour,
   which can be anything - including an amber close enough to the marker to swallow it -
   so the glyph is drawn on a dark halo rather than a flat contrast colour: it holds its
   own against a pale colour without becoming a black box on a dark one, which a filled
   chip was on every uncoloured pill. */
.calendar-month__pill-warning,
.calendar-month__band-warning {
  flex: 0 0 auto;

  color: #ffce54;

  font-size: 0.6875rem;
  line-height: 1;
  text-shadow: 0 0 2px rgba(0, 0, 0, 0.75);
}

/* The ring, as the list view's cards take one. Inset, so a marked pill is exactly the
   size of an unmarked one and the capacity the cell measures doesn't change with it.

   A shade finer than the card's, not because it should read as any quieter but because a
   pill is a fifteenth of a card's height: the same 2px on something this small closes on
   the title rather than framing it. */
.calendar-month__pill--unassigned,
.calendar-month__band--unassigned {
  box-shadow: inset 0 0 0 1.5px var(--bs-warning);
}

/* Focus outranks the warning: a ring that says where the keyboard is has to be readable
   as that, and two rings on one element read as neither. Each keeps the focus ring it
   already had - the pill's outside it, the band's inset. */
.calendar-month__pill--unassigned:focus-visible {
  box-shadow: 0 0 0 0.2rem rgba(var(--bs-primary-rgb), 0.4);
}

.calendar-month__band--unassigned:focus-visible {
  box-shadow: inset 0 0 0 0.125rem rgba(255, 255, 255, 0.85);
}

/* So does a drag: the lift under the ghost and the red ring on a move that didn't save
   both say something about right now, and outrank a standing mark. Stated because these
   rules sit later in the sheet than the drag ones and would otherwise take it back - the
   list view's cards get this from the ordering alone. */
.calendar-month__pill--unassigned.calendar-drag-ghost {
  box-shadow: 0 0.75rem 1.5rem rgba(0, 0, 0, 0.45);
}

.calendar-month__pill--unassigned.calendar-drag-failed {
  box-shadow: inset 0 0 0 1.5px var(--bs-danger-text-emphasis);
}

/* A band's title is centred across the run, so a marker in the flow with it would sit
   somewhere different on every band - and somewhere different again from the pills, which
   carry theirs at the right. Taken out of the flow and pinned to the right edge instead,
   so the warning is in one place wherever the grid draws it. The band keeps room for it
   at that end so a long centred title stops short of it rather than running underneath. */
.calendar-month__band-warning {
  position: absolute;
  top: 50%;
  right: 0.5rem;

  transform: translateY(-50%);
}

.calendar-month__band--unassigned {
  position: relative;

  padding-inline-end: 1.25rem;
}

.calendar-month__pill--completed .calendar-month__pill-title {
  opacity: 0.75;
  text-decoration: line-through;
}

/* Multi-day bands */
/* =============== */
/* The runs crossing a week, laid over it in a grid of the same seven columns with the
   same rules between them - so a band placed on columns 3 to 6 covers exactly those
   days, and the rules it crosses with it. That is what makes a run one continuous bar
   rather than one block per day, and what gives its title the width of the whole run
   instead of a seventh of the screen.

   The overlay itself is transparent to the pointer so the days beneath it still take a
   drop; only the bands answer to it. */
.calendar-month__bands {
  position: absolute;
  inset: 0;

  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  align-items: end;
  gap: var(--calendar-rule-width);

  pointer-events: none;
}

/* Square, like everything else on the sheet - the ruled grid has no rounded corners in
   it, and a run that ends in one would read as a separate object laid on top rather
   than as a stretch of the calendar itself. */
.calendar-month__band {
  grid-row: 1;

  display: flex;
  align-items: center;
  justify-content: center;

  min-width: 0;
  /* The same one line a pill is. A run reads as the same kind of thing as the events
     around it, so it is drawn at the same height as them. */
  height: var(--calendar-event-unit);

  margin-bottom: calc(var(--calendar-band-lane, 0) * var(--calendar-band-step));
  padding: 0 0.5rem;

  /* --bs-border-color, the same neutral the pill above uses - lighter than every cell
     background a band can cross (including today's own secondary-bg), so an uncoloured
     run stays visible wherever it falls rather than blending into the grid. */
  background-color: var(--calendar-event-colour, var(--bs-border-color));
  border: none;
  border-radius: 0;

  cursor: pointer;
  pointer-events: auto;
  overflow: hidden;
}

.calendar-month__band:focus-visible {
  outline: 0;

  box-shadow: inset 0 0 0 0.125rem rgba(255, 255, 255, 0.85);
}

/* Centred across the run rather than left-aligned: the bar is as wide as the event is
   long, so its title reads as belonging to the whole stretch rather than to the day it
   happens to start on. */
.calendar-month__band-title {
  flex: 0 1 auto;

  min-width: 0;

  font-size: 0.6875rem;
  font-weight: 700;
  text-align: center;

  color: var(--calendar-event-contrast, var(--bs-emphasis-color));

  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.calendar-month__band--completed .calendar-month__band-title {
  opacity: 0.75;
  text-decoration: line-through;
}

/* Mid-drag the bands stand aside, so the strip of a day they cover still takes a drop */
body.calendar-dragging .calendar-month__band {
  pointer-events: none;
}

/* The events the cell had no room to draw. A link to the same day in the list view,
   where there is no limit on what a day can show - it looks like a control because it
   is one, and a count with nowhere to go would be a dead end. */
.calendar-month__overflow {
  flex: 0 0 auto;

  display: block;

  height: var(--calendar-overflow-height);

  padding: 0 0.125rem;

  font-size: 0.625rem;
  font-weight: 700;
  line-height: var(--calendar-overflow-height);

  color: var(--bs-tertiary-color);
  text-decoration: none;
}

a.calendar-month__overflow:hover,
a.calendar-month__overflow:focus-visible {
  color: var(--bs-emphasis-color);
  text-decoration: underline;
}


/* Hover */
/* ===== */
/* Only where there is a pointer to hover with - on a touch screen these stick after a
   tap, which reads as a selection that was never made. */
@media (hover: hover) {

  /* Lifted rather than recoloured, since what is underneath is the event's own colour
     and no one fixed value would sit right on all of them. */
  .calendar-month__pill:hover,
  .calendar-month__band:hover {
    filter: brightness(1.12);
  }

  .calendar-month__cell:hover {
    background-color: var(--bs-secondary-bg);
  }

  /* A day of another month takes no events and offers no drop, so it answers to nothing */
  .calendar-month__cell--outside:hover {
    background-color: var(--bs-body-bg);
  }

  /* Today keeps its own tint rather than losing it to the hover */
  .calendar-month__cell--today:hover {
    background-color: var(--bs-secondary-bg);
  }
}

/* The month grid is designed for a wide viewport - seven columns is a lot to ask of a
   phone, where a cell is about 46px across. A title has to survive that: it is the
   whole point of the pill, so the width goes to the title and everything else gives
   way to it.

   Two things buy that width. The pill loses its colour dot and takes the colour as its
   own background instead, the way the multi-day bands already do - the colour is still
   said, and the ~10px the dot and its gap cost go to the text. And the title wraps to
   two lines rather than being cut off at one, which is what turns five characters into
   fifteen. The cells grow taller to suit; the grid scrolls, which a month on a phone
   was always going to.

   A title long enough to still be cut is read in full by tapping the pill, which opens
   the event's overlay exactly as it does at any other width. */
@media (width < 768px) {

  /* Retuning the sizes the row height is built from is all it takes - the cells stay
     uniform, they just get taller to hold two lines of title. */
  .calendar-month__grid {
    --calendar-cell-padding: 0.125rem;
    --calendar-cell-gap: 0.1875rem;
    --calendar-date-height: 1.125rem;
    /* One line, as everywhere - a two-line title here makes a pill of exactly two of
       these, which is the 1.875rem box these pills used to be given outright. */
    --calendar-event-height: 0.9375rem;
    --calendar-event-height-min: 0.75rem;
    --calendar-pill-gap: 0.125rem;
    /* A cell is a seventh of a phone, so a title needs the second line here. A wide
       cell doesn't, and a one-line pill keeps more events on screen. */
    --calendar-pill-lines: 2;
    --calendar-overflow-height: 0.75rem;
    --calendar-lanes-max: 2.5rem;

    /* The sheet bleeds a little into the page's padding - eight more pixels across is
       another character and a half per line, and it carries its own edge. */
    margin-inline: -0.25rem;
  }

  .calendar-month__cells {
    border-radius: 0.5rem;
  }

  .calendar-month__date {
    font-size: 0.75rem;
  }

  /* The nav shares its bar with two other sets of controls now, so the month gives its
     name in short - "Aug 26" - and the arrows close up around it. */
  .calendar-month-nav {
    column-gap: 0.25rem;
  }

  .calendar-month-nav__label-long {
    display: none;
  }

  .calendar-month-nav__label-short {
    display: inline;
  }

  /* Narrower to suit the short name; the size itself is the bar's, at every width */
  .calendar-month-nav__label {
    width: 3.75rem;
  }

  .calendar-month-nav__button {
    width: 1.875rem;

    font-size: 0.8125rem;
  }

  /* Tighter within the box. The height is the content's at every width now, so all this
     has to say is how close the title sits to the pill's sides - and nothing above or
     below it, since that is what keeps a two-line pill exactly two one-line pills. */
  .calendar-month__pill {
    padding: 0 0.25rem;
  }

  /* A step down from the desktop size, and level with the bands beside it - the two sit
     within a few pixels of each other in the same cell, so a difference between them
     reads as an inconsistency rather than as a hierarchy. */
  .calendar-month__pill-title {
    font-size: 0.625rem;
  }

  .calendar-month__overflow {
    padding: 0;

    font-size: 0.5625rem;
    line-height: var(--calendar-overflow-height);
  }

  .calendar-month__band {
    padding: 0 0.25rem;
  }

  .calendar-month__band-title {
    font-size: 0.625rem;
  }
}


/* Three sets of controls in one bar come to more than a phone's width at full size, so
   one of them has to go. Add Event keeps its wording - it is the bar's one action, and
   an unlabelled icon asks the reader to remember what it does. The switch keeps both of
   its words and only closes up its padding. What goes is Today and the slot balancing
   it, which between them are the width of the whole overrun: the arrows already reach
   the current month, and dropping the pair leaves the arrows and the name as the entire
   middle column - centred on the bar exactly, with nothing to push them off it. */
@media (width <=576px) {
  .calendar-month-nav__slot {
    display: none;
  }

  .control-bar-container--inline {
    column-gap: 0.25rem;
    padding-inline: 0.375rem;

    /* Both controls are tighter here, so the width they share is too */
    --calendar-bar-control-width: 5rem;
  }

  /* The list view's bar carries three controls on a phone, and all three keep their words:
     a bag with a plus on it is not self-evidently "new packing list" the way a plus is
     "add". They pay for it in padding instead, which is the part nobody reads. */
  .calendar-add-button,
  .calendar-select__enter {
    padding: 0 0.5rem;
    column-gap: 0.25rem;
  }

  /* Today is the fourth control this bar has to find room for on a phone, and unlike
     the other two a bare calendar-check glyph is enough to say what it does - so it is
     the one that gives up its word rather than the whole bar losing its padding again.
     The icon-only collapse itself (.calendar-today-button / __text) is shared with the
     packing list bar's action buttons - see control_bar.css. */

  /* Today and the switch are the tightest-packed pair on the bar now, so they sit
     closer together than a button-container's default gap - close enough to still
     read as two separate controls, not so close they blur into one. */
  .calendar-bar-default.control-bar-button-container {
    column-gap: 0.25rem;
  }

  /* The bar now holds a sentence and two buttons on one line, which is more than a phone
     has room for at full size. */
  .calendar-select-bar {
    column-gap: 0.5rem;
  }

  .calendar-select-bar__count {
    font-size: 0.8125rem;
  }

  .calendar-select-bar__target {
    font-size: 0.6875rem;
  }

  .calendar-month-nav {
    column-gap: 0.1875rem;
  }

  .calendar-month-nav__button {
    width: 1.75rem;
  }

  .calendar-month-nav__label {
    width: 3.25rem;
  }

  .calendar-view-toggle__option {
    padding: 0 0.3125rem;
  }
}


/* Wide viewport reflow */
/* ==================== */
@media (width >=768px) {

  /* Full window width rather than a centred column - the week cards are a list of
     days, and narrowing them only pushes the weather badge back into the title. */
  .events-calendar {
    row-gap: 1.125rem;
  }

  .calendar-week__header {
    padding: 0.5rem 1rem;
  }

  .calendar-day {
    column-gap: 0.875rem;

    padding: 0.75rem 0.5rem;
  }

  .calendar-day--empty {
    padding: 0.375rem 0.5rem;
  }

  .calendar-day__label {
    width: 2.75rem;
  }

  .calendar-day__weekday {
    font-size: 0.6875rem;
  }

  .calendar-day__date {
    font-size: 1rem;
  }

  .calendar-day__date--today {
    width: 1.625rem;
    height: 1.625rem;
  }

  .calendar-day__events {
    row-gap: 0.5rem;
  }

  .calendar-day__no-events {
    font-size: 0.8125rem;
  }

  .calendar-event {
    column-gap: 0.875rem;

    min-height: 3.625rem;

    padding: 0.625rem 0.875rem;
  }

  .calendar-event__main {
    column-gap: 0.875rem;
  }

  .calendar-event__title {
    font-size: 0.9375rem;
  }

  .calendar-event__meta,
  .calendar-event__weather {
    font-size: 0.8125rem;
  }

  .calendar-event__warning {
    font-size: 0.9375rem;
  }

  .calendar-event__check {
    width: 1.5rem;
    height: 1.5rem;
  }

  /* The bottom sheet becomes a centred modal dialog */
  dialog.pg-modal.calendar-sheet {
    width: 26.25rem;
    max-width: calc(100% - 2rem);
    max-height: 80%;

    margin: auto;

    border-radius: 1rem;
  }

  .calendar-sheet__content {
    padding: 1.25rem 1.375rem 1.25rem;
  }

  /* No swipe-to-dismiss affordance on a pointer device - use the explicit close */
  .calendar-sheet__handle {
    display: none;
  }

  .calendar-sheet__close {
    display: flex;
  }

  .calendar-sheet__header {
    column-gap: 0.75rem;

    padding: 0.125rem 0.25rem 0.75rem;
  }

  .calendar-sheet__title {
    font-size: 1.1875rem;
  }

}

/* Select mode */
/* =========== */
/*
  Turning the grid into a multi-select for building a packing list from several events.

  Entered from a button rather than a press-and-hold on the cards: the grid already spends
  press-and-drag on moving an event to another day, so a hold would have to guess between
  the two - and a hold says nothing at all on a desktop. Once in the mode, everything is
  ordinary tapping.

  The marks and locks are drawn on every card and revealed by these rules, so entering the
  mode costs no round trip and no re-render.
*/

.calendar-select {
  position: relative;
}

.calendar-event__select-mark,
.calendar-event__select-lock {
  display: none;
}

/* Cards while selecting */
/* --------------------- */
.calendar-selecting .calendar-event {
  cursor: pointer;
}

/* The completed toggle is a second thing a card can do, and in select mode a card only
   does one. Hidden rather than merely inert, so it doesn't invite the tap it would refuse. */
.calendar-selecting .calendar-event__check-form {
  display: none;
}

.calendar-selecting .calendar-event__select-mark {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;

  width: 1.25rem;
  height: 1.25rem;

  margin: 0 0.5rem 0 0;

  background-color: transparent;
  border: 2px solid var(--bs-border-color);
  border-radius: 0.375rem;

  color: transparent;
  font-size: 0.75rem;
}

.calendar-selecting .calendar-event--selected {
  outline: 2px solid var(--pg-accent, var(--bs-primary));
  outline-offset: -2px;
}

.calendar-selecting .calendar-event--selected .calendar-event__select-mark {
  background-color: var(--pg-accent, var(--bs-primary));
  border-color: var(--pg-accent, var(--bs-primary));
  color: var(--pg-accent-contrast, #fff);
}

/* Already on another open list, or hidden from Pup. Says which on its face, so the refusal
   when it is tapped is a confirmation rather than the first the reader hears of it. */
.calendar-selecting .calendar-event[data-calendar-select-locked] {
  opacity: 0.55;
  cursor: not-allowed;
}

/* A subtitle under the event's name rather than a pill off to one side: it is a sentence
   about this event, and at pill size the list's name - the part the reader actually needs -
   was the first thing to be truncated away. Wraps to a second line rather than ellipsing,
   since a list called something long is exactly the case this is for. */
.calendar-selecting .calendar-event__select-lock {
  display: block;

  font-size: 0.6875rem;
  font-style: italic;
  font-weight: 600;
  line-height: 1.3;

  color: var(--bs-secondary-color);
  overflow-wrap: anywhere;
}

.calendar-event--select-refused {
  animation: calendar-select-refuse 0.4s ease;
}

@keyframes calendar-select-refuse {
  0%, 100% { transform: translateX(0); }
  25%      { transform: translateX(-4px); }
  75%      { transform: translateX(4px); }
}


/* The action bar */
/* -------------- */
/* Select mode owns the control bar while it is on. The bar's ordinary controls stand down
   rather than shuffling up beside the selection's own, and the selection stretches into
   the whole width they leave. */
.calendar-selecting .calendar-bar-default {
  display: none;
}

/* The selection's bar lives inside the create group, so both have to give up their own
   width for it to reach across the bar. */
.calendar-selecting .calendar-bar-create,
.calendar-selecting .calendar-select {
  flex: 1 1 auto;
  min-width: 0;
}

.calendar-select-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  column-gap: 1rem;

  width: 100%;
  min-width: 0;
}

.calendar-select-bar[hidden] {
  display: none;
}

.calendar-select-bar__status {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* Both lines give way before the buttons do: the count and the list's name can be cut
   short and still say enough, whereas half a "Create Packing List" says nothing. */
.calendar-select-bar__count {
  font-size: 0.875rem;
  font-weight: 600;

  color: var(--bs-emphasis-color);

  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.calendar-select-bar__target {
  font-size: 0.75rem;
  color: var(--bs-secondary-color);

  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.calendar-select-bar__actions {
  display: flex;
  flex: 0 0 auto;
  column-gap: 0.5rem;
}

.calendar-select__enter[hidden] {
  display: none;
}
