/* Solarized Color Scheme */
:root {
    /* --- Fixed Solarized palette (these hex values never change) --- */
    --sol-base03: #002b36;
    --sol-base02: #073642;
    --sol-base01: #586e75;
    --sol-base00: #657b83;
    --sol-base0:  #839496;
    --sol-base1:  #93a1a1;
    --sol-base2:  #eee8d5;
    --sol-base3:  #fdf6e3;
    --sol-yellow:  #b58900;
    --sol-orange:  #cb4b16;
    --sol-red:     #dc322f;
    --sol-magenta: #d33682;
    --sol-violet:  #6c71c4;
    --sol-blue:    #268bd2;
    --sol-cyan:    #2aa198;
    --sol-green:   #859900;

    /* --- Light mode: base tones map straight through --- */
    --base03: var(--sol-base03);
    --base02: var(--sol-base02);
    --base01: var(--sol-base01);
    --base00: var(--sol-base00);
    --base0:  var(--sol-base0);
    --base1:  var(--sol-base1);
    --base2:  var(--sol-base2);
    --base3:  var(--sol-base3);

    /* Accent colors are identical in both modes */
    --yellow:  var(--sol-yellow);
    --orange:  var(--sol-orange);
    --red:     var(--sol-red);
    --magenta: var(--sol-magenta);
    --violet:  var(--sol-violet);
    --blue:    var(--sol-blue);
    --cyan:    var(--sol-cyan);
    --green:   var(--sol-green);

    /* Semantic 'lilac' token. Maps to the Solarized violet so new UI (e.g. the
       letter-change marker) can reference a named lilac without inventing an
       off-palette hex. Violet is palette-constant across light and dark modes,
       so this resolves identically in both. Mirrors the existing precedent
       where the replay spinner already treats --violet as 'lilac'. */
    --lilac: var(--sol-violet);

    /* Word box sizing. --word-len is set by JS to the current puzzle's word
       length; the box width scales with it. Uses rem (root-relative) so the
       value resolves the same on every element, plus fixed padding so short
       words don't look cramped and long words still fit. */
    --word-len: 4;
    --word-width: calc(var(--word-len) * 1.4rem + 2.5rem);
    /* Space reserved on each side of a box for the delete icon */
    --delete-gutter: 2.5rem;
}

/* --- Dark mode: swap the base tones (same hex values, mirrored roles) ---
   Dark mode applies when the user explicitly toggles it (.dark-mode) OR when the
   OS prefers dark and the user has NOT explicitly forced light (.light-mode). */
:root.dark-mode {
    --base03: var(--sol-base3);
    --base02: var(--sol-base2);
    --base01: var(--sol-base1);
    --base00: var(--sol-base0);
    --base0:  var(--sol-base00);
    --base1:  var(--sol-base01);
    --base2:  var(--sol-base02);
    --base3:  var(--sol-base03);
}

@media (prefers-color-scheme: dark) {
    /* Follow the OS dark preference unless the user forced light or dark manually */
    :root:not(.light-mode):not(.dark-mode) {
        --base03: var(--sol-base3);
        --base02: var(--sol-base2);
        --base01: var(--sol-base1);
        --base00: var(--sol-base0);
        --base0:  var(--sol-base00);
        --base1:  var(--sol-base01);
        --base2:  var(--sol-base02);
        --base3:  var(--sol-base03);
    }
}

* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

a {
    color: var(--blue);
}

a:hover {
    color: var(--violet);
}


body {
    font-family: 'Atkinson Hyperlegible Next', sans-serif;
    background-color: var(--base2);
    color: var(--base00);
    min-height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    overflow: hidden;
}

#theme-toggle {
    position: fixed;
    top: 1rem;
    left: 1rem;
    background-color: var(--base3);
    color: var(--blue);
    border: 2px solid var(--blue);
    border-radius: 50%;
    width: 40px;
    height: 40px;
    font-size: 1.5rem;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.3s ease;
    z-index: 100;
}

#theme-toggle:hover {
    background-color: var(--blue);
    color: var(--base3);
}

#game-container {
    position: relative;
    width: 100%;
    max-width: 500px;
    height: 100vh;
    padding: 0rem 2rem;
    text-align: center;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

/* Tutorial Toggle Button - top right corner */
.tutorial-toggle {
    position: fixed;
    top: 1rem;
    right: 1rem;
    left: auto;
    background-color: var(--base3);
    color: var(--blue);
    border: 2px solid var(--blue);
    border-radius: 50%;
    width: 40px;
    height: 40px;
    font-size: 1.2rem;
    font-weight: bold;
    cursor: pointer;
    transition: all 0.3s ease;
    z-index: 100;
}

