/* Paper and ink. Warm sheet, dark ink for the puzzle, forest green for what the player writes. */

:root {
  --paper: #f1e8d2;
  --paper-deep: #e8dcc0;
  --sheet: #fbf6e8;
  --ink: #26241e;
  --ink-soft: #5a5445;
  --rule: #cdbf9d;
  --rule-strong: #8d8264;
  --green: #2c5a3c;
  --green-deep: #1d4029;
  --green-wash: #dce8cf;
  --green-wash-strong: #c3d9b1;
  --row-wash: #f2ead0;
  --brick: #98351f;
  --brick-wash: #f3d9cc;
  --gold-wash: #f6e7b4;

  --font: Charter, "Bitstream Charter", "Sitka Text", Cambria, "Iowan Old Style", "Palatino Linotype", Georgia, serif;

  --chrome-h: 7.4rem; /* header + footer + breathing room */
  --board: min(calc(100dvh - var(--chrome-h)), calc(100vw - 27rem), 46rem);
  --cell: calc(var(--board) / 9);
  --radius: 0.7rem;
}

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100dvh;
  font-family: var(--font);
  font-size: 1.0625rem;
  line-height: 1.5;
  color: var(--ink);
  background-color: var(--paper);
  background-image:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 .35  0 0 0 0 .28  0 0 0 0 .15  0 0 0 .07 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>"),
    radial-gradient(120% 90% at 30% 0%, #f7efdb 0%, var(--paper) 55%, var(--paper-deep) 100%);
}

button {
  font: inherit;
  color: inherit;
}

/* Quick repeat taps (entering digits) must not trigger double-tap zoom.
   `manipulation` still allows panning and pinch-zoom, so zoom stays available. */
button,
.cell,
.level-choice,
.link {
  touch-action: manipulation;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

:focus-visible {
  outline: 3px solid var(--green);
  outline-offset: 2px;
}

/* ---------- layout ---------- */

/* Explicit minmax(0, 1fr) columns: an implicit `auto` track grows to its content's
   minimum width and silently pushes the page wider than the viewport. */
.app {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto 1fr auto;
  min-height: 100dvh;
  /* side padding grows past a notch in landscape (viewport-fit=cover) */
  padding-block: 0;
  padding-left: max(clamp(0.75rem, 2.5vw, 2rem), env(safe-area-inset-left));
  padding-right: max(clamp(0.75rem, 2.5vw, 2rem), env(safe-area-inset-right));
  max-width: 82rem;
  margin: 0 auto;
}

.top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.8rem 0 0.5rem;
}

.brand {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0;
  font-size: 1.75rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--green-deep);
}

.brand-mark {
  width: 1.9rem;
  height: 1.9rem;
}

.top-actions {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.lang {
  display: inline-flex;
  border: 2px solid var(--green);
  border-radius: var(--radius);
  overflow: hidden;
}

.lang button {
  appearance: none;
  border: 0;
  background: transparent;
  padding: 0.4rem 0.9rem;
  min-height: 2.5rem;
  cursor: pointer;
  font-weight: 600;
  color: var(--green-deep);
}

.lang button[aria-pressed="true"] {
  background: var(--green);
  color: var(--sheet);
}

.lang button:focus-visible {
  outline-offset: -4px;
  outline-color: var(--ink);
}

.stage {
  display: grid;
  grid-template-columns: auto minmax(19rem, 23rem);
  gap: clamp(1.5rem, 3.5vw, 3rem);
  justify-content: center;
  align-content: start;
  padding-top: 0.25rem;
}

.stage > *,
.side > *,
.top > *,
.top-actions > * {
  min-width: 0;
}

.board-wrap {
  width: var(--board);
  height: var(--board);
}

.side {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto auto auto minmax(0, 1fr);
  gap: 0.8rem;
  height: var(--board);
  min-height: 0;
}

/* ---------- board ---------- */

.board {
  width: var(--board);
  height: var(--board);
  display: flex;
  flex-direction: column;
  background: var(--sheet);
  border: 3px solid var(--ink);
  border-radius: 4px;
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.7) inset, 0 10px 28px -14px rgba(60, 45, 15, 0.45), 0 2px 0 var(--rule);
  user-select: none;
  -webkit-user-select: none;
  touch-action: manipulation;
}

.row {
  display: grid;
  grid-template-columns: repeat(9, 1fr);
  flex: 1 1 0;
  min-height: 0;
}

.row[data-r="2"],
.row[data-r="5"] {
  border-bottom: 3px solid var(--ink);
}

.row:not(:last-child):not([data-r="2"]):not([data-r="5"]) {
  border-bottom: 1px solid var(--rule);
}

