/* JuJu Games — single lightweight stylesheet, mobile-first */
:root {
  --c-primary: #6c5ce7;
  --c-primary-dark: #5345c9;
  --c-accent: #fdcb6e;
  --c-bg: #f7f7fb;
  --c-surface: #ffffff;
  --c-text: #2d3436;
  --c-text-soft: #636e72;
  --c-border: #e6e6ef;
  --c-success: #00b894;
  --c-error: #d63031;
  --radius: 14px;
  --shadow: 0 2px 10px rgba(45, 52, 84, .08);
  --shadow-lg: 0 8px 28px rgba(45, 52, 84, .14);
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans", "Noto Sans CJK SC", sans-serif;
  background: var(--c-bg);
  color: var(--c-text);
  line-height: 1.6;
}
img { max-width: 100%; }
a { color: var(--c-primary); }
h1, h2, h3 { line-height: 1.25; }

.container { max-width: 1080px; margin: 0 auto; padding: 0 16px; }

/* ---------- header ---------- */
.site-header {
  position: sticky; top: 0; z-index: 50;
  background: rgba(255, 255, 255, .92);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--c-border);
}
.header-inner { display: flex; align-items: center; justify-content: space-between; height: 56px; }
.logo { font-size: 1.15rem; font-weight: 800; text-decoration: none; color: var(--c-text); white-space: nowrap; }
.logo em { color: var(--c-primary); font-style: normal; }
.site-nav { display: flex; align-items: center; gap: 14px; }
.site-nav > a { text-decoration: none; color: var(--c-text-soft); font-weight: 600; font-size: .95rem; }
.site-nav > a:hover { color: var(--c-primary); }

.lang-switch { position: relative; }
.lang-btn {
  border: 1px solid var(--c-border); background: var(--c-surface); border-radius: 999px;
  padding: 5px 12px; font-size: .85rem; cursor: pointer; color: var(--c-text);
}
.lang-menu {
  display: none; position: absolute; right: 0; top: calc(100% + 6px);
  margin: 0; padding: 6px; list-style: none;
  background: var(--c-surface); border: 1px solid var(--c-border); border-radius: 12px;
  box-shadow: var(--shadow-lg); min-width: 130px;
}
.lang-menu.open { display: block; }
.lang-menu a { display: block; padding: 7px 12px; border-radius: 8px; text-decoration: none; color: var(--c-text); font-size: .92rem; }
.lang-menu a:hover { background: var(--c-bg); }
.lang-menu a.active { color: var(--c-primary); font-weight: 700; }

/* ---------- hero ---------- */
.hero { text-align: center; padding: 44px 8px 26px; }
.hero h1 { font-size: clamp(1.7rem, 4.5vw, 2.7rem); margin: 0 0 12px; }
.hero .lead { max-width: 640px; margin: 0 auto 22px; color: var(--c-text-soft); font-size: 1.05rem; }

/* ---------- buttons ---------- */
.btn {
  display: inline-block; border: 0; cursor: pointer; text-decoration: none;
  border-radius: 999px; font-weight: 700; font-size: .95rem;
  padding: 10px 22px; transition: transform .12s ease, box-shadow .12s ease;
}
.btn:active { transform: scale(.97); }
.btn-primary { background: var(--c-primary); color: #fff; box-shadow: var(--shadow); }
.btn-primary:hover { background: var(--c-primary-dark); }
.btn-ghost { background: transparent; color: var(--c-text-soft); }
.btn-lg { padding: 13px 30px; font-size: 1.05rem; }

/* ---------- games grid ---------- */
.games-section { padding: 18px 0 8px; }
.games-section h2, .why-section h2, .faq-section h2, .more-games h2, .game-research h2 { font-size: 1.45rem; }
.games-grid {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}
.game-card {
  display: flex; flex-direction: column; gap: 6px; position: relative;
  background: var(--c-surface); border: 1px solid var(--c-border); border-radius: var(--radius);
  padding: 18px; text-decoration: none; color: var(--c-text);
  box-shadow: var(--shadow); transition: transform .15s ease, box-shadow .15s ease;
}
.game-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); }
.game-card h3 { margin: 2px 0; font-size: 1.1rem; }
.game-card p { margin: 0; color: var(--c-text-soft); font-size: .9rem; flex: 1; }
.game-icon { font-size: 2rem; line-height: 1; }
.game-play { color: var(--c-primary); font-weight: 700; font-size: .9rem; margin-top: 8px; }
.game-card-sm { padding: 14px; align-items: center; flex-direction: row; gap: 10px; }
.game-card-sm h3 { font-size: .98rem; margin: 0; }
/* Tool cards are the one .game-card-sm with a description. The row layout would treat that
   <p> as a third column and squeeze it into a tall thin strip, so wrap it onto its own line
   underneath the icon and name. */
.game-tools .game-card-sm { flex-wrap: wrap; row-gap: 4px; }
.game-tools .game-card-sm h3 { flex: 1 1 auto; }
.game-tools .game-card-sm p { flex: 1 0 100%; margin: 0; font-size: .85rem; line-height: 1.4; }

