:root {
  --max-cell: 0.6in;
  --print-page-width: 7.5in; /* letter (8.5in) - 2 * 0.5in margins */
  --ink: #111;
  --rule: #333;
  --muted: #666;
  --bg: #fafaf7;
  --accent: #2c5d8f;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: Georgia, "Times New Roman", serif;
}

body { padding: 1.5rem; max-width: 60rem; margin: 0 auto; }

header h1 { margin: 0 0 .25rem 0; font-size: 1.8rem; color: var(--accent); }
.tagline { margin: 0 0 1.5rem 0; color: var(--muted); }

.form {
  background: white;
  border: 1px solid #ddd;
  border-radius: 6px;
  padding: 1.25rem;
  margin-bottom: 1.5rem;
}

.field { display: block; margin-bottom: 1rem; }
.field > span {
  display: block;
  font-weight: bold;
  margin-bottom: .35rem;
  font-size: .95rem;
}
.field code { font-family: ui-monospace, Menlo, monospace; font-size: .85rem; }
.field.inline { display: flex; align-items: center; gap: .75rem; }
.field.inline > span { margin: 0; }

input[type=text], textarea, select {
  font: inherit;
  padding: .5rem .6rem;
  border: 1px solid #bbb;
  border-radius: 4px;
  width: 100%;
  background: white;
}
textarea { font-family: ui-monospace, Menlo, monospace; font-size: .9rem; }

select {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'><path fill='%23555' d='M0 0h12L6 8z'/></svg>");
  background-repeat: no-repeat;
  background-position: right 0.7rem center;
  background-size: 10px 7px;
  padding-right: 1.9rem;
}
.field.inline select { width: auto; }

.actions { display: flex; gap: .5rem; flex-wrap: wrap; margin-top: .5rem; }
.actions button {
  font: inherit;
  padding: .55rem 1rem;
  border: 1px solid var(--accent);
  background: var(--accent);
  color: white;
  border-radius: 4px;
  cursor: pointer;
}
.actions button:disabled { opacity: .45; cursor: not-allowed; }
.actions button:not(:first-child) { background: white; color: var(--accent); }

.warning {
  margin-top: 1rem;
  padding: .65rem .8rem;
  border-left: 4px solid #c97a00;
  background: #fff6e5;
  color: #5a3a00;
  border-radius: 3px;
}

/* ---------- Puzzle render ---------- */

.puzzle {
  background: white;
  border: 1px solid #ddd;
  border-radius: 6px;
  padding: 1.25rem;
}

.puzzle-title {
  margin: 0 0 1rem 0;
  text-align: center;
  font-size: 1.5rem;
}

.grid {
  display: grid;
  /* Every line is drawn by exactly one cell. Internal lines + top/left
     silhouette: has-top/has-left on the cell below/right of the line.
     Right/bottom silhouette: has-right/has-bottom on the edge real cell
     itself. No phantom tracks — they didn't render reliably in print. */
  width: min(calc(var(--cols) * var(--max-cell)), 100%);
  grid-template-columns: repeat(var(--cols), 1fr);
  grid-template-rows: repeat(var(--rows), auto);
  margin: 0 auto 1.25rem auto;
  /* content-box keeps the width calc above sizing the cell tracks, not the
     padded outer box — the global border-box rule would otherwise shrink
     the cells to fit padding+border inside the same total width. */
  box-sizing: content-box;
  background: #e8e8e8;
  border: 3px solid black;
  padding: 10px;
}

.cell {
  /* Default cell: no border, transparent. Becomes a paintable cell only
     when classes are added: .real (white background + letter), .has-left
     (left border), .has-top (top border). Every grid line is drawn by
     exactly one cell — the one to the right or below the line — so there
     is no doubling and no alignment ambiguity between internal lines and
     silhouette edges. */
  border: none;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
}
.cell.real {
  aspect-ratio: 1 / 1;
  container-type: inline-size;
  background: white;
}
.cell.has-left { border-left: 1px solid var(--rule); }
.cell.has-top { border-top: 1px solid var(--rule); }
.cell.has-right { border-right: 1px solid var(--rule); }
.cell.has-bottom { border-bottom: 1px solid var(--rule); }

