:root {
  --ink: #161616;
  --paper: #fbf8f1;
  --canvas: #3f3f46;
  --canvas-text: #d8d4cb;
  --canvas-line: rgba(251, 248, 241, 0.4);
  --panel: #f3efe6;
  --white: #ffffff;
  --black: #111111;
  --accent: #b4532a;
  --rule: #e4dfd2;    /* decorative hairlines */
  --line: #8c8572;    /* control borders: dark enough for 3:1 non-text contrast on paper */
  --muted: #6b6659;
  --hover: rgba(22, 22, 22, 0.06);
  --shadow: 0 12px 32px rgba(0, 0, 0, 0.3);

  /* Corner radii for UI chrome. Page faces and the printed sheet stay square: they are paper. */
  --radius-sm: 4px;
  --radius-md: 6px;

  --font-display: "Playfair Display", Georgia, "Times New Roman", serif;
  --font-ui: system-ui, -apple-system, "Segoe UI", sans-serif;

  /* Type scale: labels, controls, section headings, logo. */
  --text-xs: 0.6875rem;
  --text-sm: 0.875rem;
  --text-md: 1.125rem;
  --text-lg: 1.5rem;
}

* {
  box-sizing: border-box;
}

[hidden] {
  display: none !important;
}

body {
  margin: 0;
  height: 100vh;
  height: 100dvh;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto 1fr auto auto;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-ui);
  line-height: 1.4;
}

button,
input {
  font: inherit;
}

/* Default button: a quiet outline. Ghost and primary variants are set below. */
button {
  padding: 6px 14px;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--ink);
  font-size: var(--text-sm);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background-color 120ms ease, transform 80ms ease;
}

button:disabled {
  opacity: 0.5;
  cursor: default;
}

button:not(:disabled):not(.is-active):not(.swatch):not([aria-checked="true"]):hover {
  background: var(--hover);
}

button:not(:disabled):active {
  transform: translateY(1px);
}

button:focus-visible,
input:focus-visible,
.thumb:focus-visible,
.stage-face:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.ghost {
  border-color: transparent;
}

@media (prefers-reduced-motion: reduce) {
  * {
    transition: none !important;
  }
}

/* Toolbar */

.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 20px;
  padding: 8px 20px;
  border-bottom: 1px solid var(--line);
  background: var(--paper);
}

.logo-block {
  display: flex;
  flex-direction: column;
  margin: 0 auto 0 0;
}

.logo {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: 400;
  letter-spacing: 0.01em;
  line-height: 1.1;
}

/* Creator credit under the name. It links to the creator's site. */
.byline {
  font-size: 0.75rem;
  letter-spacing: 0.02em;
  color: var(--muted);
  text-decoration: none;
  width: fit-content;
}

.byline:hover {
  color: var(--ink);
  text-decoration: underline;
}



/* One hairline box per group. The active option is a filled ink block. */
.segmented {
  display: inline-flex;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.segmented button {
  padding: 6px 12px;
  border: 0;
  border-radius: 0;
}

.segmented button + button {
  border-left: 1px solid var(--line);
}

/* The group clips its children, so the focus ring sits inside the group's edge. */
.segmented button:focus-visible {
  outline-offset: -2px;
}

.segmented button[aria-checked="true"],
.segmented button.is-active {
  background: var(--ink);
  color: var(--paper);
}

.toolbar-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

.toolbar-actions .is-active {
  background: var(--ink);
  color: var(--paper);
}

#export.primary {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
}

/* Clear confirmation: replaces the Clear button while it is waiting for an answer */

.clear-confirm {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: var(--text-sm);
}

.clear-confirm button.danger {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--white);
}

.clear-confirm button.danger:not(:disabled):not(.is-active):not(.swatch):not([aria-checked="true"]):hover {
  background: #9a4422;
  border-color: #9a4422;
  color: var(--white);
}

.clear-confirm button:not(.danger):hover {
  background: var(--hover);
}

