/*
 * The printed artifact.
 *
 * Every dimension here resolves to a millimeter value computed in layout.js and
 * injected as a custom property. Nothing is sized against the viewport, because
 * in a print context the viewport is not the page.
 *
 * Screen rules approximate the sheet so the result is reviewable in the
 * browser; the @media print block at the bottom is the source of truth.
 *
 * This file has to stand on its own. The Download HTML export ships it without
 * css/app.css, so it cannot lean on the app shell for anything, starting with
 * the box model: a grid with an explicit height and a border on it lays out a
 * hairline too tall under content-box, and one stray pixel per row of month
 * blocks is enough to push a sheet onto a second page.
 */

.calendar-pages,
.calendar-pages *,
.calendar-pages *::before,
.calendar-pages *::after {
  box-sizing: border-box;
}

.calendar-pages {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 28px;
}

/*
 * The sheet is the whole piece of paper, with the margin as padding inside it,
 * rather than just the printable area sitting in a larger page box. That is
 * what keeps it flush: the @page rule asks for no margin of its own, so the
 * element and the page box are the same size and there is no slack to pool at
 * the bottom whatever the print dialog's margin setting says.
 *
 * The height is the printable area plus its two margins rather than the paper
 * height, which is the same number less the sub-millimeter trim that stops
 * Chrome emitting a blank trailing page.
 */
.page {
  box-sizing: border-box;
  width: var(--page-width);
  height: calc(var(--printable-height) + var(--page-margin) * 2);
  padding: var(--page-margin);
  display: flex;
  flex-direction: column;
  background: #fff;
  color: #111;
  font-family: var(--body-family);
  font-variant-numeric: tabular-nums lining-nums;

  /* Keeps a sheet whole rather than letting it split across two pages. */
  break-inside: avoid;
  page-break-inside: avoid;
}

.page-inner {
  display: flex;
  height: var(--body-height);
}

/*
 * The arrangement of month blocks on one sheet. A monthly calendar is the
 * degenerate 1x1 case, which is why one layout engine covers all five
 * calendar types.
 */
.month-grid {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: var(--gutter);
  width: var(--body-width);
  height: var(--body-height);
}

/*
 * Month blocks take the exact size layout.js computed for them rather than a
 * fraction worked out in CSS, which is what makes the arrangement wrap into the
 * right number of columns and rows without either side having to guess.
 */
.month {
  flex: 0 0 auto;
  width: var(--block-width);
  height: var(--block-height);
}

.month {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  break-inside: avoid;
  page-break-inside: avoid;
}

.month-title,
.weekday-row,
.day-grid {
  flex: none;
}

.month-title {
  height: var(--title-height);
  margin: 0;
  font-family: var(--title-family);
  display: flex;
  align-items: baseline;
  gap: 0.3em;
  font-size: var(--title-font);
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1;
  white-space: nowrap;
}

.month-year {
  font-weight: 400;
  color: #5a5a5a;
}

/*
 * Exists only to give the accessibility tree a table to walk around the header
 * and the weeks. `display: contents` keeps it out of the box tree entirely, so
 * the weekday strip and the day grid stay flex children of .month.
 */
.month-table {
  display: contents;
}

.weekday-row {
  display: flex;
  height: var(--weekday-row-height);
  align-items: end;
  font-size: var(--weekday-font);
  font-weight: 600;
  color: #454545;
  letter-spacing: 0.02em;
}

/*
 * Seven equal columns, shared by the weekday strip and every week below it.
 * `flex: 1 1 0` divides the width the way the grid track `1fr` did, without the
 * sub-pixel gap that seven hard-coded percentages would leave at the right edge.
 */
.weekday-label {
  flex: 1 1 0;
  min-width: 0;
  padding: 0 var(--cell-padding) calc(var(--cell-padding) * 0.6);
  text-decoration: none;
  overflow: hidden;
  white-space: nowrap;
}

/*
 * The grid gets an explicit height and its weeks share that height equally, so
 * a five-row month stretches to the same bottom edge as a six-row month, with
 * taller cells. That is intended: the sheet always fills to the bottom margin.
 */
.day-grid {
  display: flex;
  flex-direction: column;
  height: var(--day-grid-height);

  /*
   * Grid lines are borders, never background fills, so they survive with
   * "Background graphics" switched off in the print dialog. The container
   * draws the outer frame and each cell draws its right and bottom edge, with
   * the last column and last row opting out so nothing doubles up.
   */
  border: var(--grid-line-outer-width) solid var(--grid-color);
}

/*
 * Date numbers are sized against the cell they land in, so a five-row month
 * gets larger numbers than a six-row one, the way the printed reference does.
 * layout.js emits one value per possible week count and the row count picks.
 */
.day-grid[data-weeks='4'] {
  --date-font: var(--date-font-4);
}

.day-grid[data-weeks='5'] {
  --date-font: var(--date-font-5);
}

.day-grid[data-weeks='6'] {
  --date-font: var(--date-font-6);
}

/* Every week takes an equal share of the grid's fixed height. */
.week {
  display: flex;
  flex: 1 1 0;
  min-height: 0;
}

