/* The technique pages (/learn/<technique>/) and their index (/learn/).

   Three parts: the prose and its worked example, which are static HTML from
   tools/build_pages.mjs; and the practice, which learn-app.js mounts into #app.
   Everything reuses the board, its tokens and the shared control floor.

   The one genuinely new board visual is a marked candidate. It cannot be a
   colour change alone -- a marked candidate says "I claim this can be ruled
   out", which is the answer being composed, so it has to be legible without
   colour vision. A strike-through carries the meaning (this digit is going), a
   box carries the selection, and the colour is the third signal rather than
   the only one. */

/* ------------------------------------------------------------------ page */

.learn-page {
    /* The prose measure. The practice board is allowed out to its own width
       below; text is not, because a 90-character line is hard to read. */
    max-inline-size: 46rem;
    margin: 0 auto;
    padding: 16px 16px 8px;
    line-height: 1.65;
}

.learn-page a {
    color: var(--fg-user);
}

.learn-page a:hover,
.learn-page a:focus-visible {
    color: var(--fg-body);
}

.learn-page .learn-crumbs ol {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: 0.875rem;
}

/* A separator drawn by CSS rather than typed into the list, so a screen reader
   reads three links, not three links and two slashes. */
.learn-crumbs li + li::before {
    content: "\203A";
    margin-inline-end: 4px;
    color: var(--fg-candidate);
}

.learn-page-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 8px 16px;
    margin-block: 12px 4px;
}

.learn-page h1 {
    margin: 0;
    font-size: 1.75rem;
    line-height: 1.25;
}

/* Styled as the same control the game pages carry, not left as a bare link:
   on the dark theme the browser's default link blue is close to unreadable. */
.learn-page .lang-switch {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-inline-size: var(--control-floor);
    min-block-size: var(--control-floor);
    padding: 0 12px;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: var(--bg-cell);
    color: var(--fg-body);
    text-decoration: none;
}

.learn-page .lang-switch:focus-visible {
    outline: 2px solid var(--focus);
    outline-offset: 2px;
}

.learn-lead {
    margin: 0 0 8px;
    font-size: 1.0625rem;
}

.learn-meta {
    margin: 0 0 16px;
    color: var(--fg-candidate);
    font-size: 0.875rem;
}

.learn-page h2 {
    margin: 32px 0 8px;
    font-size: 1.25rem;
    line-height: 1.4;
}

.learn-page h3 {
    margin: 20px 0 6px;
    font-size: 1.0625rem;
}

.learn-page p {
    margin: 0 0 12px;
}

.learn-page ul,
.learn-page ol {
    margin: 0 0 12px;
    padding-inline-start: 1.4rem;
}

.learn-page li {
    margin-block-end: 6px;
}

/* ------------------------------------------------------------- the index */

.learn-cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr));
    gap: 12px;
    margin: 0 0 16px;
    padding: 0 !important;
    list-style: none;
}

.learn-card {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin: 0 !important;
    padding: 14px 16px;
    border: 1px solid var(--line);
    border-radius: 10px;
    background: var(--bg-cell);
}

.learn-card h3 {
    margin: 0;
}

.learn-card p {
    margin: 0;
}

.learn-card-step,
.learn-card-record {
    color: var(--fg-candidate);
    font-size: 0.8125rem;
}

/* ------------------------------------------------------ the worked example

   Static HTML: 81 cells plus the row and column numbers the step-by-step text
   refers to. The whole figure is one role="img" with a text alternative -- the
   steps underneath already say in words what the picture shows. */

.example {
    margin: 16px 0;
}

.example-board {
    --ex-size: min(100%, 26rem);
    display: grid;
    /* minmax(0, ...) rather than 1fr: a bare 1fr never shrinks below a cell's
       min-content, and the candidate cells' min-content made the board 370px
       wide -- wider than a 390px phone once the page padding is added. */
    grid-template-columns: 1.25rem repeat(9, minmax(0, 1fr));
    inline-size: var(--ex-size);
    margin-inline: auto;
}

.ex-label {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--fg-candidate);
    font-size: 0.75rem;
}

.ex-cell {
    position: relative;
    min-inline-size: 0;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 1;
    border-right: 1px solid var(--line);
    border-bottom: 1px solid var(--line);
    background: var(--bg-page);
    font-size: 1.125rem;
    font-weight: 600;
    color: var(--fg-given);
}

/* The grid's outer frame and box lines, from classes the build adds. */
.ex-cell.ex-c0 { border-left: 3px solid var(--line); }
.ex-cell.ex-r0 { border-top: 3px solid var(--line); }
.ex-cell.ex-c2,
.ex-cell.ex-c5,
.ex-cell.ex-c8 { border-right-width: 3px; }
.ex-cell.ex-r2,
.ex-cell.ex-r5,
.ex-cell.ex-r8 { border-bottom-width: 3px; }

/* Outside the evidence: present, but quiet. The same treatment the practice
   board uses, so the example teaches the reader to read the practice board. */
.ex-cell:not([data-focus="1"]) > * {
    opacity: 0.32;
}