/* Preflight warnings: persistent list below the toolbar */
.preflight-panel {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px 20px;
  border-left: 3px solid var(--accent);
  border-bottom: 1px solid var(--rule);
  background: var(--panel);
  color: var(--ink);
}

.preflight-panel.is-empty {
  display: none;
}

.preflight-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  font-size: var(--text-sm);
}

.preflight-header button {
  padding: 2px 10px;
  font-size: var(--text-xs);
}

.preflight-panel ul {
  margin: 0;
  padding-left: 18px;
  font-size: var(--text-sm);
  color: var(--muted);
}

.preflight-panel li + li {
  margin-top: 4px;
}

/* Workspace: rail on the left, stage and dock stacked on the right */

.workspace {
  display: grid;
  grid-template-columns: 120px 1fr;
  grid-template-rows: 1fr auto;
  min-height: 0;
  overflow: hidden;
}

.rail {
  grid-row: 1 / 3;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px 8px;
  overflow-y: auto;
  background: var(--panel);
  border-right: 1px solid var(--rule);
}

/* Thumbs are flat until selected. The selected page lifts onto white with a fine outline. */
.thumb {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 6px;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  background: transparent;
  cursor: pointer;
}

.thumb:not(.is-selected):not(.is-dragover):hover {
  background: var(--hover);
}

.thumb.is-selected {
  background: var(--white);
  border-color: var(--line);
}

.thumb.is-dragover {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent);
}

.thumb-frame {
  width: 100%;
  overflow: hidden;
  border-radius: var(--radius-sm);
  background: var(--white);
  box-shadow: 0 1px 3px rgba(22, 22, 22, 0.12);
}

.thumb-label {
  font-size: var(--text-xs);
  letter-spacing: 0.02em;
  color: var(--muted);
}

.stage {
  grid-column: 2;
  grid-row: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 16px;
  overflow: auto;
  min-height: 0;
  background: var(--canvas);
  color: var(--paper);
}

.stage > * {
  flex: 0 0 auto;
}

.stage-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-md);
  font-style: italic;
  font-weight: 400;
}

.stage-count {
  margin-left: 10px;
  font-family: var(--font-ui);
  font-size: var(--text-xs);
  font-style: normal;
  letter-spacing: 0.08em;
  color: var(--canvas-text);
}

.stage-note {
  margin: 0;
  max-width: 420px;
  font-family: var(--font-display);
  font-style: italic;
  font-size: 0.8125rem;
  text-align: center;
  color: var(--canvas-text);
}

/* Page faces, shared by the rail, the stage and the sheet */

.face {
  position: relative;
  width: 100%;
  height: 100%;
  container-type: inline-size;
  padding: 9.09%;
  background: var(--white);
  color: var(--ink);
  overflow: hidden;
}

.face-image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* Empty interior page: a preview-only hint. It is never drawn into the PDF. */
.face-placeholder {
  position: absolute;
  inset: 9.09cqw;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 4cqw;
  border: 1px dashed var(--rule);
  border-radius: 3px;
  font-size: 6cqw;
  line-height: 1.3;
  text-align: center;
  color: var(--muted);
}

/* Fitted photo with a caption: the caption sits in flow on its edge and the photo fills the rest.
   The gap matches CAPTION_GAP_RATIO in export.js (4% of slot width). */
.face.fit-stack {
  display: flex;
  flex-direction: column;
  gap: 4cqw;
}

.face.diptych {
  display: flex;
  padding: 0;
}

.face.diptych.diptych-horizontal {
  flex-direction: row;
}

.face.diptych.diptych-vertical {
  flex-direction: column;
}

/* Spread: one image spans two printed slots. The face shows one slot, clipped from a
   double-width inner wrapper. The start page shows the left half, the end page the right half. */
.face.spread {
  padding: 0;
}

.face.spread .spread-inner {
  position: absolute;
  top: 0;
  height: 100%;
  width: 200%;
}

.face.spread.is-start .spread-inner {
  left: 0;
}

.face.spread.is-end .spread-inner {
  left: -100%;
}

.face.spread .spread-inner .face-image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.face.spread .text-block {
  padding: 9.09%;
}