.tutorial-toggle:hover {
    background-color: var(--blue);
    color: var(--base3);
}

/* Words Container.
   A single scrollable column holding the above stack, the entry box, and the
   below stack in document order. The whole chain flows naturally and the
   container scrolls as one unit when it's taller than the available height, so
   there's never dead space between a short stack and the entry. The entry box
   is scrolled into view when the player starts typing (see game.js). */
#words-container {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.25rem;
    /* Leave room for the theme/tutorial buttons and the score/message area */
    max-height: calc(100vh - 8rem);
    width: 100%;
    margin-bottom: 1rem;
    overflow-y: auto;
    overflow-x: hidden;
}

/* Above stack: START at top, words chaining downward toward the entry. */
#word-above-stack {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;         /* START first, then chain words downward */
    align-items: center;
    gap: 0.25rem;
    width: calc(var(--word-width) + 2 * var(--delete-gutter));
}
#word-above-stack:empty {
    display: none;
}

/* Below stack: words chaining downward from the entry toward END at bottom. */
#word-below-stack {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.25rem;
    width: calc(var(--word-width) + 2 * var(--delete-gutter));
}
#word-below-stack:empty {
    display: none;
}

.word-item {
    width: var(--word-width);
    height: 60px;
    flex: 0 0 auto;          /* keep full size inside scrolling stacks */
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    background-color: var(--base3);
    border: 2px solid var(--base03);
    border-radius: 8px;
    font-size: 2rem;
    font-weight: bold;
    color: var(--base01);
    position: relative;
}

/* Word text is a grid of equal-width letter columns rather than a single run
   of text. flex-grow keeps it filling the full inner content box of .word-item
   (box width minus the 1rem side padding), and repeat(var(--word-len), 1fr)
   splits that width into word-len identical columns. Each letter therefore sits
   in a predictable 1/word-len fraction of the box, independent of font metrics,
   which lets the letter-change marker line up exactly on the column that
   changed. --word-len is set by JS (setWordLength) before words render. */
.word-item .word-text {
    flex-grow: 1;
    display: grid;
    grid-template-columns: repeat(var(--word-len), 1fr);
    justify-items: center;
    align-items: center;
    text-align: center;
    white-space: nowrap;
}

/* One cell per letter. Centered inside its grid column and kept at the same
   bold word look as before so the visual size is unchanged. The play words use
   the monospace cut of Atkinson Hyperlegible so each glyph is the same advance
   width and is centered within its equal-width grid column; this keeps a wide
   W and a narrow I aligned so the change markers point at the true column
   center. Only the play words use mono; the rest of the UI stays in Next. */
.letter-cell {
    text-align: center;
    font-weight: bold;
    line-height: 1;
    font-family: 'Atkinson Hyperlegible Mono', monospace;
}

/* Lilac marker (U+296E) shown on the seam between two vertically adjacent
   words, pointing at the single letter column that changed between them.
   It is an absolutely-positioned child of the UPPER box of the pair.

   Horizontal: --marker-col is the 0-based changed column (set in JS). The grid
   of letters fills the inner content box, which is the box width minus the
   1rem side padding of .word-item, so the inner width is (100% - 2rem). The
   center of column c sits at ((c + 0.5) / word-len) of that inner width, and
   the grid starts 1rem in from the left edge, so:
       left = 1rem + ((col + 0.5) / word-len) * (100% - 2rem)
   translateX(-50%) then centers the glyph on that point so it lines up with
   the actual letter cell rather than the padded box.

   Vertical: the glyph is anchored a fixed 0.3rem below the upper box's bottom
   edge (bottom: -0.3rem) and pulled up/down by half its own height with
   translateY(50%), so it sits slightly lower on the seam and overlaps both the
   upper box's bottom edge and the lower box's top edge across the gap.

   z-index keeps it above the box borders; pointer-events:none ensures it never
   intercepts clicks meant for the delete icon or the entry input. --lilac is
   palette-constant across light and dark modes, so it reads the same in both. */
.change-marker {
    position: absolute;
    bottom: -0.4rem;
    left: calc(1rem + (var(--marker-col) + 0.5) / var(--word-len) * (100% - 2rem));
    transform: translate(-50%, 50%) scale(0.6, 1.2);
    font-size: 2rem;
    line-height: 1;
    color: var(--lilac);
    pointer-events: none;
    z-index: 10;
}

.word-item .word-delete-icon {
    position: absolute;
    top: 0;
    right: -2rem;
    bottom: 0;
    width: 2rem;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.25rem;
    color: var(--red);
    transition: all 0.2s ease;
    border-radius: 8px;
}

.word-item .word-delete-icon:hover {
    background-color: var(--red);
    color: var(--base3);
}

