/*
 * Shared design system for every player-facing page (puzzle, leaderboard,
 * signin, and any future game page). Palette tokens + generic components
 * live here; page-specific rules live in that page's own CSS file, loaded
 * after this one.
 */
:root {
    color-scheme: light;
    --bg: #f4f6fb;
    --card: #ffffff;
    --border: #dde2ea;
    --text: #1b2430;
    --muted: #6b7686;
    --accent: #2969c9;
    --accent-text: #ffffff;
    --error: #c53030;
    --error-bg: #fdecec;
    --success: #1a7a43;
    --success-bg: #e6f7ec;
    --shadow-sm: 0 1px 3px rgba(15, 23, 42, 0.06);
}

* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    background: var(--bg);
    color: var(--text);
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    -webkit-text-size-adjust: 100%;
}

h1 {
    font-size: 1.4rem;
    margin: 0;
}

.page {
    width: 100%;
    max-width: 480px;
    margin: 0 auto;
}

/* Grid, not flex: a 1fr/auto/1fr column template guarantees the two
   outer columns are equal width BY DEFINITION, independent of what
   content (if any) occupies them — unlike flex's space-between, which
   only centers the middle item if two sibling elements happen to
   compute to exactly the same width. That made puzzle.html's mistakes
   indicator (centered column) fragile whenever the left column's
   content (h1) was hidden and swapped for a differently-sized element.
   Each direct child claims its column explicitly below so this holds
   regardless of which children are actually visible via x-show. */
.page-header {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 0.25rem;
}
.page-header .brand { grid-column: 1; justify-self: start; }
.page-header .nav-link { grid-column: 3; justify-self: end; }

.brand {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}
.brand-logo {
    height: 2.1rem;
    width: auto;
    display: block;
}

.nav-link {
    color: var(--accent);
    font-size: 0.8rem;
    text-decoration: none;
    padding: 0.4rem 0.65rem;
    border: 1px solid var(--border);
    border-radius: 8px;
    white-space: nowrap;
}

.subtitle {
    color: var(--muted);
    margin: 0 0 1.25rem;
    font-size: 0.95rem;
}

.card {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 1.25rem;
    box-shadow: var(--shadow-sm);
}

.error-banner {
    background: var(--error-bg);
    color: var(--error);
    border-radius: 10px;
    padding: 0.75rem 0.9rem;
    font-size: 0.9rem;
    margin-bottom: 1rem;
}

.center-message {
    text-align: center;
    color: var(--muted);
    padding: 1.5rem 0;
}

button {
    font-family: inherit;
    cursor: pointer;
}

.btn-primary {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    min-height: 50px;
    margin-top: 1.25rem;
    background: var(--accent);
    color: var(--accent-text);
    border: none;
    border-radius: 10px;
    font-size: 1.05rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    text-decoration: none;
    text-align: center;
    line-height: 1.2;
}
.btn-primary:disabled { opacity: 0.6; }

.btn-secondary {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    min-height: 46px;
    margin-top: 0.6rem;
    background: transparent;
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 10px;
    font-size: 0.95rem;
    font-family: inherit;
    cursor: pointer;
    text-align: center;
}

input[type="text"],
input[type="email"],
input[type="tel"],
select {
    width: 100%;
    font-size: 1rem;
    padding: 0.75rem 0.85rem;
    border-radius: 10px;
    border: 1px solid var(--border);
    background: #eef1f6;
    color: var(--text);
    min-height: 48px;
    font-family: inherit;
}
input:focus, select:focus {
    outline: none;
    border-color: var(--accent);
}