.cell {
  position: relative;
  display: grid;
  place-items: center;
  min-width: 0;
  cursor: pointer;
  border-right: 1px solid var(--rule);
  font-family: var(--font);
  font-variant-numeric: lining-nums tabular-nums;
  background: transparent;
}

.cell[data-c="2"],
.cell[data-c="5"] {
  border-right: 3px solid var(--ink);
}

.cell[data-c="8"] {
  border-right: 0;
}

.cell .v {
  font-size: calc(var(--cell) * 0.62);
  line-height: 1;
  font-weight: 500;
  color: var(--green);
}

.cell.given .v {
  font-weight: 700;
  color: var(--ink);
}

.cell .n {
  position: absolute;
  inset: 5%;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 1fr);
  place-items: center;
  font-size: calc(var(--cell) * 0.235);
  line-height: 1;
  font-weight: 600;
  color: var(--ink-soft);
  pointer-events: none;
}

.cell .n i {
  font-style: normal;
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  border-radius: 50%;
}

.cell .n i.on-match {
  background: var(--green);
  color: var(--sheet);
}

.cell .n i.cut {
  text-decoration: line-through;
  text-decoration-thickness: 2px;
  color: var(--brick);
}

/* highlight layers: row/col/box, matching digit, selection */
.cell.peer {
  background: var(--row-wash);
}

.cell.same {
  background: var(--green-wash);
}

.cell.hint-unit {
  background: var(--gold-wash);
}

.cell.hint-pattern {
  background: #f0d98c;
}

.cell.hint-target {
  background: #f0d98c;
  box-shadow: inset 0 0 0 3px var(--green-deep);
}

.cell.hint-elim::before {
  content: "";
  position: absolute;
  inset: 3px;
  border: 2px dashed var(--brick);
  border-radius: 6px;
  pointer-events: none;
}

.cell.selected {
  background: var(--green-wash-strong);
  box-shadow: inset 0 0 0 3px var(--green);
  z-index: 1;
}

/* conflicts and wrong numbers use a symbol and a hatch, never colour alone */
.cell.conflict,
.cell.wrong {
  background-image: repeating-linear-gradient(135deg, transparent 0 6px, rgba(152, 53, 31, 0.16) 6px 8px);
}

.cell.conflict .v,
.cell.wrong .v {
  color: var(--brick);
  text-decoration: underline wavy var(--brick);
  text-decoration-thickness: 2px;
  text-underline-offset: 0.12em;
}

.cell.conflict::after,
.cell.wrong::after {
  position: absolute;
  top: 2px;
  right: 3px;
  display: grid;
  place-items: center;
  width: calc(var(--cell) * 0.27);
  height: calc(var(--cell) * 0.27);
  border-radius: 50%;
  background: var(--brick);
  color: #fff;
  font: 700 calc(var(--cell) * 0.2) / 1 var(--font);
}

.cell.conflict::after {
  content: "!";
}

.cell.wrong::after {
  content: "×";
  font-size: calc(var(--cell) * 0.26);
}

.cell.bump {
  animation: bump 0.22s ease-out;
}

@keyframes bump {
  40% {
    transform: translateX(-3px);
  }
  75% {
    transform: translateX(3px);
  }
}

/* ---------- side panel ---------- */

.meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  min-height: 1.9rem;
}

.level {
  font-size: 1.35rem;
  font-weight: 700;
  color: var(--green-deep);
}

.clock {
  font-size: 1.35rem;
  font-variant-numeric: lining-nums tabular-nums;
  color: var(--ink-soft);
}

.pad {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.5rem;
}

.pad button {
  appearance: none;
  min-width: 0;
  position: relative;
  display: grid;
  place-items: center;
  min-height: clamp(2.9rem, calc((var(--board) - 21rem) / 4), 4rem);
  padding: 0;
  border: 2px solid var(--green);
  border-radius: var(--radius);
  background: var(--sheet);
  color: var(--green-deep);
  font-size: 2rem;
  font-weight: 600;
  line-height: 1;
  font-variant-numeric: lining-nums;
  cursor: pointer;
  transition: background 0.12s;
}

.pad button:hover:not(:disabled) {
  background: var(--green-wash);
}

.pad button:active:not(:disabled) {
  background: var(--green-wash-strong);
}

.pad button .left {
  position: absolute;
  right: 0.45rem;
  bottom: 0.2rem;
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--ink-soft);
}

.pad button[aria-disabled="true"] {
  border-style: dashed;
  border-color: var(--rule-strong);
  color: var(--rule-strong);
  cursor: default;
}

.pad.notes button {
  background: var(--paper);
  font-size: 1.7rem;
}