/* Non-interactive delete icon (shown during the tutorial for illustration) */
.word-item .word-delete-icon.disabled {
    cursor: default;
}

.word-item .word-delete-icon.disabled:hover {
    background-color: transparent;
    color: var(--red);
}

/* Brief highlight used when the tutorial demonstrates a delete */
.word-item .word-delete-icon.activating {
    background-color: var(--red);
    color: var(--base3);
    transform: scale(1.25);
}

/* Entry Container - fixed height, never shrinks, so it stays on screen between
   the two flexible/scrolling stacks. */
#word-entry-container {
    width: 100%;
    display: flex;
    justify-content: center;
    flex: 0 0 auto;
}

/* When hidden on chain completion, collapse it entirely so stacks meet seamlessly */
#word-entry-container.hidden {
    display: none !important;
}

/* Wrapper so the real-time feedback label can overlay the top of the input. */
#word-entry-box {
    position: relative;
    width: var(--word-width);
}

/* Spinner shown to the right of the entry box while a saved game is replayed,
   in the same horizontal space (right: -2rem; width: 2rem) the delete ✕ uses on
   word items. Lilac (Solarized violet); the glyph takes the text color (not a
   colorful emoji) and rotates continuously. */
#word-entry-box.replaying::after {
    content: '\2689';
    position: absolute;
    top: 0;
    right: -2rem;
    bottom: 0;
    width: 2rem;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 2rem;
    color: var(--violet);
    pointer-events: none;
    animation: replay-spin 1.2s linear infinite;
}

@keyframes replay-spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}

/* Real-time feedback label, centered at the top of the input box. Hidden until
   there's a message. */
#word-entry-error {
    position: absolute;
    top: 0.35rem;
    left: 0;
    right: 0;
    text-align: center;
    font-size: 0.8rem;
    text-transform: uppercase;
    color: var(--orange);
    pointer-events: none;
    line-height: 1;
}
#word-entry-error:empty {
    display: none;
}

#word-entry {
    width: 100%;
    padding: 1rem;
    font-size: 1.5rem;
    text-align: center;
    text-transform: uppercase;
    border: 2px solid var(--base03);
    background-color: var(--base3);
    color: var(--base00);
    border-radius: 8px;
    /* The entry is where a play word is composed, so match the stacked words'
       monospace cut; all other UI chrome stays in Atkinson Hyperlegible Next. */
    font-family: 'Atkinson Hyperlegible Mono', monospace;
    outline: none;
    transition: all 0.3s ease;
}

/* When a feedback message is shown, nudge the input text down to make room. */
#word-entry-box.has-message #word-entry {
    padding-top: 1.5rem;
    padding-bottom: 0.5rem;
}

#word-entry:focus {
    border-color: var(--blue);
}

#word-entry:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    border-color: var(--red);
}

/* Live validation states */
#word-entry.valid {
    color: var(--green);
    border-color: var(--green);
}

#word-entry.error {
    border-color: var(--red);
    background-color: var(--base3);
}

/* An invalid live-entry colors the typed word red. */
#word-entry.invalid {
    color: var(--red);
}

#word-entry.shake {
    animation: shake 0.2s ease-in-out 5;
}

@keyframes shake {
    0%, 100% { transform: translateX(0); }
    25% { transform: translateX(-10px); }
    75% { transform: translateX(10px); }
}

/* Honor reduced-motion: drop the invalid-word shake (the red border still
   signals the error). Confetti is suppressed in JS. */
@media (prefers-reduced-motion: reduce) {
    #word-entry.shake {
        animation: none;
    }
}

/* Message Area */
#message-area {
    min-height: 1.5rem;
    font-size: 1.2rem;
    font-weight: bold;
    margin-bottom: 1rem;
}

#message-area.error {
    color: var(--red);
}

/* Chain complete message - made bigger */
#message-area.success {
    color: var(--green);
    font-size: 2.5rem;
    min-height: auto;
    margin-bottom: 0.5rem;
}

/* Score line (shown under the completion message) */
#score-line {
    text-align: center;
}

#score-line.hidden {
    display: none !important;
}

#score-text {
    font-size: 2rem;
    font-weight: bold;
    color: var(--base00);
    margin-bottom: 1rem;
}

#score-line button {
    background-color: var(--green);
    color: var(--base3);
    border: none;
    padding: 1rem 2rem;
    font-size: 1.2rem;
    font-weight: bold;
    border-radius: 8px;
    cursor: pointer;
    transition: all 0.3s ease;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.15rem;
    margin: 0 auto;
}

#score-line button:hover {
    background-color: var(--green);
    opacity: 0.8;
}

/* Primary button label */
#score-line button .btn-label {
    font-size: 1.2rem;
    font-weight: bold;
}