.face.diptych .photo-slot {
  position: relative;
  flex: 1 1 50%;
  min-width: 0;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.face.diptych .photo-slot.is-empty {
  border: 1px dashed var(--rule);
  margin: 9.09cqw;
  font-size: 6cqw;
  color: var(--muted);
  text-align: center;
}

.face.diptych.diptych-horizontal .photo-slot + .photo-slot {
  border-left: 1px solid var(--rule);
}

.face.diptych.diptych-vertical .photo-slot + .photo-slot {
  border-top: 1px solid var(--rule);
}

.face.diptych .caption-slot {
  position: absolute;
  inset: 9.09cqw;
  display: flex;
  flex-direction: column;
  justify-content: var(--slot-caption-justify, flex-end);
  overflow: hidden;
  pointer-events: none;
}

.photo-slot {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
}

.photo-slot .face-image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.caption-flow {
  display: flex;
  flex-direction: column;
  flex: 0 0 auto;
}

/* Fill: the photo covers the whole panel and is cropped by object-position (set from pan). */
.face.is-fill {
  padding: 0;
}

.face-image.is-fill {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.stage-face.is-fill {
  cursor: grab;
}

.stage-face.is-panning {
  cursor: grabbing;
}

.text-line {
  margin: 0;
  line-height: 1.15;
  overflow-wrap: anywhere;
}

.face.is-upside-down {
  transform: rotate(180deg);
}

/* The stage face is a div with role="button", so it gets no native button styling. */
.stage-face {
  flex: 1 1 0;
  min-height: 0;
  width: auto;
  max-width: 100%;
  height: 100%;
  max-height: 100%;
  aspect-ratio: var(--slot-ratio, 0.6471);
  padding: 0;
  border: 1px dashed var(--canvas-line);
  border-radius: var(--radius-md);
  background: none;
  cursor: pointer;
}

.stage-face:hover:not(.is-dragover) {
  border-color: var(--canvas-text);
}

.stage-face .face {
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow);
}

.stage-face.is-dragover {
  border-color: var(--accent);
}

/* Imposed sheet preview */

.sheet {
  position: relative;
  width: min(100%, 1000px);
  background: var(--white);
  box-shadow: var(--shadow);
}

/* The sheet scales to fit the available stage height in sheet view, so the whole
   preview plus the note below it is visible without scrolling. */
.stage > .sheet {
  width: min(100%, calc((100vh - 150px) * var(--sheet-ratio, 0.75)));
  height: auto;
  max-height: calc(100vh - 150px);
}

.sheet-cell {
  position: absolute;
}

.sheet-cell .face {
  outline: 1px solid var(--rule);
}

/* Fold guides: muted dashed lines that show where to fold. */
.sheet::before {
  content: "";
  position: absolute;
  z-index: 1;
  pointer-events: none;
  left: 0;
  right: 0;
  top: 50%;
  height: 1px;
  background: repeating-linear-gradient(
    to right,
    var(--line) 0 6px,
    transparent 6px 12px
  );
}

/* Vertical centre axis: a subtle reference line that the cut segment sits on. */
.sheet::after {
  content: "";
  position: absolute;
  z-index: 1;
  pointer-events: none;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 1px;
  background: repeating-linear-gradient(
    to bottom,
    var(--line) 0 6px,
    transparent 6px 12px
  );
}

/* Cut guide: distinct from the fold guides so the two don't read as the same instruction.
   It marks the middle segment of the horizontal centre line where the folded sheet is slit,
   with a small scissors icon as a universal "cut here" cue. */
.cut-guide {
  position: absolute;
  z-index: 2;
  pointer-events: none;
  left: 25%;
  top: 50%;
  width: 50%;
  height: 2px;
  transform: translateY(-50%);
  background: var(--accent);
  border-radius: 1px;
}

.cut-guide::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 18px;
  height: 18px;
  transform: translate(-50%, -50%);
  background: var(--accent);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='6' cy='6' r='3'/%3E%3Ccircle cx='6' cy='18' r='3'/%3E%3Cline x1='20' y1='4' x2='8.12' y2='15.88'/%3E%3Cline x1='14.47' y1='14.48' x2='20' y2='20'/%3E%3Cline x1='8.12' y1='8.12' x2='12' y2='12'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='6' cy='6' r='3'/%3E%3Ccircle cx='6' cy='18' r='3'/%3E%3Cline x1='20' y1='4' x2='8.12' y2='15.88'/%3E%3Cline x1='14.47' y1='14.48' x2='20' y2='20'/%3E%3Cline x1='8.12' y1='8.12' x2='12' y2='12'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* Bottom dock: a row of tabs over one panel at a time, with the status line below. The panel
   height is fixed so switching tabs does not make the dock jump. */

.dock {
  grid-column: 2;
  grid-row: 2;
  display: flex;
  flex-direction: column;
  padding: 0 20px 6px;
  border-top: 1px solid var(--line);
  background: var(--paper);
}

.dock-body {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  padding-top: 8px;
}


/* Tabs: the active one gets an accent rule underneath, the same accent the rail uses for selection. */
.dock-tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--rule);
}