.spinner {
    display: inline-block;
    width: 1rem;
    height: 1rem;
    border: 2px solid rgba(255, 255, 255, 0.4);
    border-top-color: #fff;
    border-radius: 50%;
    animation: spin 0.7s linear infinite;
    vertical-align: -2px;
    margin-right: 0.4rem;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Hand-drawn inline SVG icons share this sizing scale — the SVG markup
   itself stays inline per-page (small enough to copy into a future game),
   but every page draws from the same size/vertical-alignment convention. */
.icon {
    display: inline-block;
    width: 1em;
    height: 1em;
    vertical-align: -0.15em;
    flex-shrink: 0;
}
.icon-sm { font-size: 1.1rem; }
.icon-lg { font-size: 3rem; }

/* Shared tactile press feedback — any tappable control on any page opts in
   by adding this class, instead of every page maintaining its own :active
   selector list. */
.pressable { transition: transform 0.1s ease; }
.pressable:active { transform: scale(0.94); }

/* Generic 3-section app shell: fixed header, scrollable body, fixed
   footer. Not puzzle-specific — any future game page can opt in via
   class="app-shell" on <body> plus the .app-header/.app-body/.app-footer
   structure (each wrapping its content in the .page wrapper above). */
.app-shell {
    height: 100vh;
    height: 100dvh; /* browsers without dvh support simply ignore this line and keep the vh fallback above */
    overflow: hidden;
    display: flex;
    flex-direction: column;
}
.app-header,
.app-footer {
    flex: 0 0 auto;
    width: 100%;
    background: var(--card);
    box-shadow: var(--shadow-sm);
}
.app-header { border-bottom: 1px solid var(--border); }
.app-footer { border-top: 1px solid var(--border); min-height: 4.5rem; }
.app-header > .page { padding: 0.85rem 1rem; }
.app-body > .page { padding: 1rem; }
.app-footer > .page { padding: 0.75rem 1rem calc(0.75rem + env(safe-area-inset-bottom)); }
.app-body {
    flex: 1 1 auto;
    min-height: 0; /* without this, a flex child's default min-height:auto lets content push the column taller than the viewport instead of scrolling internally */
    overflow-y: auto;
    overflow-x: hidden;
    scrollbar-width: none; /* Firefox */
}
.app-body::-webkit-scrollbar { display: none; } /* Chromium/Safari/Android WebView */

/* Icon-only variant of .nav-link above — a compact circular icon button
   instead of a text pill, for header shortcuts (difficulty picker,
   puzzle.html's leaderboard link, leaderboard.html's puzzle link). */
.nav-link.icon-only {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    padding: 0;
    flex-shrink: 0;
}

/* Round, colorful "game HUD" badges — a coin/medal look (gradient fill +
   soft drop shadow + a glossy inner highlight) rather than the flat
   outline style everything else uses, since these sit in the persistent
   header and read better as playful shortcuts than as plain nav links.
   font-size bumps the icon itself up proportionally (the shared .icon
   rule sizes to 1em), since a 1.75rem-body-sized icon read too small
   floating inside a 2.5rem coin. Shared by puzzle.html and
   leaderboard.html — page-specific variants (.leaderboard-btn,
   .puzzle-btn) layer their own color/size on top of this base. */
.badge-btn {
    width: 2.5rem;
    height: 2.5rem;
    border: none;
    border-radius: 50%;
    color: #fff;
    font-size: 1.15rem;
    box-shadow: 0 3px 6px rgba(15, 23, 42, 0.22), inset 0 1px 0 rgba(255, 255, 255, 0.4);
    transition: background 0.25s ease;
}
/* The player's own difficulty-preference picker — same badge on both
   puzzle.html and leaderboard.html, colored by whichever tier is
   currently active. Plain blue is the pre-load fallback (before
   loadPreferredDifficulty()/loadDifficulty() resolves, or if it fails). */
.difficulty-btn {
    background: linear-gradient(155deg, #8fb3e8, #2969c9);
}
.difficulty-btn.tier-easy {
    background: linear-gradient(155deg, #6fd19a, #1a7a43);
}
.difficulty-btn.tier-medium {
    background: linear-gradient(155deg, #ffd166, #f4a300);
    color: #6b4400;
}
.difficulty-btn.tier-hard {
    background: linear-gradient(155deg, #ef8080, #c53030);
}

/* Solve-history shortcut (puzzle.html and leaderboard.html both link to
   historique.html) — the same purple as .tour-replay-btn (puzzle.css),
   reused here as this app's "secondary feature" accent so it reads as
   distinct from the gold "go to the other main page" badges above and
   from every difficulty tier color. No pulse/glow: unlike the
   page-to-page shortcuts, this isn't the primary next action. */
.history-btn {
    background: linear-gradient(155deg, #b79cf0, #7c5cff);
}

/* The "go to the other main page" gold pulsing badge — puzzle.html links
   to leaderboard, leaderboard.html links back to puzzle, and
   historique.html links to BOTH, so this lives here (shared by every
   page) rather than duplicated per-page as it used to be split between
   puzzle.css/leaderboard.css, one glow keyframe each under a different
   name for the exact same rule. */
.leaderboard-btn,
.puzzle-btn {
    width: 2.85rem;
    height: 2.85rem;
    font-size: 1.3rem;
    background: linear-gradient(155deg, #ffd166, #f4a300);
    color: #6b4400;
    animation: goldBadgeGlow 2.6s ease-in-out infinite;
}
@keyframes goldBadgeGlow {
    0%, 100% { box-shadow: 0 3px 6px rgba(15, 23, 42, 0.22), inset 0 1px 0 rgba(255, 255, 255, 0.4); }
    50% { box-shadow: 0 3px 6px rgba(15, 23, 42, 0.22), inset 0 1px 0 rgba(255, 255, 255, 0.4), 0 0 0 6px rgba(244, 163, 0, 0.22); }
}

/* Wraps the header's icon buttons (difficulty + the page-to-page shortcut)
   so they claim .page-header's right-hand grid track (see .page-header
   .nav-link above) as a single unit — the individual .nav-link children
   no longer sit directly in the grid, so their own grid-column:3 rule has
   no effect on them anymore; this wrapper is what actually claims column
   3 now. Shared by puzzle.html and leaderboard.html. */
.header-actions {
    grid-column: 3;
    justify-self: end;
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

/* Difficulty picker modal — shared by puzzle.html and leaderboard.html
   (both let the player change their difficulty preference from the
   header, see .difficulty-btn above). */
.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(15, 23, 42, 0.45);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    z-index: 60;
}
.modal-card {
    width: 100%;
    max-width: 340px;
}
.modal-title {
    font-size: 1.1rem;
    margin: 0 0 1rem;
    text-align: center;
}
.difficulty-options {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}
.difficulty-option {
    appearance: none;
    -webkit-appearance: none;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 48px;
    border-radius: 10px;
    border: 1px solid var(--border);
    background: #eef1f6;
    color: var(--text);
    font-family: inherit;
    font-size: 1rem;
    font-weight: 600;
    cursor: pointer;
}
.difficulty-option.active {
    border: 1.5px solid var(--accent);
    background: rgba(41, 105, 201, 0.14);
    color: var(--accent);
}
.modal-note {
    font-size: 0.8rem;
    color: var(--muted);
    text-align: center;
    margin: 1rem 0 0;
}

/* Tier-upgrade prompt's accept/dismiss row (puzzle.html) — .btn-primary/
   .btn-secondary default to full-width stacked blocks everywhere else;
   here they sit side by side instead, so their own width/margin-top are
   reset in favor of the flex row's own gap. */
.tier-upgrade-actions {
    display: flex;
    gap: 0.6rem;
    margin-top: 1.25rem;
}
.tier-upgrade-actions .btn-primary,
.tier-upgrade-actions .btn-secondary {
    width: auto;
    flex: 1;
    margin-top: 0;
}

@media (prefers-reduced-motion: reduce) {
    * {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        scroll-behavior: auto !important;
    }
}