.cell-number {
  position: absolute;
  top: 4%;
  left: 6%;
  font-size: 24cqi;
  font-family: ui-sans-serif, system-ui, sans-serif;
  line-height: 1;
}

.cell-letter {
  font-size: 55cqi;
  font-family: ui-sans-serif, system-ui, sans-serif;
  font-weight: 600;
  text-transform: uppercase;
  line-height: 1;
}

/* On-screen view shows letters; print modes override below. */

.clues {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem;
}
.clue-col h3 {
  margin: 0 0 .5rem 0;
  border-bottom: 2px solid var(--ink);
  padding-bottom: .25rem;
}
.clue-col ol {
  margin: 0;
  padding-left: 1.75rem;
  line-height: 1.5;
}

.app-version {
  margin-top: 2rem;
  text-align: right;
  font-size: .75rem;
  color: var(--muted);
  opacity: .6;
  font-family: ui-monospace, Menlo, monospace;
}

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

/* In puzzle mode, hide letters; in answer mode, show them. */
body.mode-puzzle .cell-letter { visibility: hidden; }

@media print {
  @page { size: letter; margin: 0.5in; }
  body {
    background: white;
    padding: 0;
    max-width: none;
  }
  .screen-only { display: none !important; }

  .puzzle {
    border: none;
    padding: 0;
    box-shadow: none;
  }

  .grid {
    /* Concrete per-cell length for print. Firefox's print engine doesn't
       reliably resolve aspect-ratio + 1fr tracks + container-query units
       during pagination, so we sidestep all three with an explicit size. */
    /* Reserve space for the frame (3px border + 10px padding on each side
       = 26px ≈ 0.28in) so the framed grid still fits the printable area. */
    --print-cell: min(var(--max-cell), calc((var(--print-page-width) - 0.3in) / var(--cols)));
    page-break-inside: avoid;
    break-inside: avoid;
    width: calc(var(--cols) * var(--print-cell));
    grid-template-columns: repeat(var(--cols), var(--print-cell)) !important;
    grid-template-rows: repeat(var(--rows), var(--print-cell)) !important;
    /* Force browsers to print the gray fill instead of stripping it. */
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }

  .cell.real {
    width: var(--print-cell);
    height: var(--print-cell);
    aspect-ratio: auto;
    container-type: normal;
  }

  .cell-number { font-size: calc(var(--print-cell) * 0.24); }
  .cell-letter { font-size: calc(var(--print-cell) * 0.55); }

  /* Every line painted by exactly one cell. Right/bottom silhouettes use
     border-right/border-bottom on the edge real cell instead of a 1px
     phantom track — print engines drop sub-pixel-rounded 1px tracks. */
  .cell {
    border: none;
    box-shadow: none !important;
  }
  .cell.has-left { border-left: 1px solid black; }
  .cell.has-top { border-top: 1px solid black; }
  .cell.has-right { border-right: 1px solid black; }
  .cell.has-bottom { border-bottom: 1px solid black; }
  .cell, .grid { color: black; }

  /* Answer-key (clue list) placement — chosen by the user at print time
     via body[data-answer-placement]. "below" is the natural flow and needs
     no rules. */

  body[data-answer-placement="separate"] .clues {
    break-before: page;
    page-break-before: always;
  }

  /* Reserve a fixed, readable column for the clues; shrink the grid's
     page-width budget so the existing --print-cell formula on .grid uses
     the remaining space. Whatever the grid doesn't consume stays with the
     puzzle as breathing room rather than padding the right margin. */
  body[data-answer-placement="side"] {
    --print-page-width: 4.7in; /* 7.5in page - 2.5in clues - 0.3in gap */
  }
  body[data-answer-placement="side"] .puzzle {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 0.3in;
  }
  body[data-answer-placement="side"] .puzzle-title {
    flex: 0 0 100%;
    margin-bottom: 0;
  }
  body[data-answer-placement="side"] .grid {
    flex: 0 0 auto;
    margin: 0;
  }
  body[data-answer-placement="side"] .clues {
    flex: 0 0 2.5in;
    display: block;
  }
  body[data-answer-placement="side"] .clue-col + .clue-col {
    margin-top: 1rem;
  }
}