/* Secondary line: the next puzzle name, smaller */
#score-line button .btn-sub {
    font-size: 0.8rem;
    font-weight: normal;
    opacity: 0.85;
}

/* "No more puzzles" message shown when there is no next game */
#no-more-puzzles {
    font-size: 1.2rem;
    font-weight: bold;
    color: var(--base00);
}

#no-more-puzzles.hidden {
    display: none !important;
}

.hidden {
    display: none !important;
}

/* Tutorial Overlay - positioned at top so it does NOT cover the puzzle */
.overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    z-index: 1000;
    display: flex;
    justify-content: center;
    align-items: flex-start;
    pointer-events: none;
}

.tutorial-content {
    background-color: var(--base3);
    padding: 0.75rem 2.5rem 0.75rem 1rem;
    border-radius: 0 0 16px 16px;
    width: 95%;
    color: var(--base00);
    border: 2px solid var(--base03);
    border-top: none;
    position: relative;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
    pointer-events: auto;
}

.close-btn {
    position: absolute;
    top: 0.25rem;
    right: 0.5rem;
    background: none;
    border: none;
    font-size: 2.25rem;
    line-height: 1;
    cursor: pointer;
    color: var(--base0);
    transition: all 0.2s ease;
}

.close-btn:hover {
    color: var(--red);
    transform: scale(1.2);
}

/* Tutorial body: prev arrow | text | next arrow */
.tutorial-body {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding-top: 0.5rem;
}

#tutorial-steps {
    flex-grow: 1;
}

.tutorial-step p {
    margin: 0;
    line-height: 1.4;
    font-size: 1.5rem;
    color: var(--base01);
}

/* Space stacked paragraphs (e.g. the intro card has two). */
.tutorial-step p + p {
    margin-top: 0.75rem;
}

/* The ✕ called out in the tutorial text, shown in the delete-icon's red. */
.tutorial-step .x-mark {
    color: var(--red);
    font-weight: bold;
}

.nav-arrow {
    background: none;
    border: none;
    color: var(--blue);
    font-size: 3.5rem;
    line-height: 1;
    cursor: pointer;
    padding: 0 0.5rem;
    transition: all 0.2s ease;
    flex-shrink: 0;
}

.nav-arrow:hover {
    color: var(--base03);
    transform: scale(1.2);
}

.nav-arrow.hidden {
    visibility: hidden;
    display: inline-block !important;
}

/* Confetti Canvas */
#confetti-canvas {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    z-index: 999;
}

/* Confetti Fade Overlay */
#confetti-fade-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: var(--base2);
    z-index: 998;
    transition: opacity 0.2s ease;
}


/* ---- Info modal (opened by the ? button) ---- */
/* A full-screen panel holding the title/about blurb, a tutorial-launch button,
   the current puzzle info, and the credits. Replaces the old always-visible
   bottom footers, which the mobile keyboard kept shoving over the board. */
.info-modal {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 1rem;
    background-color: rgba(0, 0, 0, 0.5);
    overflow-y: auto;
}

.info-modal.hidden {
    display: none !important;
}

.info-content {
    position: relative;
    background-color: var(--base3);
    color: var(--base00);
    border: 2px solid var(--base03);
    border-radius: 16px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
    width: 100%;
    max-width: 32rem;
    max-height: 100%;
    overflow-y: auto;
    padding: 2rem 1.75rem 1.5rem;
    text-align: center;
}

.info-title {
    margin: 0 0 1rem;
    font-size: 2.25rem;
    color: var(--blue);
}

.info-content p {
    margin: 0 0 0.9rem;
    line-height: 1.45;
    font-size: 1.1rem;
    color: var(--base01);
}

.info-tutorial-btn {
    display: inline-block;
    margin: 0.5rem auto 1.5rem;
    padding: 0.75rem 1.5rem;
    font-family: inherit;
    font-size: 1.15rem;
    color: var(--base3);
    background-color: var(--blue);
    border: none;
    border-radius: 10px;
    cursor: pointer;
    transition: all 0.2s ease;
}

.info-tutorial-btn:hover {
    background-color: var(--violet);
    transform: scale(1.03);
}

.info-puzzle {
    margin: 0 0 1.25rem;
    font-size: 0.95rem;
    color: var(--base0);
    user-select: none;
}

.info-puzzle:empty {
    display: none;
}

.info-credits {
    font-size: 0.85rem;
    line-height: 1.5;
    color: var(--base0);
    border-top: 1px solid var(--base1);
    padding-top: 1rem;
}


/* Narrow screens (phones): shrink the whole app by 20%. */
@media (max-width: 640px) {
    html {
        font-size: 80%;
    }
}