.ex-cell[data-focus="1"] {
    background: var(--bg-cell);
}

/* The unit the deduction is about, and the cells it singles out. */
.ex-cell[data-unit="1"] {
    background: var(--bg-cell-peer);
}

.ex-cell[data-subject="1"] {
    background: var(--bg-cell-digit);
    box-shadow: inset 0 0 0 2px var(--focus);
}

.ex-cell[data-target="1"] {
    background: var(--bg-cell-selected);
    box-shadow: inset 0 0 0 3px var(--focus);
}

.ex-answer {
    color: var(--fg-user);
}

.ex-cands {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    inline-size: 100%;
    block-size: 100%;
    font-size: 0.625rem;
    font-weight: 400;
    color: var(--fg-candidate);
    line-height: 1;
}

.ex-cand {
    display: flex;
    align-items: center;
    justify-content: center;
}

.ex-cand[data-key="1"] {
    color: var(--fg-user);
    font-weight: 700;
}

.ex-cand[data-struck="1"] {
    color: var(--fg-conflict);
    background: var(--bg-cell-conflict);
    text-decoration: line-through;
    font-weight: 700;
}

.example figcaption {
    margin-block-start: 8px;
    color: var(--fg-candidate);
    font-size: 0.875rem;
    text-align: center;
}

.example-legend {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 4px 16px;
    margin: 8px 0 0;
    padding: 0 !important;
    list-style: none;
    font-size: 0.8125rem;
    color: var(--fg-candidate);
}

.example-legend li::before {
    content: "";
    display: inline-block;
    inline-size: 0.9em;
    block-size: 0.9em;
    margin-inline-end: 6px;
    vertical-align: -0.1em;
    border: 1px solid var(--line);
}

.example-legend .lg-unit::before { background: var(--bg-cell-peer); }
.example-legend .lg-subject::before { background: var(--bg-cell-digit); box-shadow: inset 0 0 0 2px var(--focus); }
.example-legend .lg-target::before { background: var(--bg-cell-selected); box-shadow: inset 0 0 0 2px var(--focus); }
.example-legend .lg-struck::before { background: var(--bg-cell-conflict); border-color: var(--fg-conflict); }

/* ------------------------------------------------------- the practice area */

.learn-practice {
    margin-block-start: 32px;
    padding-block-start: 8px;
    border-top: 1px solid var(--line);
}

.learn-app {
    /* A smaller board than the games use, so that on a laptop the question,
       the board and the digit pad fit one screen together. --board-width is
       derived from --board-raw at :root and inherited as a computed value, so
       redefining --board-raw alone here would change nothing -- both are set. */
    --board-raw: min(56dvh, 28rem, calc(100vw - 32px));
    --board-width: var(--board-raw);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    padding: 8px 0;
}

@supports (width: round(down, 10px, 3px)) {
    .learn-app {
        --board-width: calc(round(down, var(--board-raw) - 3px, 9px) + 3px);
    }
}

.learn-view {
    display: flex;
    flex-direction: column;
    gap: 12px;
    inline-size: min(100%, var(--board-width));
}

/* Wide screens put the controls beside the board rather than under it, which
   is what keeps the pad and the verdict on screen with the board. */
@media (min-width: 900px) {
    .learn-view {
        display: grid;
        grid-template-columns: var(--board-width) minmax(14rem, 18rem);
        grid-template-areas:
            "instruction instruction"
            "board controls"
            "board feedback";
        grid-template-rows: auto auto 1fr;
        align-items: start;
        gap: 12px 20px;
        inline-size: auto;
    }

    .learn-instruction { grid-area: instruction; }
    .learn-board-area { grid-area: board; }
    .learn-controls { grid-area: controls; }
    .learn-feedback { grid-area: feedback; }
}

.learn-instruction,
.learn-controls,
.learn-feedback {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* An element hidden by the view must stay hidden even where this sheet gives
   it a display value of its own -- .learn-digit-pad's grid used to win over
   [hidden], which left the digit pad on screen during pruning exercises. */
.learn-view [hidden] {
    display: none !important;
}

.learn-board-area {
    display: flex;
    justify-content: center;
    inline-size: 100%;
    /* chrome.css gives .board-area 8px of padding for the games' shell. Here it
       would sit on top of a board already sized to the column, and on a phone
       those 16px are what pushed the page wider than the screen. */
    padding: 0;
}

.learn-prompt,
.learn-record {
    margin: 0;
}

.learn-prompt {
    font-size: 0.9375rem;
}

.learn-record {
    color: var(--fg-candidate);
    font-size: 0.8125rem;
}

.learn-controls {
    align-items: stretch;
}

.learn-digit-prompt,
.learn-tally,
.learn-explanation {
    margin: 0;
    color: var(--fg-candidate);
    font-size: 0.8125rem;
}

.learn-digit-pad {
    display: grid;
    grid-template-columns: repeat(3, minmax(48px, 1fr));
    gap: 8px;
    inline-size: min(100%, 240px);
    align-self: center;
}

.learn-digit {
    aspect-ratio: 1;
    max-block-size: 64px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--bg-cell);
    color: var(--fg-body);
    font: inherit;
    font-size: 1.25rem;
    font-weight: 600;
    padding: 0;
    cursor: pointer;
}