.dock-tab {
  margin-bottom: -1px;
  padding: 6px 10px;
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  background: transparent;
  color: var(--muted);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.dock-tab.is-active {
  border-bottom-color: var(--accent);
  color: var(--ink);
}

.dock-tab:disabled {
  opacity: 0.5;
  cursor: default;
  color: var(--muted);
}

.dock-tab:disabled.is-active {
  border-bottom-color: transparent;
}

.dock-panel {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}

#panel-text {
  flex-direction: row;
  flex-wrap: wrap;
  gap: 6px 12px;
  align-items: flex-end;
}

#text-fields {
  width: 100%;
}

#caption-field,
#slot-caption-fields {
  flex: 1 1 180px;
  min-width: 140px;
}

#slot-caption-fields {
  flex-wrap: nowrap;
}

/* Page footer: states where the work lives. Print hides it with the rest of the page (see @media print). */
.app-footer {
  padding: 4px 24px;
  border-top: 1px solid var(--rule);
  background: var(--paper);
  color: var(--muted);
  font-size: var(--text-xs);
}

.app-footer p {
  margin: 0;
}

.app-footer a {
  color: inherit;
  text-decoration: underline;
}

/* Icon-only link. Its name is in aria-label and title, so the footer stays one line of text. */
.app-footer .social {
  display: inline-flex;
  vertical-align: -0.2em;
  text-decoration: none;
}

.app-footer .social svg {
  width: 1.05em;
  height: 1.05em;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
}

/* How-to-fold dialog, opened from the toolbar */

.fold-guide {
  width: min(560px, calc(100vw - 32px));
  padding: 20px 24px;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--paper);
  color: var(--ink);
}

.fold-guide::backdrop {
  background: rgb(22 22 22 / 0.45);
}

.fold-guide-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.fold-guide-header h2 {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-lg);
}

.fold-steps {
  display: grid;
  gap: 12px;
  margin: 16px 0;
  padding: 0;
  list-style: none;
  font-size: var(--text-sm);
  line-height: 1.5;
}

.fold-steps li {
  display: grid;
  grid-template-columns: 120px 1fr;
  align-items: center;
  gap: 16px;
}

.fold-steps svg {
  width: 100%;
  height: auto;
  fill: none;
  stroke: var(--ink);
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.fold-steps .fold-accent {
  fill: var(--accent);
  fill-opacity: 0.25;
  stroke: var(--accent);
}

.fold-steps .fold-cut {
  stroke: var(--accent);
  stroke-width: 2.5;
}

.fold-steps p {
  margin: 0;
}

@media (max-width: 480px) {
  .fold-steps li {
    grid-template-columns: 1fr;
  }
}

.fold-guide-note {
  margin: 12px 0 0;
  color: var(--muted);
  font-size: var(--text-xs);
}

.fold-guide-image {
  display: block;
  width: 100%;
  height: auto;
  margin-top: 16px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-md);
  background: #fff7e6;
}