.day-cell {
  box-sizing: border-box;
  display: flex;
  flex: 1 1 0;
  flex-direction: column;
  align-items: flex-end;
  min-width: 0;
  overflow: hidden;
  padding: var(--cell-padding);
  border-right: var(--grid-line-width) solid var(--grid-color);
  border-bottom: var(--grid-line-width) solid var(--grid-color);
}

.week > .day-cell:last-child {
  border-right: 0;
}

.week:last-child > .day-cell {
  border-bottom: 0;
}

/*
 * Weekend shading is the one thing on the page that is a background fill, so it
 * only appears when "Background graphics" is enabled in the print dialog. The
 * tint is deliberately far lighter than the grid color: a mid-gray fill hides
 * a mid-gray hairline, and the grid has to stay readable through the shading.
 *
 * Deliberately no print-color-adjust here. Forcing the fill would override the
 * dialog's own checkbox, and the app tells the user that checkbox controls the
 * shading, so it has to actually control it.
 */
.day-cell.is-weekend {
  background-color: var(--weekend-shade);
}

.day-number {
  font-size: var(--date-font);
  line-height: 1;
  font-weight: 500;
}

.day-cell.is-adjacent .day-number {
  color: #a8a8a8;
  font-weight: 400;
}

/*
 * A holiday is marked with a soft disc behind the date rather than by bolding
 * it. The disc is drawn by a pseudo-element so the number stays exactly where
 * it would otherwise sit and holiday dates keep aligning with the rest of the
 * column. `z-index: 0` gives the number its own stacking context, which keeps
 * the disc above any weekend shading on the cell and below the digits.
 */
.day-cell.is-holiday .day-number {
  position: relative;
  z-index: 0;
}

.day-cell.is-holiday .day-number::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 1.75em;
  height: 1.75em;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: rgb(0 0 0 / 5%);
  z-index: -1;
}

/*
 * Sits on the floor of the cell on a single line, so the writing space above it
 * stays one clean block rather than being interrupted by a wrapped label. Light
 * enough to read as an annotation next to the date, and truncated rather than
 * wrapped when a name outruns the column.
 */
.day-holiday {
  margin-top: auto;
  align-self: stretch;
  font-size: var(--holiday-font);
  line-height: 1.2;
  text-align: left;
  color: #9a9a9a;
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/*
 * Used where a cell is too narrow to spell the holiday out. An outlined ring
 * rather than a filled dot, so it prints without background graphics.
 */
.day-holiday-marker {
  box-sizing: border-box;
  width: calc(var(--holiday-font) * 0.62);
  height: calc(var(--holiday-font) * 0.62);
  margin-top: calc(var(--cell-padding) * 0.5);
  border: 0.25mm solid #444;
  border-radius: 50%;
}

/* Notes ---------------------------------------------------------------- */

.notes {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.notes-column {
  width: var(--notes-column-width);
  height: var(--body-height);
  margin-left: var(--notes-gap);
}

.notes-strip {
  height: var(--notes-strip-height);
  margin-top: var(--notes-gap);
}

.notes-title {
  margin: 0 0 calc(var(--cell-padding) * 1.5);
  font-size: var(--weekday-font);
  font-weight: 600;
  color: #454545;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.notes-strip .notes-title {
  margin-bottom: calc(var(--cell-padding) * 0.8);
}

.notes-lines {
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

.notes-line {
  height: var(--notes-line-height);
  border-bottom: var(--notes-rule-width) solid var(--notes-rule-color);
}

/*
 * Carries the holiday name for assistive technology in layouts too dense to
 * print it. A title attribute alone is neither keyboard reachable nor reliably
 * announced, and it never prints.
 */
.calendar-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Screen preview -------------------------------------------------------- */

@media screen {
  /* Screen and print now draw the same box, so the preview only adds the scale
     that fits it in the window and something to lift it off the background. */
  .page {
    zoom: var(--preview-zoom, 1);
    box-shadow: 0 1px 2px rgb(0 0 0 / 18%), 0 10px 30px rgb(0 0 0 / 12%);
  }
}

/* Print ----------------------------------------------------------------- */

@media print {
  /*
   * The stacking used for the screen preview has to come off, and it has to
   * come off here rather than in the app stylesheet: the exported file ships
   * this sheet alone, and a residual flex gap between sheets would push the
   * last one onto an extra page.
   */
  .calendar-pages {
    display: block;
    gap: 0;
  }

  /*
   * Centered on the sheet, which matters when the print dialog's margin setting
   * disagrees with ours. Choosing "None" there makes Chrome ignore the @page
   * margin and hand the full sheet over as the page box; the sheet is then
   * wider than this fixed-size page and the slack is exactly the margin we
   * asked for, so centering puts it back where it belongs. With "Default" there
   * is no slack and this does nothing.
   */
  .page {
    zoom: 1;
    box-shadow: none;
    margin: 0 auto;
  }

  /*
   * Only the sheets between pages force a break. The final sheet must not, or
   * the print engine emits an empty trailing page.
   */
  .page:not(:last-of-type) {
    break-after: page;
    page-break-after: always;
  }
}