.learn-digit:focus-visible {
    outline: 2px solid var(--focus);
    outline-offset: 1px;
}

.learn-digit[disabled] {
    opacity: 0.55;
    cursor: default;
}

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

.learn-hint {
    margin: 0;
    padding: 8px 10px;
    border-inline-start: 3px solid var(--focus);
    background: var(--bg-cell);
    font-size: 0.875rem;
}

.learn-result {
    margin: 0;
    font-size: 0.9375rem;
    font-weight: 600;
}

/* Prefixed with a mark as well as coloured, for the same reason the board never
   signals a conflict with colour alone. */
.learn-result[data-state="correct"] { color: var(--fg-user); }
.learn-result[data-state="retry"] { color: var(--fg-conflict); }
.learn-result[data-state="revealed"] { color: var(--fg-body); }

.learn-result[data-state="correct"]::before { content: "\2713\00a0"; }
.learn-result[data-state="retry"]::before { content: "\00d7\00a0"; }

.learn-actions {
    display: flex;
    gap: 8px;
}

.learn-submit,
.learn-hint-button,
.learn-actions button {
    padding: 8px 16px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--bg-cell);
    color: var(--fg-body);
    font: inherit;
    cursor: pointer;
}

.learn-submit:focus-visible,
.learn-hint-button:focus-visible,
.learn-actions button:focus-visible {
    outline: 2px solid var(--focus);
    outline-offset: 1px;
}

.learn-submit,
.learn-next {
    border-color: var(--focus) !important;
    border-width: 2px !important;
}

/* A candidate the player has marked for elimination. Three signals, of which
   colour is only one: the strike says the digit is going, the outline says the
   press landed here, and the ground separates it from its eight neighbours. */
.candidate[data-marked="1"] {
    color: var(--fg-conflict);
    background: var(--bg-cell-conflict);
    outline: 1px solid var(--fg-conflict);
    text-decoration: line-through;
    border-radius: 2px;
}

/* A mark judged wrong: a heavier ring, so it stands out from the marks that
   were right without relying on a second colour. */
.candidate[data-wrong="1"] {
    outline: 2px solid var(--fg-conflict);
    outline-offset: 1px;
    text-decoration: none;
}

@media (prefers-reduced-motion: no-preference) {
    .candidate { transition: background-color 120ms, color 120ms; }
}

/* The focus view: the board shows what the deduction rests on at full
   strength and dims the rest. Dimmed rather than hidden, so a candidate on
   screen can always be traced back to the digits that produced it.

   The rules mirror rush.css's focus view -- same selectors, same reasoning --
   but keyed off data-learn-focus rather than data-rush-focus. Sharing the
   attribute would tie two pages' board rendering together through a name that
   belongs to one of them, and the practice page loads no rush stylesheet. */
.board[data-learn-focus="1"] .cell:not([data-focus="1"]):not([tabindex="0"]) {
    background: var(--bg-page);
}

.board[data-learn-focus="1"] .cell:not([data-focus="1"]):not([tabindex="0"]) .cell-value,
.board[data-learn-focus="1"] .cell:not([data-focus="1"]):not([tabindex="0"]) .cell-candidates {
    opacity: 0.32;
}

/* What a hint points at, and the cell a wrong answer is explained by. An inset
   ring in each case, of two weights, so neither depends on colour alone. */
.cell[data-learn-hint="1"] {
    box-shadow: inset 0 0 0 2px var(--focus);
}

.cell[data-learn-reason="1"] {
    box-shadow: inset 0 0 0 3px var(--fg-conflict);
}

.cell[data-learn-reason="1"] .cell-value {
    opacity: 1 !important;
}

/* The cell being asked for. An inner ring rather than a tint: the cell is not
   wrong, it is the question, and it sits inside the selection outline the cell
   already carries so the two read as one mark. */
.cell[data-target="1"] {
    box-shadow: inset 0 0 0 3px var(--focus);
}

/* A placement exercise hides the target's own candidate list, because that
   list *is* the answer -- for a naked single it is literally the single digit
   being asked for. The evidence around it is what the deduction is supposed to
   be read from. Pruning exercises keep every candidate: there the marks are
   what the player is composing. */
.board[data-learn-focus="1"] .cell[data-target="1"] .cell-candidates {
    visibility: hidden;
}

/* ------------------------------------------------------- page navigation */

.learn-pager {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 8px;
    margin-block: 32px 8px;
}

.learn-pager a {
    display: inline-flex;
    align-items: center;
    min-block-size: var(--control-floor);
    padding: 0 14px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--bg-cell);
    color: var(--fg-body);
    text-decoration: none;
}

.learn-pager a:focus-visible {
    outline: 2px solid var(--focus);
    outline-offset: 2px;
}

.learn-pager .learn-pager-next {
    margin-inline-start: auto;
    border-color: var(--focus);
    border-width: 2px;
}

.learn-page + .site-footer {
    margin-block-start: 16px;
}