.field-row,
.option-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 6px 16px;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.field-row .field {
  flex: 1 1 160px;
}

.field label,
.field-label {
  font-size: 0.625rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Text fields are underlined, not boxed */
.field input[type="text"],
.dock-caption input {
  width: 100%;
  padding: 2px 0;
  border: 0;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
  background: transparent;
  color: var(--ink);
  font-size: 0.8125rem;
}

.field input[type="text"]::placeholder,
.dock-caption input::placeholder {
  color: var(--muted);
  opacity: 1;
}

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.chip {
  padding: 5px 12px;
  border-color: var(--line);
  font-size: var(--text-sm);
}

.chip.is-active {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
}

.swatches {
  display: inline-flex;
  gap: 8px;
}

/* Round swatches. The selected one gets a ring, so the colour itself stays readable. */
.swatch {
  width: 26px;
  height: 26px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
}

.swatch-white {
  background: var(--white);
}

.swatch-black {
  background: var(--black);
}

.swatch.is-active {
  box-shadow: 0 0 0 2px var(--paper), 0 0 0 3px var(--ink);
}

/* Icon buttons for alignment. The icon is decorative: each button has an aria-label. */
.align-group {
  display: inline-flex;
  gap: 8px;
}

.segmented .icon-button {
  display: inline-grid;
  place-items: center;
  width: 36px;
  height: 32px;
  padding: 0;
}

.icon-button svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.field-overlay output {
  margin-left: 6px;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  text-transform: none;
}

.overlay-controls {
  display: flex;
  align-items: center;
  gap: 12px;
}

.overlay-controls input[type="range"] {
  width: 160px;
  accent-color: var(--ink);
}

/* Cover and back-cover faces */

.cover-face {
  padding: 0;
  background: var(--black);
}

.cover-image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.cover-shade {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.text-block {
  position: absolute;
  /* cqw, not %: export pads by 9% of the slot width on every side, including top and bottom. */
  inset: 9.09cqw;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.cover-title,
.cover-sub {
  margin: 0;
  line-height: 1.15;
  overflow-wrap: anywhere;
}

/* Gap before each block after the first, as 0.4 x that block's own size, matching export.js (BLOCK_GAP). */
.cover-sub:not(:first-child) {
  margin-top: 0.4em;
}

.cover-title {
  font-weight: 400;
}

.cover-title.is-placeholder {
  opacity: 0.6;
}

/* Same width as a Words field, so the caption underline matches the cover's inputs. */
.dock-caption {
  flex: 0 1 180px;
}

/* Photo actions under the stage face: replace, remove, and the Fit / Fill group. */
.photo-bar {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 6px 10px;
  width: 100%;
}

/* The bar sits on the dark stage, so its buttons take the stage's light text and hairlines. */
.photo-bar button {
  padding: 4px 10px;
  color: var(--canvas-text);
  border-color: var(--canvas-line);
  font-size: 0.8125rem;
}

.photo-bar button:not(:disabled):not(.is-active):hover {
  color: var(--paper);
  border-color: var(--canvas-text);
  background: rgba(251, 248, 241, 0.08);
}

.photo-bar .segmented {
  border-color: var(--canvas-line);
}

.photo-bar .segmented button + button {
  border-left-color: var(--canvas-line);
}

.photo-bar .segmented button:not([aria-checked="true"]):hover {
  color: var(--paper);
  background: rgba(251, 248, 241, 0.08);
}

.photo-bar .segmented button[aria-checked="true"] {
  background: var(--paper);
  color: var(--ink);
}

.photo-bar-sub {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 6px 10px;
}

.spread-note {
  margin: 0;
  color: var(--canvas-text);
  font-size: var(--text-sm);
}

.face.diptych .photo-slot {
  cursor: pointer;
}

.face.diptych .photo-slot:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

.dock-note {
  margin: 0;
  font-size: 0.6875rem;
  line-height: 1.3;
  color: var(--muted);
}

/* Toast: a short message at the top of the screen, with an optional action such as Undo. */
.toast {
  position: fixed;
  top: 16px;
  left: 50%;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 12px;
  max-width: min(560px, calc(100vw - 32px));
  transform: translateX(-50%);
  padding: 10px 14px;
  border-radius: var(--radius-md);
  background: var(--ink);
  box-shadow: var(--shadow);
  color: var(--paper);
  font-size: var(--text-sm);
}

.toast button {
  padding: 4px 10px;
  border-color: rgb(251 248 241 / 0.5);
  color: var(--paper);
}

/* Phone width: the rail becomes a horizontal strip above the stage */

@media (max-width: 720px) {
  /* On a phone the page keeps the full screen height. The preview takes the space above a bottom
     panel, and the panel scrolls inside itself with its tabs kept at the top. */
  .workspace {
    grid-template-columns: 1fr;
    grid-template-rows: auto minmax(0, 1fr) auto;
  }

  .stage {
    grid-column: 1;
    grid-row: 2;
    min-height: 0;
    container-type: size;
  }

  .dock {
    grid-column: 1;
    grid-row: 3;
    max-height: 55dvh;
    overflow-y: auto;
  }

  .dock.is-collapsed {
    padding-bottom: 0;
  }

  .dock.is-collapsed .dock-body {
    display: none;
  }

  .dock-tabs {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--paper);
  }

  .rail {
    grid-row: 1;
    flex-direction: row;
    overflow-x: auto;
    overflow-y: hidden;
    border-right: 0;
    border-bottom: 1px solid var(--rule);
  }

  .thumb {
    flex: 0 0 56px;
  }

  /* The page face fills the height the stage has left, and its width follows from the paper ratio. */
  /* The face is as tall as the stage has room for, and its width follows from the paper ratio. */
  .stage-face {
    width: min(100cqw, max(160px, calc((100cqh - 140px) * var(--slot-ratio, 0.6471))));
    max-width: 100%;
    height: auto;
  }


  /* One hairline strip that scrolls sideways, so the toolbar doesn't stack into several rows above
     the preview. It matches the paper-size control: items keep their natural widths and share
     dividers, so uneven labels read as one bar instead of loose buttons. */
  .toolbar-actions {
    flex-wrap: nowrap;
    gap: 0;
    overflow-x: auto;
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
  }

  .toolbar-actions > button {
    flex: 0 0 auto;
    padding: 8px 14px;
    border: 0;
    border-radius: 0;
    white-space: nowrap;
  }

  /* Dividers name their neighbours explicitly: the button reset above would otherwise win. */
  .toolbar-actions > .clear-confirm,
  .toolbar-actions > button + button,
  .toolbar-actions > .clear-confirm + button {
    border-left: 1px solid var(--line);
  }

  .toolbar-actions .clear-confirm {
    flex: 0 0 auto;
    gap: 0;
    white-space: nowrap;
  }

  .toolbar-actions .clear-confirm span {
    padding: 8px 14px;
  }

  .toolbar-actions .clear-confirm button {
    padding: 8px 14px;
    border: 0;
    border-radius: 0;
  }

  .toolbar-actions .clear-confirm button + button {
    border-left: 1px solid var(--line);
  }
}

/* Print: only the imposed sheet is printed. Its size is set in pt by main.js, the same unit as
   the layout, and the @page rule for that size is written there too. */
.print-sheet {
  display: none;
}

@media print {
  * {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }

  body {
    display: block;
    height: auto;
    background: var(--white);
  }

  body > :not(.print-sheet) {
    display: none !important;
  }

  .print-sheet {
    display: block;
  }

  .print-sheet .sheet {
    width: 100%;
    height: 100%;
    box-shadow: none;
  }

  /* Fold guides, the cut guide, and cell outlines are on-screen aids. Remove them here to print a clean sheet. */
  .print-sheet .sheet::before,
  .print-sheet .sheet::after,
  .print-sheet .cut-guide {
    display: none;
  }

  .print-sheet .sheet-cell .face {
    outline: none;
  }

  /* Preview-only text. The PDF leaves these out too. */
  .print-sheet .face-placeholder,
  .print-sheet .is-placeholder {
    display: none;
  }
}