.pad.notes button::before {
  content: "";
  position: absolute;
  inset: 4px;
  border: 1px dotted var(--green);
  border-radius: calc(var(--radius) - 3px);
}

.tools {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.5rem;
}

.tools #btn-new {
  grid-column: span 2;
}

.tools .btn {
  padding-inline: 0.3rem;
}

.side.hinting .pad button {
  min-height: 2.6rem;
}

.btn {
  appearance: none;
  min-width: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  min-height: 2.9rem;
  padding: 0.4rem 0.8rem;
  border: 2px solid var(--green);
  border-radius: var(--radius);
  background: var(--sheet);
  color: var(--green-deep);
  font-size: 1.1rem;
  font-weight: 600;
  line-height: 1.15;
  cursor: pointer;
  transition: background 0.12s;
}

.btn:hover:not(:disabled) {
  background: var(--green-wash);
}

.btn:disabled,
.btn[aria-disabled="true"] {
  border-style: dashed;
  border-color: var(--rule-strong);
  color: var(--rule-strong);
  cursor: default;
}

.btn[aria-pressed="true"] {
  background: var(--green);
  color: var(--sheet);
}

.btn.primary {
  background: var(--green);
  color: var(--sheet);
}

.btn.primary:hover:not(:disabled) {
  background: var(--green-deep);
}

.btn.accent {
  border-color: #a98a1f;
  background: var(--gold-wash);
  color: #4f3d05;
}

.btn.accent:hover:not(:disabled) {
  background: #f0d98c;
}

.btn.quiet {
  border-color: transparent;
  background: transparent;
  text-decoration: underline;
  text-underline-offset: 0.2em;
  text-decoration-thickness: 1px;
}

.btn.quiet:hover:not(:disabled) {
  background: rgba(44, 90, 60, 0.1);
}

kbd {
  font: inherit;
  font-size: 0.8em;
  padding: 0 0.35em;
  border: 1px solid currentColor;
  border-radius: 0.3em;
  opacity: 0.75;
}

.hint {
  min-height: 0;
  overflow: auto;
  padding: 0.8rem 1rem 0.9rem;
  border: 2px solid #a98a1f;
  border-radius: var(--radius);
  background: #fbf0c8;
}

.hint[hidden] {
  display: none;
}

.hint h2 {
  margin: 0 0 0.3rem;
  font-size: 1.15rem;
}

.hint p {
  margin: 0 0 0.6rem;
  font-size: 1.02rem;
  line-height: 1.45;
}

.hint .hint-note {
  font-size: 0.9rem;
  color: var(--ink-soft);
}

.hint .hint-note:empty {
  display: none;
}

.hint-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.hint-actions .btn {
  min-height: 2.6rem;
}

/* ---------- footer, toast ---------- */

.foot {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1.25rem;
  align-items: baseline;
  padding: 0.55rem 0 max(0.7rem, env(safe-area-inset-bottom));
  font-size: 0.875rem;
  color: var(--ink-soft);
}

.foot-line {
  margin: 0;
}

.foot-date {
  margin-left: auto;
  opacity: 0.8;
}

.foot .warning {
  color: var(--brick);
  font-weight: 600;
}

.foot-line[hidden] {
  display: none;
}

.link {
  appearance: none;
  border: 0;
  background: none;
  padding: 0.1rem 0.25rem;
  font-weight: 700;
  color: var(--green-deep);
  text-decoration: underline;
  cursor: pointer;
}

.toast {
  position: fixed;
  left: 50%;
  bottom: 3.2rem;
  z-index: 10;
  max-width: min(32rem, calc(100vw - 2rem));
  margin: 0;
  padding: 0.6rem 1.1rem;
  border-radius: var(--radius);
  background: var(--ink);
  color: var(--sheet);
  font-size: 1.05rem;
  text-align: center;
  transform: translate(-50%, 0.5rem);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s, transform 0.18s;
}

.toast.show {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* ---------- dialogs ---------- */

dialog {
  width: min(30rem, calc(100vw - 2rem));
  max-height: calc(100dvh - 2rem);
  padding: 1.4rem 1.5rem 1.2rem;
  border: 3px solid var(--ink);
  border-radius: 6px;
  background: var(--sheet);
  color: var(--ink);
  box-shadow: 0 20px 50px -12px rgba(40, 30, 10, 0.55);
  overflow: auto;
}

dialog.wide {
  width: min(44rem, calc(100vw - 2rem));
}

dialog::backdrop {
  background: rgba(45, 38, 22, 0.5);
}

dialog h2 {
  margin: 0 0 0.5rem;
  font-size: 1.5rem;
  color: var(--green-deep);
}

dialog h3 {
  margin: 1.2rem 0 0.3rem;
  font-size: 1.15rem;
  color: var(--green-deep);
}

dialog p {
  margin: 0 0 0.7rem;
}

.dlg-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
}