.game-cat {
  position: absolute; top: 14px; right: 14px;
  font-size: .72rem; font-weight: 700; padding: 3px 9px; border-radius: 999px;
}
.cat-memory    { background: #e8e3ff; color: #5345c9; }
.cat-attention { background: #dff7ef; color: #00795f; }
.cat-math      { background: #fff1d6; color: #9a6a00; }
.cat-reaction  { background: #ffe3e3; color: #b33939; }
.cat-typing    { background: #e3edff; color: #2952cc; }
.cat-word      { background: #fce4f0; color: #a83a72; }

/* ---------- typing test ---------- */
.tt-words {
  display: flex; flex-wrap: wrap; gap: 6px 10px; justify-content: center;
  max-width: 620px; margin: 6px auto 16px; font-size: 1.15rem; line-height: 1.7;
}
.tt-word { color: var(--c-text-soft); }
.tt-word.tt-current { color: var(--c-text); font-weight: 700; background: #eef0ff; border-radius: 6px; padding: 0 5px; }
.tt-word.tt-current.tt-bad { background: #ffe3e3; color: #b33939; }
.tt-input {
  width: 100%; max-width: 420px; padding: 12px 14px; font: inherit; font-size: 1.05rem;
  border: 2px solid var(--c-border); border-radius: 12px; text-align: center;
}
.tt-input:focus { outline: none; border-color: var(--c-primary); }

/* ---------- falling words ---------- */
.fw-field {
  position: relative; width: 100%; max-width: 560px; height: 340px; margin: 0 auto 14px;
  overflow: hidden; border: 2px solid var(--c-border); border-radius: 14px;
  background: linear-gradient(#f6f6ff, #ffffff);
}
.fw-word {
  position: absolute; transform: translateX(-50%); white-space: nowrap;
  font-weight: 700; font-size: 1.05rem; color: var(--c-text);
  background: #eef0ff; border: 1px solid #dcd9ff; border-radius: 8px; padding: 3px 9px;
}
.fw-input {
  width: 100%; max-width: 420px; padding: 12px 14px; font: inherit; font-size: 1.05rem;
  border: 2px solid var(--c-border); border-radius: 12px; text-align: center;
}
.fw-input:focus { outline: none; border-color: var(--c-primary); }

/* ---------- typing tutor (virtual keyboard) ---------- */
.kt-round { font-size: .85rem; color: var(--c-text-soft); margin-bottom: 2px; }
.kt-prompt { font-size: 1.7rem; font-weight: 800; letter-spacing: 2px; min-height: 2rem; margin: 2px 0 4px; }
.kt-prompt .kt-typed { color: var(--c-primary); }
.kt-prompt .kt-rest { color: var(--c-text-soft); }
.kt-finger { font-size: .9rem; font-weight: 700; color: var(--c-text); min-height: 1.2rem; margin-bottom: 12px; }
.kt-keyboard { display: inline-flex; flex-direction: column; gap: 6px; max-width: 100%; }
.kt-row { display: flex; gap: 6px; justify-content: center; }
.kt-key {
  width: 40px; height: 44px; border: 1px solid var(--c-border); border-radius: 8px;
  font: inherit; font-size: .95rem; background: #fff; color: var(--c-text);
  cursor: pointer; transition: transform .08s ease, box-shadow .08s ease;
}
.kt-key.kt-space { width: 220px; cursor: default; color: var(--c-text-soft); font-size: .8rem; }
.kt-key.kt-next { border: 2px solid var(--c-primary); box-shadow: 0 0 0 3px rgba(108,92,231,.25); font-weight: 800; transform: translateY(-2px); }
.kt-key.kt-good { background: #d7f7df !important; }
.kt-key.kt-bad  { background: #ffd9d9 !important; }
.kt-f0 { background: #ffe0e6; } .kt-f1 { background: #ffe9d6; }
.kt-f2 { background: #fff6d6; } .kt-f3 { background: #e3f7e0; }
.kt-f4 { background: #d9f3f0; } .kt-f5 { background: #dce9ff; }
.kt-f6 { background: #e7e0ff; } .kt-f7 { background: #f7e0f3; }
.kt-hands { display: flex; justify-content: center; gap: 26px; margin: 4px 0 12px; }
.kt-hand { display: flex; align-items: flex-end; gap: 5px; padding: 8px 9px 10px; background: #ecebf4; border-radius: 12px 12px 22px 22px; }
.kt-bar { width: 15px; border-radius: 8px; background: #dcdce4; transition: transform .1s ease, box-shadow .1s ease, filter .1s ease; }
.kt-bar.kt-thumb { width: 17px; }
.kt-bar.kt-active { box-shadow: 0 0 0 3px var(--c-primary); transform: translateY(-6px); filter: saturate(1.7) brightness(.96); }
@media (max-width: 480px) {
  .kt-key { width: 30px; height: 38px; font-size: .82rem; }
  .kt-key.kt-space { width: 150px; }
  .kt-row { gap: 4px; }
  .kt-hands { gap: 18px; }
  .kt-hand { gap: 4px; padding: 6px 6px 8px; }
}

/* ---------- text sections ---------- */
.why-section, .faq-section { padding: 22px 0 4px; }
.why-section p { color: var(--c-text-soft); }
.faq-item {
  background: var(--c-surface); border: 1px solid var(--c-border);
  border-radius: 12px; padding: 12px 16px; margin-bottom: 10px;
}
.faq-item summary { font-weight: 700; cursor: pointer; }
.faq-item p { color: var(--c-text-soft); margin: 10px 0 2px; }

.feedback-banner {
  text-align: center; background: linear-gradient(135deg, #6c5ce7, #8e7bf0);
  color: #fff; border-radius: var(--radius); padding: 30px 20px; margin: 30px 0 40px;
}
.feedback-banner h2 { margin-top: 0; }
.feedback-banner .btn-primary { background: #fff; color: var(--c-primary); }

/* understated feedback prompt at the bottom of topic + game pages */
.page-feedback {
  margin: 34px 0 8px; padding: 22px 18px 6px;
  border-top: 1px solid var(--c-border); text-align: center;
}
.page-feedback p { color: var(--c-text-soft); margin: 0 0 14px; }
.page-actions { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }
.btn-share { background: var(--c-surface); color: var(--c-primary); box-shadow: var(--shadow); }
.btn-share:hover { background: #f3f0ff; }
.btn-share:disabled { cursor: default; opacity: .75; }

/* ---------- game page ---------- */
.game-page { padding-top: 22px; }
.breadcrumb { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; font-size: .85rem; color: var(--c-text-soft); margin: 0 0 12px; }
.breadcrumb a { color: var(--c-text-soft); text-decoration: none; }
.breadcrumb a:hover { color: var(--c-primary); }
.breadcrumb .crumb-current { color: var(--c-text); font-weight: 600; }
.game-header { display: flex; gap: 16px; align-items: center; margin-bottom: 14px; }
.game-icon-lg { font-size: 3rem; line-height: 1; }
.game-header h1 { margin: 0 0 4px; font-size: clamp(1.5rem, 4vw, 2.1rem); }
.game-header .lead { margin: 0 0 6px; color: var(--c-text-soft); }
.game-meta { display: flex; gap: 10px; align-items: center; margin: 0; }
.game-meta .game-cat { position: static; }
.game-best { font-size: .9rem; color: var(--c-text-soft); }

.game-root {
  background: var(--c-surface); border: 1px solid var(--c-border); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 22px; margin: 14px 0 26px;
  min-height: 320px; display: flex; align-items: center; justify-content: center;
}

.game-info { display: grid; gap: 14px; grid-template-columns: 1fr; margin-bottom: 10px; }
.info-block {
  background: var(--c-surface); border: 1px solid var(--c-border);
  border-radius: var(--radius); padding: 6px 22px 14px;
}
.info-block h2 { font-size: 1.15rem; }
.info-block li { margin-bottom: 6px; color: var(--c-text-soft); }
.game-desc-seo { color: var(--c-text-soft); font-size: .95rem; }
.more-games { margin: 26px 0 40px; }

/* ---------- related research ---------- */
.game-research { margin: 0 0 44px; }
.game-research h2 { margin-bottom: 4px; }
.research-note { color: var(--c-text-soft); font-size: .95rem; margin: 0 0 14px; }
.paper-list { list-style: none; padding: 0; margin: 0; display: grid; gap: 12px; }
.paper {
  background: var(--c-surface); border: 1px solid var(--c-border);
  border-radius: var(--radius); padding: 12px 16px;
}
.paper-title { display: block; font-weight: 600; color: var(--c-primary); text-decoration: none; }
.paper-title:hover { text-decoration: underline; }
.paper-cite { display: block; color: var(--c-text-soft); font-size: .9rem; margin-top: 3px; }

/* ---------- shared game UI ---------- */
.g-center { text-align: center; width: 100%; }
.g-stats { display: flex; justify-content: center; gap: 22px; margin-bottom: 14px; flex-wrap: wrap; }
.g-stat { font-size: .9rem; color: var(--c-text-soft); }
.g-stat strong { font-size: 1.25rem; color: var(--c-text); display: block; }
.g-msg { min-height: 1.4em; font-weight: 700; margin: 8px 0; }

/* Completion is the headline; the score is a quiet detail (product principle) */
.result-card { text-align: center; }
.result-card .result-done { font-size: 2.2rem; font-weight: 800; color: var(--c-success); margin: 4px 0 10px; }
.result-card .result-value { font-size: 1.25rem; font-weight: 600; color: var(--c-text-soft); margin: 4px 0 10px; }
.result-card .result-best { color: var(--c-text-soft); margin-bottom: 4px; }
.result-card .result-egg { color: #9a6a00; background: #fff6e3; display: inline-block; padding: 4px 14px; border-radius: 999px; font-size: .9rem; margin: 6px 0 10px; }
.result-card .result-trdone { font-size: 1.15rem; font-weight: 800; color: var(--c-primary); margin: 14px 0 2px; }
.result-card .btn { margin-top: 10px; }

/* ---------- daily training ---------- */
.training-page { max-width: 640px; margin: 0 auto; padding-bottom: 30px; }
.hero-sm { padding: 30px 8px 18px; }
.training-alt { text-align: center; margin-top: 18px; }
.training-section { padding: 6px 0 10px; }
.training-card {
  background: linear-gradient(135deg, #ffffff, #f3f1ff);
  border: 1px solid #ddd8f7; border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 20px 22px 22px; text-align: center;
}
.training-card h2 { margin: 0 0 2px; }
.tr-sub { color: var(--c-text-soft); margin: 2px 0 14px; font-size: .95rem; }
.tr-stats { display: flex; justify-content: center; gap: 22px; flex-wrap: wrap; margin-bottom: 12px; }
.tr-stats .g-stat strong { display: inline; font-size: 1.15rem; margin-left: 4px; color: var(--c-primary); }
.tr-streak { color: var(--c-success); font-weight: 700; }
.tr-plan { list-style: none; margin: 0 auto 14px; padding: 0; max-width: 340px; text-align: left; }
.tr-plan li {
  display: flex; justify-content: space-between; align-items: center;
  background: var(--c-surface); border: 1px solid var(--c-border); border-radius: 10px;
  padding: 8px 14px; margin-bottom: 6px; font-weight: 600;
}
.tr-plan li.done { opacity: .65; }
.tr-plan li.done span:first-child { text-decoration: line-through; }
.tr-check { color: var(--c-success); font-weight: 800; }
.tr-done-msg { font-size: 1.1rem; font-weight: 800; color: var(--c-success); margin: 10px 0; }
.tr-week { margin-top: 16px; }
.tr-week-label { color: var(--c-text-soft); font-size: .85rem; margin: 0 0 6px; }
.tr-chips { display: flex; justify-content: center; gap: 8px; flex-wrap: wrap; }
.tr-chip {
  font-size: .82rem; font-weight: 700; padding: 4px 12px; border-radius: 999px;
  background: var(--c-bg); color: #b6b0c8; border: 1px solid var(--c-border);
}
.tr-chip.lit { background: #e8e3ff; color: var(--c-primary-dark); border-color: #cdc4f5; }
.tr-banner {
  text-align: center; font-weight: 700; color: var(--c-primary);
  background: #efecff; border-radius: 999px; padding: 6px 16px;
  display: table; margin: 14px auto 0;
}

/* memory match */
.mm-grid { display: grid; grid-template-columns: repeat(4, minmax(56px, 86px)); gap: 10px; justify-content: center; }
.mm-card {
  aspect-ratio: 1; border-radius: 12px; border: 0; cursor: pointer;
  background: var(--c-primary); color: transparent; font-size: clamp(1.4rem, 6vw, 2.1rem);
  transition: transform .18s ease, background .18s ease;
}
.mm-card.open { background: var(--c-surface); border: 2px solid var(--c-border); color: inherit; transform: rotateY(180deg); }
.mm-card.matched { background: #e9fbf5; border-color: var(--c-success); color: inherit; cursor: default; }

/* schulte table */
.st-grid { display: grid; grid-template-columns: repeat(5, minmax(48px, 72px)); gap: 8px; justify-content: center; }
.st-cell {
  aspect-ratio: 1; border-radius: 10px; border: 1px solid var(--c-border); cursor: pointer;
  background: var(--c-surface); font-size: clamp(1rem, 4vw, 1.4rem); font-weight: 700; color: var(--c-text);
}
.st-cell:hover { border-color: var(--c-primary); }
.st-cell.done { background: #eceafd; color: #b6b0e8; border-color: transparent; cursor: default; }
.st-cell.err { background: #ffe3e3; border-color: var(--c-error); animation: shake .3s; }
@keyframes shake { 25% { transform: translateX(-4px); } 75% { transform: translateX(4px); } }

/* quick math */
.qm-problem { font-size: clamp(2rem, 8vw, 3rem); font-weight: 800; margin: 8px 0 18px; }
.qm-options { display: grid; grid-template-columns: repeat(2, minmax(110px, 160px)); gap: 12px; justify-content: center; }
.qm-opt {
  padding: 16px 8px; font-size: 1.3rem; font-weight: 700; cursor: pointer;
  border: 2px solid var(--c-border); border-radius: 12px; background: var(--c-surface); color: var(--c-text);
}
.qm-opt:hover { border-color: var(--c-primary); }
.qm-opt.good { background: #e9fbf5; border-color: var(--c-success); }
.qm-opt.bad { background: #ffe3e3; border-color: var(--c-error); }

/* reaction time */
.rt-area {
  width: 100%; max-width: 560px; min-height: 280px; border-radius: var(--radius); border: 0;
  font-size: 1.3rem; font-weight: 800; color: #fff; cursor: pointer;
  background: var(--c-primary); display: flex; align-items: center; justify-content: center; flex-direction: column; gap: 6px;
}
.rt-area.waiting { background: var(--c-error); }
.rt-area.go { background: var(--c-success); }
.rt-area small { font-weight: 600; opacity: .85; }

/* grid memory */
.gm-grid { display: grid; gap: 8px; justify-content: center; }
.gm-grid.showing { pointer-events: none; }
.gm-cell {
  aspect-ratio: 1; border-radius: 10px; border: 1px solid var(--c-border);
  background: var(--c-surface); cursor: pointer; transition: background .15s ease;
}
.gm-cell.lit { background: var(--c-primary); border-color: var(--c-primary); }
.gm-cell.good { background: #aef3de; border-color: var(--c-success); }
.gm-cell.bad { background: #ffc6c6; border-color: var(--c-error); animation: shake .3s; }

/* pattern logic */
.pn-seq { font-size: clamp(1.5rem, 6vw, 2.2rem); font-weight: 800; margin: 8px 0 18px; letter-spacing: .1em; }

/* stroop */
.sp-word { font-size: clamp(2.2rem, 9vw, 3.2rem); font-weight: 800; margin: 6px 0 18px; }
.sp-word.sp-bad { animation: shake .3s; }
.sp-options { display: grid; grid-template-columns: repeat(2, minmax(110px, 160px)); gap: 12px; justify-content: center; }
.sp-opt {
  padding: 16px 8px; font-size: 1.1rem; font-weight: 800; cursor: pointer;
  border: 0; border-radius: 12px; color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,.25);
}
.sp-opt:active { transform: scale(.97); }

/* dot sense */
.de-area {
  position: relative; width: min(340px, 100%); height: 200px; margin: 0 auto 10px;
  background: #f1f0fa; border-radius: 12px; overflow: hidden;
}
.de-dot { position: absolute; width: 12px; height: 12px; border-radius: 50%; background: var(--c-primary); }

/* odd one out */
.oo-grid { display: grid; gap: 6px; justify-content: center; }
.oo-cell {
  aspect-ratio: 1; border-radius: 10px; border: 1px solid var(--c-border); cursor: pointer;
  background: var(--c-surface); font-size: clamp(1.1rem, 4.5vw, 1.6rem); line-height: 1;
}
.oo-cell.err { background: #ffe3e3; border-color: var(--c-error); animation: shake .3s; }

/* number memory */
.nm-display { font-size: clamp(2.2rem, 10vw, 3.4rem); font-weight: 800; letter-spacing: .12em; margin: 14px 0; }
.nm-input {
  font-size: 1.6rem; text-align: center; letter-spacing: .12em; width: min(320px, 80%);
  padding: 10px; border: 2px solid var(--c-border); border-radius: 12px;
}
.nm-input:focus { outline: none; border-color: var(--c-primary); }
.nm-bar { height: 6px; background: var(--c-border); border-radius: 3px; max-width: 320px; margin: 0 auto 8px; overflow: hidden; }
.nm-bar i { display: block; height: 100%; background: var(--c-primary); transition: width .1s linear; }

/* ---------- feedback page ---------- */
.feedback-page { max-width: 620px; margin: 0 auto; padding: 30px 0 50px; }
.feedback-form {
  background: var(--c-surface); border: 1px solid var(--c-border); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 22px; display: flex; flex-direction: column; gap: 14px;
}
.rating-fieldset { border: 0; padding: 0; margin: 0; }
.rating-fieldset legend { font-weight: 700; margin-bottom: 6px; }
.rating-radios { display: inline-flex; flex-direction: row-reverse; gap: 4px; }
.rating-radios input { position: absolute; opacity: 0; width: 0; }
.rating-radios label { font-size: 2rem; color: #d6d3e8; cursor: pointer; transition: color .1s; }
.rating-radios input:checked ~ label, .rating-radios label:hover, .rating-radios label:hover ~ label { color: var(--c-accent); }
.rating-radios input:focus-visible + label { outline: 2px solid var(--c-primary); border-radius: 4px; }
.field-label { font-weight: 700; }
.feedback-form textarea, .fb-dialog textarea {
  width: 100%; border: 2px solid var(--c-border); border-radius: 12px; padding: 10px;
  font: inherit; resize: vertical;
}
.feedback-form textarea:focus, .fb-dialog textarea:focus { outline: none; border-color: var(--c-primary); }
.alert { border-radius: 12px; padding: 12px 16px; margin: 14px 0; font-weight: 600; }
.alert-success { background: #e9fbf5; color: #00795f; }
.alert-error { background: #ffe3e3; color: var(--c-error); }
.fb-note { color: var(--c-text-soft); font-size: .82rem; margin: 0; }
/* Spam honeypot: parked off-screen rather than display:none — bots that skip hidden inputs
   still fill this one, and no sighted or screen-reader user ever reaches it (aria-hidden +
   tabindex="-1" on the element). Anything typed here marks the submission as spam. */
.hp-field { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }

/* ---------- privacy page ---------- */
.privacy-page { max-width: 680px; margin: 0 auto; padding: 30px 0 50px; }
.privacy-page .lead { color: var(--c-text-soft); }
.privacy-page h2 { margin-top: 28px; font-size: 1.15rem; }
.privacy-page li { margin: 6px 0; }

/* floating feedback button + dialog */
.fb-fab {
  position: fixed; right: 16px; bottom: 16px; z-index: 60;
  border: 0; border-radius: 999px; padding: 11px 18px; cursor: pointer;
  background: var(--c-primary); color: #fff; font-weight: 700; font-size: .92rem;
  box-shadow: var(--shadow-lg);
}
.fb-fab:hover { background: var(--c-primary-dark); }
.fb-dialog {
  border: 0; border-radius: var(--radius); box-shadow: var(--shadow-lg);
  padding: 22px; width: min(420px, calc(100vw - 32px));
}
.fb-dialog::backdrop { background: rgba(30, 30, 60, .45); }
.fb-dialog h2 { margin-top: 0; font-size: 1.2rem; }
.fb-stars { display: flex; gap: 4px; margin-bottom: 12px; }
.fb-star { background: none; border: 0; font-size: 1.9rem; color: #d6d3e8; cursor: pointer; padding: 0 2px; }
.fb-star.sel { color: var(--c-accent); }
.fb-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 12px; }

/* ---------- footer ---------- */
.site-footer {
  border-top: 1px solid var(--c-border); background: var(--c-surface);
  margin-top: 40px; padding: 30px 0;
}
.footer-inner {
  display: flex; flex-wrap: wrap; gap: 18px 48px;
  justify-content: space-between; align-items: flex-start;
}
.footer-brand-col { max-width: 460px; }
.footer-brand { font-weight: 700; margin: 0 0 6px; }
.footer-tag { color: var(--c-text-soft); font-size: .9rem; margin: 0; }
.footer-links { display: flex; flex-direction: column; gap: 8px; }
.footer-links a { color: var(--c-text-soft); text-decoration: none; font-size: .92rem; }
.footer-links a:hover { color: var(--c-primary); }
.footer-bottom {
  border-top: 1px solid var(--c-border); margin-top: 20px; padding-top: 14px;
  color: var(--c-text-soft); font-size: .82rem; text-align: center;
}
.footer-bottom a { color: inherit; text-decoration: underline; }

/* ---------- responsive ---------- */
@media (min-width: 700px) {
  .game-info { grid-template-columns: 1fr 1fr; }
  .hero { padding-top: 60px; }
}
@media (max-width: 420px) {
  .site-nav { gap: 9px; }
  .site-nav > a { font-size: .85rem; }
  .fb-fab span { display: none; }
  .mm-grid { grid-template-columns: repeat(4, 1fr); width: 100%; }
  .st-grid { grid-template-columns: repeat(5, 1fr); width: 100%; }
  .game-root { padding: 14px; }
}

/* ---------- homepage topic hub ---------- */
/* unify all homepage block widths so their left/right edges line up (full container) */
.home > section { max-width: none; margin-left: 0; margin-right: 0; }
.topics-section { padding: 14px 0 8px; }
.topics-section h2 { font-size: 1.45rem; }
.topics-grid {
  display: grid; gap: 16px;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}
.topic-card {
  display: flex; flex-direction: column; gap: 8px;
  background: var(--c-surface); border: 1px solid var(--c-border); border-radius: var(--radius);
  padding: 26px 22px; text-decoration: none; color: var(--c-text);
  box-shadow: var(--shadow); transition: transform .15s ease, box-shadow .15s ease;
}
.topic-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); }
.topic-icon { font-size: 2.6rem; line-height: 1; }
.topic-card h3 { margin: 4px 0 0; font-size: 1.3rem; }
.topic-card p { margin: 0; color: var(--c-text-soft); font-size: .95rem; flex: 1; }
.topic-meta { color: var(--c-primary); font-weight: 700; font-size: .9rem; margin-top: 6px; }

/* ---------- topic page: embedded featured game ---------- */
.topic-featured { margin: 8px 0 0; text-align: center; }
.topic-featured h2 { font-size: 1.25rem; margin-bottom: 12px; }
.topic-featured-link { margin-top: 10px; }
.topic-featured-link a { color: var(--c-primary); font-weight: 700; text-decoration: none; }
.topic-featured-link a:hover { text-decoration: underline; }

/* ---------- daily word ---------- */
.dw { width: 100%; max-width: 360px; margin: 0 auto; }
.dw-board { display: flex; flex-direction: column; gap: 6px; align-items: center; }
.dw-row { display: flex; gap: 6px; justify-content: center; }
.dw-tile {
  width: 56px; height: 56px; display: flex; align-items: center; justify-content: center;
  font-size: 1.8rem; font-weight: 800; text-transform: uppercase;
  border: 2px solid var(--c-border); border-radius: 8px; background: var(--c-surface); color: var(--c-text);
}
.dw-tile.dw-filled  { border-color: #b9b9c9; }
.dw-tile.dw-correct { background: var(--c-success); border-color: var(--c-success); color: #fff; }
.dw-tile.dw-present { background: var(--c-accent);  border-color: var(--c-accent);  color: #5a4a00; }
.dw-tile.dw-absent  { background: #b2bec3; border-color: #b2bec3; color: #fff; }
.dw-msg { min-height: 20px; text-align: center; color: var(--c-text-soft); font-weight: 600; font-size: .9rem; margin: 8px 0; }
.dw-keyboard { display: flex; flex-direction: column; gap: 6px; }
.dw-kb-row { display: flex; gap: 5px; justify-content: center; }
.dw-key {
  min-width: 30px; height: 50px; padding: 0 6px; border: 0; border-radius: 6px;
  background: #e4e4ee; color: var(--c-text); font-weight: 700; font-size: .95rem;
  text-transform: uppercase; cursor: pointer; transition: filter .12s ease;
}
.dw-key:hover { filter: brightness(.95); }
.dw-key-wide { min-width: 52px; font-size: .78rem; }
.dw-key.dw-correct { background: var(--c-success); color: #fff; }
.dw-key.dw-present { background: var(--c-accent);  color: #5a4a00; }
.dw-key.dw-absent  { background: #9aa5ac; color: #fff; }
.dw-end:empty { display: none; }
.dw-reveal { text-align: center; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--c-border); }
.dw-word { font-size: 1.35rem; margin: 0 0 6px; }
.dw-pos { color: var(--c-text-soft); font-weight: 400; font-size: 1rem; }
.dw-reveal p { margin: 6px 0; color: var(--c-text); line-height: 1.5; }
.dw-label { font-weight: 700; color: var(--c-text-soft); }
.dw-lost { font-size: 1.1rem; font-weight: 700; margin-bottom: 4px; }
.dw-answer { font-size: 1.6rem; font-weight: 800; letter-spacing: 2px; color: var(--c-primary); }
.dw-tomorrow { margin-top: 12px; color: var(--c-text-soft); font-size: .9rem; }
@media (max-width: 380px) {
  .dw-tile { width: 48px; height: 48px; font-size: 1.5rem; }
  .dw-key { height: 46px; min-width: 26px; }
  .dw-key-wide { min-width: 44px; }
}

/* ---------- word unscramble ---------- */
.un { width: 100%; max-width: 460px; margin: 0 auto; text-align: center; }
.un-progress { font-weight: 800; color: var(--c-primary); font-size: 1.05rem; }
.un-label { color: var(--c-text-soft); font-size: .9rem; margin: 2px 0 10px; }
.un-current { min-height: 52px; display: flex; gap: 6px; justify-content: center; align-items: center; }
.un-slot {
  width: 40px; height: 48px; display: flex; align-items: center; justify-content: center;
  font-size: 1.5rem; font-weight: 800; border-bottom: 3px solid var(--c-primary); cursor: pointer;
}
.un-msg { min-height: 20px; color: var(--c-text-soft); font-weight: 600; font-size: .9rem; margin: 6px 0; }
.un-tiles { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin: 6px 0 14px; }
.un-tile {
  width: 52px; height: 56px; border: 0; border-radius: 10px; background: #efeaff;
  color: var(--c-primary-dark); font-size: 1.6rem; font-weight: 800; cursor: pointer;
  box-shadow: var(--shadow); transition: transform .1s ease, opacity .1s ease;
}
.un-tile:hover { transform: translateY(-2px); }
.un-tile.used { opacity: .28; pointer-events: none; }
.un-controls { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; }
.un-finish { display: inline-block; margin-top: 14px; background: none; border: 0; color: var(--c-text-soft); font-weight: 700; cursor: pointer; text-decoration: underline; }
.un-found, .un-missed { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; margin: 14px 0 0; }
.un-word {
  background: #eef7f3; color: #00795f; border-radius: 999px;
  padding: 3px 11px; font-size: .85rem; font-weight: 700;
}
.un-missed .un-word { background: #f1eef9; color: var(--c-primary-dark); }
.un-missed-label { margin: 16px 0 6px; font-weight: 700; color: var(--c-text-soft); }
@media (max-width: 380px) {
  .un-tile { width: 44px; height: 50px; font-size: 1.4rem; }
}

/* ---------- word search ---------- */
.ws { width: 100%; text-align: center; }
.ws-theme { font-size: 1.25rem; font-weight: 800; color: var(--c-primary); }
.ws-progress { color: var(--c-text-soft); font-weight: 600; font-size: .9rem; margin: 2px 0 12px; }
.ws-grid {
  display: grid; gap: 3px; margin: 0 auto 14px; touch-action: none; user-select: none;
}
.ws-cell {
  aspect-ratio: 1 / 1; display: flex; align-items: center; justify-content: center;
  background: var(--c-surface); border: 1px solid var(--c-border); border-radius: 5px;
  font-weight: 700; font-size: 1rem; text-transform: uppercase; cursor: pointer;
}
.ws-cell.sel   { background: var(--c-accent); border-color: var(--c-accent); color: #5a4a00; }
.ws-cell.found { background: #cdeee2; border-color: #00b894; color: #00795f; }
.ws-list { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }
.ws-word { font-weight: 700; font-size: .9rem; color: var(--c-text); padding: 2px 4px; }
.ws-word.found { color: var(--c-text-soft); text-decoration: line-through; }
@media (max-width: 380px) {
  .ws-cell { font-size: .85rem; }
}

/* ---------- sudoku (classic 9x9 / mini 6x6 / daily) ---------- */
.sk { width: 100%; max-width: 480px; margin: 0 auto; text-align: center; }
.sk-bar { display: flex; justify-content: center; align-items: center; margin-bottom: 12px; min-height: 34px; }
.sk-diffs { display: inline-flex; gap: 3px; background: var(--c-bg); border: 1px solid var(--c-border); border-radius: 999px; padding: 3px; }
.sk-diff { border: 0; background: transparent; color: var(--c-text-soft); font: inherit; font-size: .85rem; font-weight: 700; padding: 5px 13px; border-radius: 999px; cursor: pointer; }
.sk-diff.on { background: var(--c-primary); color: #fff; }
.sk-daily-label { color: var(--c-text-soft); font-weight: 600; font-size: .92rem; }

.sk-grid {
  display: grid; gap: 0; margin: 0 auto 12px; width: 100%; max-width: 460px;
  border: 2px solid var(--c-text-soft); border-radius: 8px; overflow: hidden;
  touch-action: manipulation; user-select: none;
}
.sk-cell {
  box-sizing: border-box; aspect-ratio: 1 / 1; display: flex; align-items: center; justify-content: center;
  background: var(--c-surface); border: 1px solid var(--c-border);
  font-size: clamp(1rem, 5.4vw, 1.55rem); font-weight: 600; color: var(--c-primary); cursor: pointer;
}
.sk-cell.given { color: var(--c-text); font-weight: 800; }
.sk-cell.br { border-right: 2px solid var(--c-text-soft); }
.sk-cell.bb { border-bottom: 2px solid var(--c-text-soft); }
.sk-cell.peer { background: #f1effb; }
.sk-cell.same { background: #e4defb; }
.sk-cell.sel  { background: #d3c9fb; box-shadow: inset 0 0 0 2px var(--c-primary); }
.sk-cell.bad  { background: #ffe3e3; color: var(--c-error); }
.sk-cell.hintflash { animation: sk-flash .9s ease; }
@keyframes sk-flash { 0%, 100% { box-shadow: inset 0 0 0 2px var(--c-primary); } 50% { box-shadow: inset 0 0 0 4px var(--c-accent); background: #fff6e3; } }
.sk-val { line-height: 1; }
.sk-notes { display: grid; grid-template-columns: repeat(3, 1fr); width: 100%; height: 100%; padding: 2px; box-sizing: border-box; }
.sk-notes span { font-size: clamp(.5rem, 2.1vw, .68rem); color: var(--c-text-soft); font-weight: 600; display: flex; align-items: center; justify-content: center; line-height: 1; }

.sk-msg { min-height: 1.5em; color: var(--c-text-soft); font-weight: 600; font-size: .9rem; margin: 4px 0 10px; line-height: 1.35; }

.sk-pad { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; margin-bottom: 12px; }
.sk-num {
  flex: 1 1 0; min-width: 38px; max-width: 56px; height: 50px; border: 1px solid var(--c-border);
  border-radius: 10px; background: var(--c-surface); color: var(--c-primary-dark);
  font: inherit; font-size: 1.3rem; font-weight: 800; cursor: pointer; box-shadow: var(--shadow);
}
.sk-num:hover { background: #f3f0ff; }
.sk-num:active { transform: scale(.96); }
.sk-erase { color: var(--c-text-soft); font-size: 1.2rem; }

.sk-controls { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-bottom: 10px; }
.sk-ctl {
  border: 1px solid var(--c-border); background: var(--c-surface); color: var(--c-text);
  font: inherit; font-size: .9rem; font-weight: 700; padding: 9px 14px; border-radius: 10px; cursor: pointer;
}
.sk-ctl:hover { background: var(--c-bg); }
.sk-ctl.on { background: var(--c-primary); color: #fff; border-color: var(--c-primary); }

.sk-opts { display: flex; gap: 14px; justify-content: center; align-items: center; flex-wrap: wrap; }
.sk-opt { background: none; border: 0; color: var(--c-text-soft); font: inherit; font-size: .82rem; cursor: pointer; text-decoration: underline; }
.sk-timer { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--c-text); font-size: .9rem; }
.sk-end { margin-top: 16px; }
.sk-end:empty { display: none; }
.sk-tomorrow { margin-top: 12px; color: var(--c-text-soft); font-size: .9rem; }

/* large-print mode: bigger numbers + stronger contrast (great for seniors) */
.sk.sk-large { max-width: 540px; }
.sk.sk-large .sk-cell { font-size: clamp(1.3rem, 6.6vw, 2.1rem); }
.sk.sk-large .sk-cell.given { color: #000; }
.sk.sk-large .sk-num { height: 56px; font-size: 1.5rem; }

/* ---------- mahjong solitaire ---------- */
/* Tile geometry comes from --tw/--th/--dx/--dy, set on .mj-board by mahjong.js: every
   tile positions itself with calc() off those, so resizing only rewrites four numbers
   instead of re-laying out 144 nodes. Faces are drawn here (dots, bars, CJK) because
   the Unicode mahjong block is tofu in the default font stack on much of Windows. */
.mj { width: 100%; text-align: center; }
.mj-bar { display: flex; justify-content: center; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: 10px; min-height: 34px; }
.mj-sizes { display: inline-flex; gap: 3px; background: var(--c-bg); border: 1px solid var(--c-border); border-radius: 999px; padding: 3px; }
.mj-size { border: 0; background: transparent; color: var(--c-text-soft); font: inherit; font-size: .85rem; font-weight: 700; padding: 5px 13px; border-radius: 999px; cursor: pointer; }
.mj-size.on { background: var(--c-primary); color: #fff; }
.mj-left { color: var(--c-text-soft); font-weight: 600; font-size: .9rem; }

.mj-wrap {
  overflow-x: auto; overflow-y: hidden; padding: 14px 6px 16px; border-radius: 14px;
  background: radial-gradient(120% 100% at 50% 0%, #f2f4f0 0%, #e6eae2 55%, #dde3d8 100%);
  box-shadow: inset 0 1px 3px rgba(60, 70, 50, .1);
}
.mj-board { position: relative; margin: 0 auto; touch-action: manipulation; user-select: none; }

/* A tile is a face (the footprint the grid places) plus a body whose thickness sticks out
   BEYOND it, to the right and below. That overhang is the trick: within one flat layer the
   next tile along is painted on top of it (z-index rises with hx and hy), so a flat block
   reads as an edge-to-edge field of faces with thickness showing only along its bottom-right
   border — while a tile stacked on the layer above shows its full thickness and casts a
   shadow. Walls between every neighbour would make a flat layer look like a staircase. */
.mj-tile {
  position: absolute; width: var(--tw); height: var(--th);
  padding: 0; border: 0; background: none; font: inherit;
  cursor: default; transition: transform .09s ease;
}
.mj-tile[hidden] { display: none; }          /* our display:flex would beat the UA rule */
.mj-body {
  position: absolute; left: 0; top: 0;
  right: calc(-1 * var(--dz)); bottom: calc(-1 * var(--dz));
  border-radius: 7px;
  background: linear-gradient(152deg, #d6c29a 0%, #b49b6d 42%, #8a7245 100%);
  /* the hairline outline stops neighbouring tiles merging into one ivory mosaic;
     the long soft shadow is what separates one layer from the next */
  /* --lz is the tile's layer: the higher it sits, the longer and softer the shadow it
     drops on the pile below. Shadows never take pointer events, so this is the one depth
     cue we can lay on thickly without eating into anything's clickable area. */
  box-shadow: 0 0 0 1px rgba(78, 64, 36, .5),
              calc(var(--dz) * (.4 + var(--lz) * .3)) calc(var(--dz) * (.7 + var(--lz) * .45))
              calc(var(--dz) * (1.2 + var(--lz) * .7)) rgba(28, 32, 50, calc(.4 + var(--lz) * .06));
}
.mj-face {
  /* a hairline of the body shows along the right and bottom: the groove real tiles have
     between them, without which a flat layer merges into one continuous ivory field */
  position: absolute; left: 0; top: 0; right: var(--gap); bottom: var(--gap);
  display: flex; align-items: center; justify-content: center;
  border: 1px solid #bfae87; border-radius: 6px;
  background: linear-gradient(155deg, #fffefa 0%, #fdf8ec 55%, #f5eeda 100%);
  overflow: hidden;
}
.mj-face img { width: 88%; height: 88%; object-fit: contain; pointer-events: none; }

.mj-tile.free { cursor: pointer; }
/* Hover brightens the face instead of moving the tile: on a board this dense, tiles that
   jump a couple of pixels under the cursor read as jitter (and shift their own hit box). */
.mj-tile.free:hover .mj-face { background: linear-gradient(155deg, #ffffff 0%, #fffdf4 55%, #fbf6e6 100%); }
.mj-tile.free:focus-visible { outline: 3px solid var(--c-primary); outline-offset: 2px; border-radius: 8px; }
/* Blocked tiles sit in shadow rather than fading out: working out what is even liftable
   on a 144-tile pile is the tedious part, not the interesting part — but the artwork
   still has to look like artwork. */
.mj-tile.blocked .mj-face::after {
  content: ''; position: absolute; inset: 0; background: rgba(96, 84, 54, .26);
}
.mj-tile.sel { transform: translate(-2px, -3px); }
.mj-tile.sel .mj-face { box-shadow: inset 0 0 0 3px var(--c-primary); }
.mj-tile.hint .mj-face { animation: mj-flash .55s ease-in-out 4; }
.mj-tile.nope { animation: mj-nope .4s ease; }
@keyframes mj-flash { 50% { box-shadow: inset 0 0 0 4px var(--c-accent); background: #fff6e0; } }
@keyframes mj-nope { 25% { transform: translateX(-3px); } 75% { transform: translateX(3px); } }

.mj-msg { min-height: 1.5em; color: var(--c-text-soft); font-weight: 600; font-size: .9rem; margin: 2px 0 10px; line-height: 1.35; }
.mj-controls { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-bottom: 10px; }
.mj-ctl {
  border: 1px solid var(--c-border); background: var(--c-surface); color: var(--c-text);
  font: inherit; font-size: .9rem; font-weight: 700; padding: 9px 14px; border-radius: 10px; cursor: pointer;
}
.mj-ctl:hover { background: var(--c-bg); }
.mj-opts { display: flex; gap: 14px; justify-content: center; align-items: center; flex-wrap: wrap; }
.mj-opt { background: none; border: 0; color: var(--c-text-soft); font: inherit; font-size: .82rem; cursor: pointer; text-decoration: underline; }
.mj-timer { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--c-text); font-size: .9rem; }
.mj-end { margin-top: 16px; }
.mj-end:empty { display: none; }

/* ---------- tools (/tools/{slug}) ---------- */
.tool-hero { margin: 24px 0 8px; }
.tool-kicker { color: var(--c-text-soft); font-weight: 600; font-size: .9rem; margin: 0 0 4px; }
.tool-hero h1 { margin: 0 0 8px; }
.tool-hero .lead { color: var(--c-text-soft); font-size: 1.05rem; margin: 0; }
.tool-prose { margin-top: 40px; }
.tool-steps { padding-left: 20px; }
.tool-steps li { margin-bottom: 8px; }
.tool-crosslink { color: var(--c-text-soft); }

.wsm-ui {
  background: var(--c-surface); border: 1px solid var(--c-border);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 20px; margin: 20px 0;
}
.wsm-field { margin-bottom: 16px; }
.wsm-field label { display: block; font-weight: 600; margin-bottom: 6px; }
.wsm-field input[type="text"], .wsm-field textarea, .wsm-field select {
  width: 100%; padding: 10px 12px; font: inherit; color: var(--c-text);
  background: var(--c-bg); border: 1px solid var(--c-border); border-radius: 10px;
}
.wsm-field textarea { resize: vertical; min-height: 120px; font-variant-numeric: tabular-nums; }
.wsm-help { color: var(--c-text-soft); font-size: .88rem; margin: 6px 0 0; }
.wsm-link {
  background: none; border: 0; padding: 0; font: inherit; color: var(--c-primary);
  text-decoration: underline; cursor: pointer;
}
.wsm-row { display: grid; gap: 16px; }
.wsm-checks { border: 0; padding: 0; margin: 0 0 16px; }
.wsm-legend { font-weight: 600; padding: 0; margin-bottom: 6px; }
.wsm-check { display: block; margin-bottom: 6px; color: var(--c-text); }
.wsm-actions { display: flex; flex-wrap: wrap; gap: 10px; }
.wsm-msg { margin: 12px 0 0; color: var(--c-text-soft); min-height: 1.4em; }
.wsm-msg-warn { color: var(--c-error); }

/* the sheet — what actually gets printed */
.wsm-sheet {
  background: #fff; border: 1px solid var(--c-border); border-radius: var(--radius);
  padding: 24px; margin: 20px 0; box-shadow: var(--shadow);
}
.wsm-sheet-title { margin: 0 0 4px; text-align: center; }
.wsm-sheet-kicker { margin: 0 0 12px; text-align: center; color: var(--c-text-soft); font-weight: 600; }
/* A word search should read as a dense block of letters — a wide grid of big sparse
   squares is hard to scan and wastes the page. Keep it tight on screen and on paper. */
.wsm-grid { display: grid; gap: 2px; margin: 0 auto; max-width: 460px; }
.wsm-cell {
  aspect-ratio: 1; display: flex; align-items: center; justify-content: center;
  font-weight: 600; font-size: clamp(.7rem, 2.2vw, 1.05rem); letter-spacing: .02em;
  color: #111;
}
.wsm-cell.on { background: var(--c-accent); border-radius: 4px; }
.wsm-list-title { font-weight: 700; margin: 20px 0 8px; }
.wsm-list {
  list-style: none; padding: 0; margin: 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 4px 12px;
}
.wsm-list li { font-weight: 600; letter-spacing: .03em; }
.wsm-credit { margin: 22px 0 0; text-align: center; font-size: .72rem; color: #999; }

/* live print options, toggled on #wsm-root by the tool's JS */
.wsm-is-large .wsm-grid { gap: 5px; max-width: 560px; }
.wsm-is-large .wsm-cell { font-size: clamp(.95rem, 3.2vw, 1.5rem); font-weight: 700; }
.wsm-is-large .wsm-list { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); font-size: 1.15rem; }
#tool-root:not(.wsm-is-answers) .wsm-sheet-answer { display: none; }
.wsm-no-credit .wsm-credit { display: none; }

@media (min-width: 640px) {
  .wsm-row { grid-template-columns: 1fr 1fr; }
}

/* ---------- killer sudoku ---------- */
/* Reuses the sudoku pad/controls (.sk-*); only the board differs. The cage outline is a
   separate inset layer per cell rather than borders on the cell itself, so dashed cage edges
   and solid 3x3 box lines can sit on the same boundary without fighting each other. */
.ks-grid {
  display: grid; grid-template-columns: repeat(9, 1fr); gap: 0;
  margin: 0 auto 12px; width: 100%; max-width: 460px;
  border: 2px solid var(--c-text-soft); border-radius: 8px; overflow: hidden;
  touch-action: manipulation; user-select: none;
}
.ks-cell {
  position: relative; box-sizing: border-box; aspect-ratio: 1 / 1;
  display: flex; align-items: center; justify-content: center;
  background: var(--c-surface); border: 1px solid var(--c-border);
  font-size: clamp(1rem, 5.4vw, 1.55rem); font-weight: 600; color: var(--c-primary); cursor: pointer;
}
.ks-cell.given { color: var(--c-text); font-weight: 800; }
.ks-cell.br { border-right: 2px solid var(--c-text-soft); }
.ks-cell.bb { border-bottom: 2px solid var(--c-text-soft); }
.ks-cell.peer { background: #f1effb; }
.ks-cell.incage { background: #efeafc; }
.ks-cell.same { background: #e4defb; }
.ks-cell.sel  { background: #d3c9fb; box-shadow: inset 0 0 0 2px var(--c-primary); }
.ks-cell.bad  { background: #ffe3e3; color: var(--c-error); }
.ks-cell.hintflash { animation: sk-flash .9s ease; }

.ks-cage { position: absolute; inset: 3px; pointer-events: none; border: 0 dashed #9a92b8; }
.ks-cage.kt { border-top-width: 1.5px; }
.ks-cage.kb { border-bottom-width: 1.5px; }
.ks-cage.kl { border-left-width: 1.5px; }
.ks-cage.kr { border-right-width: 1.5px; }
/* The cage total sits in the corner the outline already brackets. */
.ks-sum {
  position: absolute; top: 3px; left: 4px; line-height: 1;
  font-size: clamp(.5rem, 2.1vw, .7rem); font-weight: 800; color: var(--c-text-soft);
}
.ks-large .ks-grid { max-width: 560px; }
.ks-large .ks-cell { font-size: clamp(1.2rem, 6.4vw, 2rem); font-weight: 800; }
.ks-large .ks-sum { font-size: clamp(.6rem, 2.6vw, .85rem); color: var(--c-text); }
/* Notes must clear the cage total, or the two overlap in the top-left square. */
.ks-cell .sk-notes { padding-top: 8px; }

/* ---------- tool: sudoku solver ---------- */
/* The grid is 81 real <input>s, so it works before JS and on a phone keypad. Styling mirrors
   the game board (.sk-*) so the two read as the same product. */
.sks-board-wrap { display: flex; justify-content: center; }
.sks-grid {
  display: grid; grid-template-columns: repeat(9, 1fr); gap: 0;
  width: 100%; max-width: 460px; margin: 0 0 14px;
  border: 2px solid var(--c-text-soft); border-radius: 8px; overflow: hidden;
}
.sks-cell {
  box-sizing: border-box; aspect-ratio: 1 / 1; min-width: 0; padding: 0;
  background: var(--c-surface); border: 1px solid var(--c-border); border-radius: 0;
  font: inherit; font-size: clamp(1rem, 5.2vw, 1.5rem); font-weight: 800;
  color: var(--c-text); text-align: center;
}
.sks-cell:focus { outline: none; background: #d3c9fb; box-shadow: inset 0 0 0 2px var(--c-primary); }
.sks-cell.br { border-right: 2px solid var(--c-text-soft); }
.sks-cell.bb { border-bottom: 2px solid var(--c-text-soft); }
.sks-cell.bad { background: #ffe3e3; color: var(--c-error); }
/* Worked out for you, never confused with what you typed. */
.sks-cell.solved { color: var(--c-primary); font-weight: 600; }
.sks-cell.stepped { animation: sk-flash .9s ease; }

.sks-msg { min-height: 1.5em; color: var(--c-text-soft); font-weight: 600; font-size: .95rem; margin: 0 0 12px; line-height: 1.4; }
.sks-msg-warn { color: var(--c-error); }
.sks-msg-good { color: var(--c-success); }
.sks-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 14px; }
.sks-hint-help { color: var(--c-text-soft); font-size: .88rem; margin: 0; }

/* ---------- tool: printable sudoku ---------- */
.psk-ui {
  background: var(--c-surface); border: 1px solid var(--c-border); border-radius: var(--radius);
  padding: 20px; margin: 18px 0 24px;
}
.psk-row { display: grid; gap: 16px; }
.psk-field { margin-bottom: 4px; }
.psk-field label { display: block; font-weight: 600; margin-bottom: 6px; }
.psk-field select {
  width: 100%; box-sizing: border-box; padding: 10px 12px; font: inherit;
  border: 1px solid var(--c-border); border-radius: 10px; background: var(--c-surface); color: var(--c-text);
}
.psk-checks { border: 0; padding: 0; margin: 16px 0; }
.psk-legend { font-weight: 600; padding: 0; margin-bottom: 6px; }
.psk-check { display: block; margin-bottom: 6px; color: var(--c-text); }
.psk-actions { display: flex; flex-wrap: wrap; gap: 10px; }
.psk-msg { margin: 12px 0 0; color: var(--c-text-soft); min-height: 1.4em; }
.psk-msg-warn { color: var(--c-error); }

.psk-sheet {
  background: var(--c-surface); border: 1px solid var(--c-border); border-radius: var(--radius);
  padding: 22px; margin-bottom: 18px;
}
/* One and two per page stack in a single column — a sudoku is square, so on portrait paper
   two side by side would be half the size of two stacked. Four and six go two across. */
.psk-page-grid { display: grid; gap: 22px; }
.psk-per-4 .psk-page-grid, .psk-per-6 .psk-page-grid { grid-template-columns: repeat(2, 1fr); }
.psk-item-head { margin: 0 0 8px; font-weight: 700; font-size: .9rem; color: var(--c-text-soft); text-align: center; }
.psk-board {
  display: grid; grid-template-columns: repeat(9, 1fr); gap: 0;
  width: 100%; max-width: 420px; margin: 0 auto;
  border: 2px solid var(--c-text); border-radius: 4px; overflow: hidden;
}
.psk-cell {
  box-sizing: border-box; aspect-ratio: 1 / 1; display: flex; align-items: center; justify-content: center;
  background: #fff; border: 1px solid #c8c8d0; font-size: clamp(.7rem, 2.4vw, 1.1rem); font-weight: 700; color: #000;
}
.psk-cell.br { border-right: 2px solid var(--c-text); }
.psk-cell.bb { border-bottom: 2px solid var(--c-text); }
/* On the answer key, the numbers that were blanks are greyed so the clues still read as clues. */
.psk-cell.psk-filled { color: #7a7a86; font-weight: 500; }
.psk-credit { margin: 18px 0 0; text-align: center; font-size: .72rem; color: #999; }

#tool-root:not(.psk-is-answers) .psk-sheet-answer { display: none; }
.psk-no-credit .psk-credit { display: none; }

/* ---------- solitaire: klondike / freecell / spider ---------- */
/* Card geometry is two custom properties (--cw/--ch) set on .sol-board by solitaire.js;
   every card and pile sizes itself off those, so a resize or the full-screen toggle
   rewrites two numbers instead of re-laying out 104 nodes. Faces are text + CSS, not
   images: ♠♥♦♣ (U+2660-2663) are in every default font stack, while the playing-card
   block (U+1F0A0…) is tofu on much of Windows, which is where this traffic comes from. */
.sol { width: 100%; text-align: center; }
.sol-bar { display: flex; justify-content: center; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: 10px; min-height: 34px; }
.sol-seg { display: inline-flex; gap: 3px; background: var(--c-bg); border: 1px solid var(--c-border); border-radius: 999px; padding: 3px; }
.sol-segbtn { border: 0; background: transparent; color: var(--c-text-soft); font: inherit; font-size: .85rem; font-weight: 700; padding: 5px 13px; border-radius: 999px; cursor: pointer; }
.sol-segbtn.on { background: var(--c-primary); color: #fff; }
.sol-stats { color: var(--c-text-soft); font-weight: 600; font-size: .9rem; font-variant-numeric: tabular-nums; }

.sol-boardwrap {
  overflow-x: auto; overflow-y: hidden; padding: 12px 8px 14px; border-radius: 14px;
  background: radial-gradient(120% 100% at 50% 0%, #2f7d54 0%, #23694a 55%, #1b543c 100%);
  box-shadow: inset 0 1px 4px rgba(0, 30, 15, .35);
}
.sol-board { position: relative; margin: 0 auto; touch-action: manipulation; user-select: none; }

/* A pile is the drop target, so it has to reach the bottom of its own fan — solitaire.js
   sets the height of every tableau column for exactly that reason. */
.sol-pile { position: absolute; width: var(--cw); height: var(--ch); }
.sol-pile.sol-empty::before {
  content: ''; position: absolute; inset: 0; border-radius: calc(var(--cw) * .09);
  border: 1px dashed rgba(255, 255, 255, .34); background: rgba(255, 255, 255, .05);
}
.sol-stock.sol-recycle::before { content: '↻'; display: grid; place-items: center; color: rgba(255,255,255,.6); font-size: calc(var(--cw) * .4); }

.sol-card {
  position: absolute; width: var(--cw); height: var(--ch);
  border-radius: calc(var(--cw) * .09);
  background: #fff; color: #1a1a1a;
  box-shadow: 0 0 0 1px rgba(20, 40, 30, .28), 0 1px 2px rgba(0, 20, 10, .28);
  cursor: default; overflow: hidden;
}
.sol-card.sol-red { color: #cc2b2b; }
.sol-card.live { cursor: pointer; }
.sol-card.sel { box-shadow: 0 0 0 2px var(--c-primary), 0 2px 8px rgba(0, 20, 10, .4); }
/* Rank and suit sit side by side, not stacked. In a fanned column only the top sliver of
   each card is visible, and a stacked corner puts the suit in the part the next card
   covers — you could read the ranks but not the suits, which is most of the information. */
.sol-corner {
  position: absolute; left: 7%; top: 1%; display: flex; align-items: baseline; gap: .12em;
  line-height: 1; font-weight: 800;
  font-size: calc(var(--cw) * .3); font-variant-numeric: tabular-nums;
}
.sol-corner .sol-suit { font-size: calc(var(--cw) * .27); font-weight: 400; }
.sol-pip {
  position: absolute; right: 5%; bottom: 1%;
  font-size: calc(var(--cw) * .52); line-height: 1; opacity: .9;
}
/* The back needs a visible weave: a flat block of colour makes a face-down column read as
   one tall slab instead of a stack of cards. */
.sol-card.sol-down { background: #4a5bb5; }
.sol-back {
  position: absolute; inset: 6%; border-radius: calc(var(--cw) * .06);
  background:
    repeating-linear-gradient(45deg, rgba(255,255,255,.16) 0 2px, transparent 2px 6px),
    repeating-linear-gradient(-45deg, rgba(255,255,255,.16) 0 2px, transparent 2px 6px),
    linear-gradient(150deg, #6070cc 0%, #4a5bb5 60%, #3a49a0 100%);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .28);
}

/* The dragged stack rides on the body so it is never clipped by the board's scroll box. */
.sol-ghost { position: fixed; z-index: 9999; pointer-events: none; width: var(--cw); filter: drop-shadow(0 6px 10px rgba(0, 20, 10, .45)); }
.sol-ghost .sol-card { position: absolute; }
.sol-lifting .sol-card.sel { opacity: .28; }

.sol-msg { min-height: 1.5em; color: var(--c-text-soft); font-weight: 600; font-size: .9rem; margin: 6px 0 10px; line-height: 1.35; }
.sol-controls { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-bottom: 10px; }
.sol-ctl {
  border: 1px solid var(--c-border); background: var(--c-surface); color: var(--c-text);
  font: inherit; font-size: .88rem; font-weight: 600; padding: 8px 14px; border-radius: 10px; cursor: pointer;
}
.sol-ctl:hover { background: var(--c-bg); }
.sol-ctl[hidden] { display: none; }
/* Full-screen icon drawn with borders rather than typed as a glyph — see solitaire.js.
   Two nested corners read as "expand" at any size and cannot tofu. */
.sol-fs { display: inline-flex; align-items: center; gap: 7px; }
.sol-fsicon {
  position: relative; display: inline-block; width: .85em; height: .72em;
  border: 2px solid currentColor; border-radius: 2px;
}
.sol-fsicon::before {
  content: ''; position: absolute; inset: 2px;
  border-top: 2px solid currentColor; border-bottom: 2px solid currentColor; opacity: .45;
}
.sol-opts { display: flex; gap: 14px; justify-content: center; align-items: center; flex-wrap: wrap; }
.sol-opt { background: none; border: 0; color: var(--c-text-soft); font: inherit; font-size: .82rem; cursor: pointer; text-decoration: underline; }
.sol-timer { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--c-text); font-size: .9rem; }
.sol-end { margin-top: 16px; }
.sol-end:empty { display: none; }

/* Full screen shows the GAME, not the page enlarged. The felt becomes the entire screen
   and the controls sit on top of it; keeping the page-grey background here would just
   look like the layout had been zoomed. The element is put into real full screen by the
   Fullscreen API (solitaire.js), and these same rules drive the fixed-position fallback
   used on iOS Safari — hence position/inset/z-index, which are inert once the browser has
   promoted the element. z-index clears the sticky site header, which sits at 50. */
.sol-full {
  position: fixed; inset: 0; z-index: 200; margin: 0; padding: 10px 12px 12px;
  display: flex; flex-direction: column; overflow: hidden;
  background: radial-gradient(120% 100% at 50% 0%, #2f7d54 0%, #23694a 55%, #1b543c 100%);
}
/* Zero flex-basis: the felt takes exactly the space the controls leave, which is what
   roomFor() measures to size the cards. With `auto` it would size to the board instead
   and the two would chase each other. */
.sol-full .sol-boardwrap {
  flex: 1 1 0; min-height: 0; padding: 0; border-radius: 0;
  background: none; box-shadow: none;
  /* Scrolls in BOTH directions here, unlike on the page: with Large cards on, the board is
     deliberately allowed to outgrow the felt, and the felt has a fixed height in full
     screen, so overflow-y: hidden would put part of the board out of reach. `safe` keeps a
     board bigger than the felt from having its top-left corner cropped past the scroll. */
  overflow: auto;
  display: flex; align-items: center; align-items: safe center;
  justify-content: center; justify-content: safe center;
}
/* As a flex item the board would otherwise shrink below its own width, squashing the
   columns instead of letting the felt pan — which is what ten-column Spider needs on a
   phone, where the cards are already at their legibility floor. */
.sol-full .sol-board { flex: none; }
.sol-full .sol-bar { margin-bottom: 8px; }
.sol-full .sol-msg { color: rgba(255, 255, 255, .88); margin: 6px 0 8px; }
.sol-full .sol-stats { color: rgba(255, 255, 255, .82); }
.sol-full .sol-timer { color: #fff; }
.sol-full .sol-seg { background: rgba(0, 0, 0, .22); border-color: rgba(255, 255, 255, .22); }
.sol-full .sol-segbtn { color: rgba(255, 255, 255, .78); }
.sol-full .sol-segbtn.on { background: #fff; color: #1b543c; }
.sol-full .sol-ctl {
  background: rgba(255, 255, 255, .13); border-color: rgba(255, 255, 255, .3); color: #fff;
}
.sol-full .sol-ctl:hover { background: rgba(255, 255, 255, .24); }
.sol-full .sol-opt { color: rgba(255, 255, 255, .72); }
.sol-full .sol-end { margin-top: 10px; }
/* Every row of chrome here is a row the cards do not get. Entering full screen must never
   make the cards SMALLER than they were on the page, and on a landscape phone (~390px of
   height) the default strip was enough to do exactly that. So: no reserved empty message
   line, and tighter buttons. */
.sol-full .sol-msg:empty { display: none; }
.sol-full .sol-ctl { padding: 6px 12px; font-size: .85rem; }
.sol-full .sol-controls { margin-bottom: 6px; }
@media (max-height: 520px) {
  .sol-full { padding: 6px 10px 8px; }
  .sol-full .sol-bar { margin-bottom: 4px; }
  .sol-full .sol-opts { display: none; }
}
body.sol-locked { overflow: hidden; }

/* ---------- print: only the puzzle sheet survives ---------- */
@media print {
  .site-header, .site-footer, .fb-dialog,
  .tool-hero, .tool-prose, .wsm-ui, .psk-ui, .sks-ui { display: none !important; }

  html, body { background: #fff; }
  .container { max-width: none; padding: 0; }

  .wsm-sheet { border: 0; border-radius: 0; box-shadow: none; padding: 0; margin: 0; }
  /* Break BEFORE the answer key, never after the puzzle: a display:none answer sheet is
     still :last-child, so a trailing break-after would eject a blank page every time. */
  .wsm-sheet-answer { break-before: page; page-break-before: always; }
  #tool-root:not(.wsm-is-answers) .wsm-sheet-answer { display: none !important; }

  /* Fixed millimetre widths, not 100% — the cells are square, so an edge-to-edge grid
     becomes as tall as it is wide and pushes the word list onto a second page. */
  .wsm-grid { width: 135mm; max-width: 100%; gap: .6mm; }
  .wsm-cell { font-size: 12pt; color: #000; }
  .wsm-is-large .wsm-grid { width: 165mm; gap: 1.2mm; }
  .wsm-is-large .wsm-cell { font-size: 17pt; }

  /* Per-cell outlines read as a maze of boxes. A flat grey fill traces the word cleanly —
     print-color-adjust keeps it, since browsers drop backgrounds when printing by default. */
  .wsm-cell.on {
    background: #cfcfcf !important; outline: 0; border-radius: 0;
    -webkit-print-color-adjust: exact; print-color-adjust: exact;
  }

  .wsm-sheet-title { font-size: 16pt; }
  .wsm-list-title { font-size: 11pt; margin: 8mm 0 3mm; }
  .wsm-list { font-size: 11pt; grid-template-columns: repeat(auto-fill, minmax(32mm, 1fr)); }
  .wsm-is-large .wsm-list { font-size: 14pt; grid-template-columns: repeat(auto-fill, minmax(42mm, 1fr)); }
  .wsm-credit { color: #777; font-size: 8pt; margin-top: 8mm; }

  /* ----- printable sudoku ----- */
  .psk-sheet { border: 0; border-radius: 0; box-shadow: none; padding: 0; margin: 0; }
  /* Break BEFORE each sheet after the first, never after: a break-after on the last sheet
     ejects a trailing blank page (same trap as the word search answer key). */
  .psk-sheet + .psk-sheet { break-before: page; page-break-before: always; }
  #tool-root:not(.psk-is-answers) .psk-sheet-answer { display: none !important; }
  /* A hidden answer sheet is still a sibling, so the first visible puzzle sheet after it
     would inherit a page break it doesn't need — reset when answers are off. */
  #tool-root:not(.psk-is-answers) .psk-sheet-answer + .psk-sheet { break-before: auto; page-break-before: auto; }

  .psk-page-grid { gap: 8mm; }
  /* Millimetre widths, not percentages: the cells are square, so an edge-to-edge grid would
     be as tall as the page is wide and push the last row off the sheet. */
  .psk-board { width: 155mm; max-width: 100%; border-color: #000; }
  .psk-per-2 .psk-board { width: 115mm; }
  .psk-per-4 .psk-board, .psk-per-6 .psk-board { width: 82mm; }
  .psk-cell { font-size: 15pt; border-color: #999; }
  .psk-per-2 .psk-cell { font-size: 12pt; }
  .psk-per-4 .psk-cell, .psk-per-6 .psk-cell { font-size: 9pt; }
  .psk-cell.br { border-right: 1.6pt solid #000; }
  .psk-cell.bb { border-bottom: 1.6pt solid #000; }
  .psk-item-head { font-size: 10pt; color: #000; margin-bottom: 3mm; }
  .psk-credit { color: #777; font-size: 8pt; margin-top: 6mm; }
}

@page { margin: 14mm; }