.dlg-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.6rem;
  margin-top: 1.1rem;
}

.levels {
  display: grid;
  gap: 0.55rem;
  margin: 0.8rem 0;
}

.level-choice {
  display: block;
  position: relative;
}

.level-choice input {
  position: absolute;
  opacity: 0;
  inset: 0;
  cursor: pointer;
}

.level-choice span {
  display: block;
  padding: 0.65rem 0.9rem 0.65rem 3rem;
  border: 2px solid var(--rule-strong);
  border-radius: var(--radius);
  background: var(--paper);
  position: relative;
}

.level-choice span::before {
  content: "";
  position: absolute;
  left: 0.9rem;
  top: 50%;
  width: 1.25rem;
  height: 1.25rem;
  margin-top: -0.625rem;
  border: 2px solid var(--green);
  border-radius: 50%;
  background: var(--sheet);
}

.level-choice strong {
  display: block;
  font-size: 1.15rem;
}

.level-choice small {
  display: block;
  font-size: 0.95rem;
  color: var(--ink-soft);
}

.level-choice input:checked + span {
  border-color: var(--green);
  background: var(--green-wash);
}

.level-choice input:checked + span::before {
  background: radial-gradient(circle, var(--green) 0 45%, var(--sheet) 50%);
}

.level-choice input:focus-visible + span {
  outline: 3px solid var(--green);
  outline-offset: 2px;
}

.warn {
  padding: 0.55rem 0.8rem;
  border: 2px dashed var(--brick);
  border-radius: var(--radius);
  background: var(--brick-wash);
  font-weight: 600;
}

.warn[hidden] {
  display: none;
}

.keys {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.35rem 1.2rem;
  margin: 0;
}

.keys dt {
  font-weight: 700;
}

.keys dd {
  margin: 0;
}

/* ---------- smaller screens ---------- */

@media (max-width: 52rem) {
  :root {
    --board: min(calc(100vw - 1.5rem), 34rem);
  }

  .stage {
    grid-template-columns: minmax(0, 34rem);
    gap: 1rem;
  }

  .side {
    height: auto;
    grid-template-rows: none;
  }

  .pad {
    grid-template-columns: repeat(9, minmax(0, 1fr));
    gap: 0.25rem;
  }

  .pad button {
    min-height: 3.1rem;
    font-size: 1.5rem;
  }

  .pad button .left {
    right: 0.2rem;
    bottom: 0.1rem;
    font-size: 0.65rem;
  }

  .brand {
    font-size: 1.45rem;
  }

  .hint {
    max-height: none;
  }

  .foot-date {
    margin-left: 0;
  }
}

@media (max-width: 40rem) {
  /* keyboard hints mean nothing on a phone and cost button width */
  .btn kbd {
    display: none;
  }
}

@media (max-width: 26rem) {
  .top {
    gap: 0.5rem;
  }

  .top-actions {
    gap: 0.35rem;
  }

  .brand {
    gap: 0.4rem;
    font-size: 1.3rem;
  }

  .brand-mark {
    width: 1.6rem;
    height: 1.6rem;
  }

  .lang button {
    padding: 0.4rem 0.55rem;
    font-size: 1rem;
  }

  #btn-help {
    padding: 0.4rem 0.35rem;
    font-size: 1rem;
  }

  .tools .btn {
    padding-inline: 0.15rem;
    font-size: 1rem;
  }

  .tools {
    gap: 0.4rem;
  }
}

/* short, wide laptop windows: tighter chrome, same big board */
@media (min-width: 52.01rem) and (max-height: 46rem) {
  :root {
    --chrome-h: calc(6.6rem + 3px); /* +3px: a 720px-tall window measured 2px of page scroll */
  }

  .top {
    padding-top: 0.5rem;
  }

  .tools .btn {
    min-height: 2.6rem;
    font-size: 1.05rem;
  }
}

/* Short landscape (phones on their side, ~844x390): the controls are taller than a
   board sized to the viewport height, so the side panel takes its natural height
   and the page scrolls. The footer then follows the real content, with no overlap. */
@media (min-width: 52.01rem) and (max-height: 34rem) {
  :root {
    --board: max(17.5rem, min(calc(100dvh - var(--chrome-h)), calc(100vw - 27rem), 46rem));
  }

  .side {
    height: auto;
    grid-template-rows: none;
    align-self: start;
  }

  .hint {
    overflow: visible;
  }
}

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

@media (forced-colors: active) {
  .cell.selected {
    outline: 3px solid Highlight;
  }
}
