/* Base Styles — warm parchment ground with a deep burgundy accent ("Burgundy
   Editorial" direction). Neutrals are warm-biased toward the accent rather
   than a plain gray scale. */
:root {
    --bg-page: #f9f4ef;
    --bg-surface: #fffdfb;
    --bg-surface-alt: #f3ece3;
    --border: #e6dcd0;
    --border-strong: #cdbca8;
    --text-primary: #1f1512;
    --text-secondary: #5c4b43;
    --text-muted: #93817a;
    --accent: #7a2b3f;
    --accent-light: #9c3d54;
    --accent-dark: #571d2c;
    --accent-tint: #f6e9ec;
    --accent-gradient: linear-gradient(135deg, var(--accent-light), var(--accent));
    --accent-gradient-hover: linear-gradient(135deg, var(--accent), var(--accent-dark));
    --radius-lg: 0px;
    --radius-md: 0px;
    --radius-sm: 0px;
    --shadow-sm: 0 2px 12px rgba(31, 21, 18, 0.07);
    --shadow-md: 0 14px 34px rgba(122, 43, 63, 0.18);

    --font-display: 'Fraunces', Georgia, serif;
    --font-body: 'IBM Plex Sans', -apple-system, sans-serif;

    /* Shared easing curves — a snappy "pop" for anything that lifts/grows on
       hover or entrance, a softer settle for fades/reveals — replacing the
       generic `ease` used throughout so motion reads intentional rather
       than default. */
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    --ease-pop: cubic-bezier(0.22, 1, 0.36, 1);

    /* JLPT level spectrum — an ordinal "difficulty warmth" progression
       (N5 cool/calm -> N1 deep wine, echoing the site's own accent at the
       hardest level) rather than five arbitrary hues, so the color itself
       tells you where a level sits. Validated with the dataviz skill's
       palette checker against this page's surface (#f9f4ef): passes the
       lightness band, chroma floor, and CVD-separation checks for every
       adjacent pair except N1<->N2 (ΔE 8.2 simulated / 8.2 normal-vision,
       short of the 15 floor) — accepted because every place these colors
       appear also carries an explicit "N5"..."N1" text label, so color is
       never the only way to tell two levels apart.
       Each also gets a light tint for card/badge backgrounds. */
    --jlpt-n5: #1f8f6b;
    --jlpt-n5-tint: #e7f3ee;
    --jlpt-n4: #d1a01f;
    --jlpt-n4-tint: #faf1de;
    --jlpt-n3: #c85a1f;
    --jlpt-n3-tint: #f9ece1;
    --jlpt-n2: #9c3520;
    --jlpt-n2-tint: #f6e5df;
    --jlpt-n1: #82304a;
    --jlpt-n1-tint: #f4e5ea;
}

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

html {
    scroll-behavior: smooth;
}

/* 64px header height + 30px to offset the scroll-reveal animation's translateY(30px) in
   script.js: an off-screen section is still in that pre-reveal, shifted-down state at the
   moment a nav link is clicked, so the browser's scroll target needs the extra headroom.
   (Was 148px when the masthead was two rows tall.) */
section[id] {
    scroll-margin-top: 94px;
}

.hidden {
    display: none !important;
}

/* Visually hidden but still reachable by screen readers -- unlike .hidden (display:none, which
   removes an element from the accessibility tree too), this keeps content announced while
   taking it out of the visual layout. Used for section headings that exist purely to fix a
   heading-level skip (H1 straight to H3, with no visible H2 the design calls for) without
   introducing a redundant visible label. */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

body {
    margin: 0;
    min-height: 100vh;
    background: var(--bg-page);
    font-family: var(--font-body);
    color: var(--text-primary);
    overflow-x: hidden;
    position: relative;
}

/* Display face for headline-weight text — a warm, characterful serif in
   place of running the whole site through one workhorse sans, used with
   restraint on names/section titles/big numbers rather than everywhere. */
.main-name,
.section-title h2,
.stat-number {
    font-family: var(--font-display);
}

.container {
    max-width: 1200px;
    margin: 0 auto;
    position: relative;
    z-index: 2;
}

/* Animated Background - Minimal Shapes */
.background-animation {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 1;
    overflow: hidden;
}

.floating-shape {
    position: absolute;
    opacity: 0.4;
    animation: float 30s infinite linear;
    border: 1px solid rgba(122, 43, 63, 0.18);
}

.shape-1 {
    width: 200px;
    height: 200px;
    background: transparent;
    border-radius: 0px;
    top: 20%;
    left: 10%;
    animation-delay: 0s;
}

.shape-2 {
    width: 150px;
    height: 150px;
    background: transparent;
    border-radius: 0px;
    top: 60%;
    right: 20%;
    animation-delay: 10s;
}

.shape-3 {
    width: 100px;
    height: 100px;
    background: transparent;
    border-radius: 0px;
    top: 40%;
    right: 10%;
    animation-delay: 20s;
}

.shape-4 {
    width: 120px;
    height: 120px;
    background: transparent;
    border-radius: 0px;
    bottom: 30%;
    left: 20%;
    animation-delay: 15s;
}

@keyframes float {
    0%, 100% {
        transform: translateY(0) rotate(0deg);
    }
    50% {
        transform: translateY(-40px) rotate(180deg);
    }
}

/* ---------------------------------------------------------------------
   Masthead + footer chrome tokens.

   "Lifted wine": the previous --header-bg (#1c0f16) was so near-black that on the site's
   light-themed pages it read as a heavy lid clamped over the page rather than a masthead.
   These values lift it into an actual plum while keeping the same wine-and-gold identity.

   The block is declared on .site-header-wrap AND .site-footer together — rather than in
   :root, or duplicated onto each — so header and footer are literally the same palette and
   can never drift apart: the page ends up bookended by one chrome color. Keeping it off
   :root also means a per-page theme block (portfolio/reading/phonetics/game) can never
   accidentally shadow these, which is the whole point of the chrome having its own tokens
   rather than reusing the page's --accent/--bg-surface.
   --------------------------------------------------------------------- */
.site-header-wrap,
.site-footer {
    --header-bg: #4a2c3a;
    --header-bg-elevated: #5c3a49;
    --header-border: rgba(232, 189, 109, 0.32);
    --header-text: #f9efe3;
    --header-text-muted: #d3b9ab;
    --header-accent: #e8bd6d;
    --header-accent-dark: #c99a45;
    --header-accent-tint: rgba(232, 189, 109, 0.16);
}

/* Header: one fixed row — brand at the far left, section nav in the middle, account menu
   pinned right. It replaces the old two-row masthead (a five-cell nav row whose items each
   stretched to a fifth of the viewport, plus a separate login bar underneath holding a
   "back to Portfolio" link and the account menu), which cost 115px of permanent chrome.
   One row is ~64px, so the pages below it get 50px of their own space back. */
.site-header-wrap {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 1000;
    transition: box-shadow 0.3s var(--ease-out);
}

.header {
    display: flex;
    align-items: stretch;
    gap: 20px;
    min-height: 64px;
    padding: 0 40px;
    background: var(--header-bg);
    border-bottom: 1px solid var(--header-border);
}

/* Brand: gold seal chip carrying 言 — the first character of 言葉合わせ, the word game's
   Japanese name — plus the name and a role line. The whole block is one link home, which
   is what the old login bar's "← Portfolio" back-link used to do on its own row. */
.site-brand {
    display: flex;
    align-items: center;
    align-self: center;
    gap: 12px;
    flex: 0 0 auto;
    padding: 5px 4px;
    margin-left: -4px;
    text-decoration: none;
    color: var(--header-text);
}

.brand-seal {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    background: linear-gradient(150deg, var(--header-accent), var(--header-accent-dark));
    color: var(--header-bg);
    font-size: 1.15rem;
    font-weight: 700;
    line-height: 1;
    transition: box-shadow 0.2s var(--ease-out);
}

.brand-seal img {
    width: 88%;
    height: 88%;
    object-fit: contain;
    display: block;
}

.site-brand:hover .brand-seal {
    box-shadow: 0 0 0 3px var(--header-accent-tint);
}

.brand-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.brand-name {
    font-family: var(--font-display);
    font-size: 0.98rem;
    font-weight: 600;
    line-height: 1.15;
    white-space: nowrap;
    transition: color 0.2s ease;
}

.site-brand:hover .brand-name {
    color: var(--header-accent);
}

.brand-role {
    font-size: 0.58rem;
    font-weight: 600;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--header-text-muted);
    line-height: 1.15;
    white-space: nowrap;
}

/* Nav items now size to their own labels and sit centered in the space between brand and
   account, instead of each stretching to a fifth of the bar. */
.header-nav {
    display: flex;
    align-items: stretch;
    gap: 2px;
    margin: 0 auto;
    min-width: 0;
}

.nav-item {
    position: relative;
    display: flex;
}

.nav-trigger {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    padding: 0 14px;
    font-family: inherit;
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--header-text);
    cursor: pointer;
    text-decoration: none;
    white-space: nowrap;
    transition: color 0.2s var(--ease-out), background 0.2s var(--ease-out), border-color 0.2s var(--ease-out);
}

.nav-trigger:hover {
    background: var(--header-accent-tint);
    color: var(--header-accent);
}

/* Caret appears only on the two items that actually own a dropdown, so the affordance is
   visible rather than something you have to discover by hovering. */
.nav-caret {
    font-size: 0.6rem;
    line-height: 1;
    opacity: 0.75;
    transition: transform 0.2s var(--ease-out);
}

.nav-item:hover .nav-caret,
.nav-item:focus-within .nav-caret {
    transform: translateY(2px);
}

/* Marks the nav item for the page currently open (set directly in each page's own header
   markup). A gold rule along the bottom edge of the bar now that the trigger fills the
   header's full height, instead of the old inset box-shadow. */
.nav-current {
    background: var(--header-accent-tint);
    color: var(--header-accent);
    border-bottom-color: var(--header-accent);
}

/* Keyboard focus has to stay visible on a dark ground, and the dropdowns open on :focus-within
   as well as :hover, so tabbing through the bar is a real path. */
.site-brand:focus-visible,
.nav-trigger:focus-visible,
.nav-dropdown a:focus-visible,
.account-menu-trigger:focus-visible,
.account-menu-panel button:focus-visible,
.account-menu-panel a:focus-visible,
.site-footer a:focus-visible {
    outline: 2px solid var(--header-accent);
    outline-offset: -2px;
}

.nav-dropdown {
    position: absolute;
    top: 100%;
    left: 0;
    min-width: 220px;
    background: var(--header-bg-elevated);
    border: 1px solid var(--header-border);
    padding: 10px 0;
    opacity: 0;
    transform: translateY(-8px);
    pointer-events: none;
    box-shadow: 0 16px 34px rgba(0, 0, 0, 0.4);
    transition: all 0.3s var(--ease-out);
    z-index: 10;
}

.nav-item:hover .nav-dropdown,
.nav-item:focus-within .nav-dropdown {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}

.nav-dropdown a {
    display: block;
    padding: 12px 20px;
    color: var(--header-text);
    text-decoration: none;
    font-size: 0.9rem;
    border-left: 2px solid transparent;
    transition: all 0.2s var(--ease-out);
}

.nav-dropdown a:hover {
    background: var(--header-accent-tint);
    border-left: 2px solid var(--header-accent);
    color: var(--header-accent);
}

/* (.login-bar / .back-link / .nav-placeholder are gone: the login bar's second row was folded
   into the single header row, its back-link replaced by the brand block, and the empty
   "Section 5 -> Coming soon" nav item removed rather than shipping a visible placeholder.) */

/* ---------------------------------------------------------------------
   Account menu — a single compact avatar/icon trigger in the top-right
   that expands into a small dropdown panel (guest: a login prompt;
   signed in: email + account settings + log out), replacing the old
   bare inline Log In / email-and-Log-Out pair.
   --------------------------------------------------------------------- */
/* Now pinned to the right of the single header row (it used to sit in the second "login bar"
   row underneath the nav). */
/* No margin-left:auto here — .header-nav's own `margin: 0 auto` already eats all the free
   space on both sides, which centers the nav between brand and account and pushes this to
   the far right. A second auto margin would split that free space three ways instead. */
.account-menu {
    position: relative;
    flex: 0 0 auto;
    align-self: center;
}

.account-menu-trigger {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    border: 1px solid var(--header-border);
    background: var(--header-bg-elevated);
    color: var(--header-accent);
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1rem;
    cursor: pointer;
    transition: border-color 0.2s ease, transform 0.2s var(--ease-pop), box-shadow 0.2s ease;
}

.account-menu-trigger:hover,
.account-menu.open .account-menu-trigger {
    border-color: var(--header-accent);
    box-shadow: 0 0 0 3px var(--header-accent-tint);
}

.account-menu-trigger svg {
    width: 18px;
    height: 18px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.8;
}

.account-menu-scrim {
    position: fixed;
    inset: 0;
    background: rgba(20, 12, 10, 0.45);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.25s var(--ease-out);
    z-index: 999;
}

.account-menu.open .account-menu-scrim {
    opacity: 1;
    pointer-events: auto;
}

/* A side panel fixed to the viewport edge -- not the trigger button -- so it spans the full
   height regardless of scroll position, wide enough to hold real navigation (Dashboard /
   Account details / Settings) instead of the small dropdown this used to be, which only had
   room for the language toggle and Log Out. */
.account-menu-panel {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    width: 320px;
    max-width: 86vw;
    background: var(--header-bg-elevated);
    border-left: 1px solid var(--header-border);
    box-shadow: -24px 0 50px rgba(0, 0, 0, 0.4);
    display: flex;
    flex-direction: column;
    padding: 76px 22px 22px;
    overflow-y: auto;
    transform: translateX(100%);
    pointer-events: none;
    transition: transform 0.32s var(--ease-pop);
    z-index: 1000;
}

.account-menu.open .account-menu-panel {
    transform: translateX(0);
    pointer-events: auto;
}

.account-menu-note {
    margin: 0 0 12px;
    font-size: 0.85rem;
    color: var(--header-text-muted);
    line-height: 1.5;
}

.account-menu-label {
    margin: 0 0 4px;
    font-size: 0.7rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--header-text-muted);
}

#auth-anon .account-menu-cta {
    width: 100%;
    text-align: center;
}

/* The account panel hangs off the masthead, so its CTA should wear the masthead's gold, not
   the page's. .auth-btn paints var(--accent-gradient), and every page-theme block redefines
   that token on body -- so the identical button came out blue on the portfolio and copper on
   Phonetics Family, which undercut the idea of one consistent bar. Scoped to the panel alone:
   .auth-btn inside #auth-modal / #account-details-modal / #account-settings-modal is page-level
   UI and keeps the page accent. Dark wine on gold rather than the base rule's white, which would
   sit at ~1.9:1 here. Qualified by .site-header-wrap purely for specificity: reading.css sets
   its own body:has(.reading-main) .auth-btn colour (0,2,1) as part of that page's light flip,
   which would otherwise outrank a bare .account-menu-panel .auth-btn (0,2,0) and leave the
   reader page's panel button a different ink from the other pages. */
.site-header-wrap .account-menu-panel .auth-btn {
    background: linear-gradient(135deg, var(--header-accent), var(--header-accent-dark));
    border-color: var(--header-accent-dark);
    color: var(--header-bg);
}

.site-header-wrap .account-menu-panel .auth-btn:hover {
    background: linear-gradient(135deg, var(--header-accent-dark), var(--header-accent));
    border-color: var(--header-accent);
    color: var(--header-bg);
}

#auth-authed {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    flex: 1;
}

.account-menu-profile {
    display: flex;
    align-items: center;
    gap: 12px;
    padding-bottom: 18px;
    margin-bottom: 8px;
    border-bottom: 1px solid var(--header-border);
}

.account-menu-profile-avatar {
    flex: 0 0 auto;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: linear-gradient(150deg, var(--header-accent), var(--header-accent-dark));
    color: var(--header-bg);
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1rem;
    display: flex;
    align-items: center;
    justify-content: center;
}

.account-menu-profile-text {
    min-width: 0;
}

.auth-user-email {
    display: block;
    font-size: 0.88rem;
    font-weight: 600;
    color: var(--header-text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    margin: 0;
}

.account-menu-nav {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin-bottom: 10px;
}

.account-menu-nav-item {
    display: flex;
    align-items: center;
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    color: var(--header-text);
    font-family: inherit;
    font-size: 0.9rem;
    font-weight: 600;
    padding: 11px 10px;
    cursor: pointer;
    text-decoration: none;
    transition: background 0.15s ease, color 0.15s ease;
}

.account-menu-nav-item::after {
    content: '\203a';
    margin-left: auto;
    opacity: 0.5;
    font-size: 1rem;
}

.account-menu-nav-item:hover {
    background: var(--header-accent-tint);
    color: var(--header-accent);
}

.account-menu-logout {
    display: block;
    width: 100%;
    text-align: left;
    background: none;
    border: none;
    border-top: 1px solid var(--header-border);
    margin-top: auto;
    padding: 16px 10px 0;
    color: var(--header-text-muted);
    font-weight: 600;
    font-size: 0.88rem;
    cursor: pointer;
    transition: color 0.2s ease;
}

.account-menu-logout:hover {
    color: var(--header-accent);
}

/* Settings modal's language toggle: same .lang-toggle-btn markup as before, but now living
   inside a page-level modal (a sibling of .site-header-wrap, not a descendant) instead of the
   header-scoped account panel -- the base rule's --header-* tokens don't cascade there, so this
   overrides with the page's own tokens instead. Higher specificity than the base rule wins
   regardless of source order. */
.settings-lang-row {
    margin: 0 0 24px;
    padding-bottom: 20px;
    border-bottom: 1px solid var(--border);
}

.settings-lang-row .lang-toggle-btn {
    border-color: var(--border-strong);
    color: var(--text-secondary);
}

.settings-lang-row .lang-toggle-btn:hover {
    border-color: var(--accent);
    color: var(--text-primary);
}

.settings-lang-row .lang-toggle-btn.active {
    background: var(--accent);
    border-color: var(--accent);
    color: #ffffff;
}

.lang-toggle {
    display: flex;
    gap: 4px;
}

.lang-toggle-btn {
    flex: 1;
    background: none;
    border: 1px solid var(--header-border);
    color: var(--header-text-muted);
    padding: 6px 0;
    font-size: 0.8rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}

.lang-toggle-btn:hover {
    border-color: var(--header-accent);
    color: var(--header-text);
}

.lang-toggle-btn.active {
    background: var(--header-accent);
    border-color: var(--header-accent);
    color: var(--header-bg);
    cursor: default;
}

.modal-label {
    margin: 0 0 4px;
    font-size: 0.7rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.auth-btn {
    display: inline-block;
    padding: 10px 20px;
    background: var(--accent-gradient);
    border: 1px solid var(--accent);
    border-radius: var(--radius-sm);
    color: #ffffff;
    font-weight: 600;
    font-size: 0.95rem;
    cursor: pointer;
    box-shadow: var(--shadow-sm);
    transition: all 0.3s var(--ease-out);
}

.auth-btn:hover {
    background: var(--accent-gradient-hover);
    border-color: var(--accent-dark);
    transform: translateY(-1px);
    box-shadow: var(--shadow-md);
}

.auth-btn-outline {
    background: transparent;
    color: var(--accent);
}

/* Rectangle with the left edge cut on a diagonal: long side on top, short side on bottom */
.auth-btn-cut {
    padding-left: 28px;
    clip-path: polygon(0 0, 100% 0, 100% 100%, 16px 100%);
}

.auth-btn-outline:hover {
    background: var(--accent-gradient);
    color: #ffffff;
}

/* Auth modal */
.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(20, 20, 43, 0.45);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 2000;
    padding: 20px;
}

.modal-card {
    position: relative;
    width: 100%;
    max-width: 400px;
    background: var(--bg-surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    padding: 40px 30px 30px;
}

.modal-close {
    position: absolute;
    top: 4px;
    right: 8px;
    background: none;
    border: none;
    font-size: 1.5rem;
    line-height: 1;
    color: var(--text-muted);
    cursor: pointer;
    width: 44px;
    height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.modal-card h3 {
    margin: 0 0 20px 0;
    color: var(--text-primary);
    font-size: 1.5rem;
}

#auth-form {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

#auth-form label {
    font-size: 0.85rem;
    color: var(--text-secondary);
    margin-top: 8px;
}

#auth-form input {
    padding: 10px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    font-family: inherit;
    font-size: 1rem;
    color: var(--text-primary);
}

#auth-form input:focus {
    outline: none;
    border-color: var(--accent);
}

#auth-form .auth-btn {
    margin-top: 16px;
    text-align: center;
}

.auth-error {
    color: #d33f3f;
    font-size: 0.9rem;
    margin: 4px 0 0 0;
}

/* Deliberately NOT var(--accent-dark): the site palette is wine, so on most pages that
   token is #571d2c and renders the *success* state in a colour indistinguishable from the
   error red four lines above. A successful password-reset request read as a failure for as
   long as it took to notice. Success needs a hue the error state can never take. */
.auth-error.auth-info {
    color: #1a7f4b;
}

.auth-forgot-link {
    align-self: flex-end;
    background: none;
    border: none;
    padding: 0;
    margin-top: 6px;
    color: var(--accent);
    font-size: 0.82rem;
    cursor: pointer;
    font-family: inherit;
}

.auth-forgot-link:hover {
    color: var(--accent-dark);
    text-decoration: underline;
}

.auth-terms-row {
    margin-top: 10px;
}

.auth-checkbox-label {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    font-size: 0.82rem;
    color: var(--text-secondary);
    line-height: 1.4;
    cursor: pointer;
}

.auth-checkbox-label input[type="checkbox"] {
    margin-top: 2px;
    flex-shrink: 0;
}

.auth-checkbox-label a {
    color: var(--accent);
}

/* Account modal */
.account-email {
    color: var(--text-secondary);
    margin: 0 0 24px;
    word-break: break-all;
}

.account-danger-zone {
    border: 1px solid #e6b3b3;
    background: #fff5f5;
    padding: 16px 18px;
}

.account-danger-zone h4 {
    margin: 0 0 8px;
    color: #b23b3b;
    font-size: 0.95rem;
}

.account-danger-zone p {
    margin: 0 0 14px;
    font-size: 0.85rem;
    color: var(--text-secondary);
    line-height: 1.5;
}

.account-delete-btn {
    background: #d33f3f;
    border-color: #d33f3f;
}

.account-delete-btn:hover:not(:disabled) {
    background: #b23b3b;
    border-color: #b23b3b;
}

.account-delete-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    transform: none !important;
    box-shadow: none !important;
}

.account-delete-confirm {
    margin-top: 12px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.account-delete-confirm label {
    font-size: 0.82rem;
    color: var(--text-secondary);
}

.account-delete-confirm input {
    padding: 8px 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    font-family: inherit;
}

.account-delete-status {
    margin: 10px 0 0;
    font-size: 0.85rem;
    color: #d33f3f;
}

.auth-mode-toggle {
    display: block;
    width: 100%;
    text-align: center;
    margin-top: 16px;
    background: none;
    border: none;
    color: var(--accent);
    cursor: pointer;
    font-size: 0.9rem;
}

/* Home page content (hero through contact) moved to portfolio.css, scoped to
   .portfolio-main with its own "Engineering Blueprint" dark theme tokens — see that file.
   Kept out of :root here since privacy.html/terms.html/reset-password.html still use these
   shared light tokens directly for their own plain content. */

/* ---------------------------------------------------------------------
   Site footer — shared by every page.

   It used to be styled only in portfolio.css, which only index.html loads, so the other five
   pages shipped the same <footer class="site-footer"> markup and rendered it with browser
   defaults: rgb(0,0,238) underlined links, no padding, left-aligned — and on game.html's
   near-black ground the inherited near-black ink was effectively invisible. Styling it here
   fixes all five at once (the now-duplicate rules were deleted from portfolio.css).

   It reuses the masthead's own --header-* tokens (declared on the shared selector list at the
   top of this file) so the page is bookended by one chrome color rather than the footer
   quietly picking up whatever theme the page above it happens to run.

   Full-bleed: the <footer> now sits *outside* .container in every page's markup, so the dark
   ground reaches the viewport edges instead of being a boxed 1200px strip with page ground
   showing either side on wide screens. .footer-inner re-establishes that same 1200px measure
   for the content, so the columns still line up with the page above. No width:100vw — that
   reintroduces a horizontal scrollbar wherever a vertical one is present.
   --------------------------------------------------------------------- */
.site-footer {
    /* .background-animation is position:fixed at z-index:1, and .container sits above it at
       z-index:2. Now that the footer lives outside .container it needs its own positioned
       stacking above the shapes — otherwise they'd float over the footer and swallow clicks
       on its links. */
    position: relative;
    z-index: 2;
    background: var(--header-bg);
    border-top: 1px solid var(--header-border);
    color: var(--header-text-muted);
    font-size: 0.9rem;
    padding: 56px 40px 26px;
}

.footer-inner {
    max-width: 1200px;
    margin: 0 auto;
}

.footer-grid {
    display: grid;
    grid-template-columns: 1.6fr 1fr 1.1fr;
    gap: 36px 32px;
}

.footer-brand {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    /* keeps the link's hit area past 40px tall around the 36px seal */
    padding: 3px 0;
    text-decoration: none;
    color: var(--header-text);
}

.footer-brand .brand-seal {
    width: 36px;
    height: 36px;
    font-size: 1.2rem;
}

.footer-brand-name {
    font-family: var(--font-display);
    font-size: 1.05rem;
    font-weight: 600;
    line-height: 1.2;
}

.footer-blurb {
    margin: 14px 0 0;
    max-width: 34ch;
    font-size: 0.86rem;
    line-height: 1.65;
    color: var(--header-text-muted);
}

.footer-heading {
    margin: 0 0 14px;
    font-family: var(--font-body);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--header-accent);
}

.footer-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.site-footer a {
    color: var(--header-text);
    text-decoration: none;
    transition: color 0.2s ease;
}

.site-footer a:hover {
    color: var(--header-accent);
    text-decoration: underline;
}

.footer-list a {
    display: inline-block;
    padding: 7px 0;
}

.footer-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px 24px;
    margin-top: 40px;
    padding-top: 18px;
    border-top: 1px solid var(--header-border);
}

.footer-copy {
    margin: 0;
    font-size: 0.84rem;
    color: var(--header-text-muted);
}

.site-footer .footer-links {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 22px;
    font-size: 0.84rem;
}

.site-footer .footer-links a {
    display: inline-block;
    padding: 6px 0;
}

/* ---------------------------------------------------------------------
   Responsive chrome
   --------------------------------------------------------------------- */
/* Intermediate step: the full brand text plus four label-sized nav items plus the account
   trigger still fit under ~1080px, but only once the bar's own padding and type tighten. */
@media (max-width: 1080px) {
    .header {
        padding: 0 20px;
        gap: 12px;
    }

    .nav-trigger {
        padding: 0 10px;
        font-size: 0.86rem;
    }

    .brand-name {
        font-size: 0.92rem;
    }
}

/* Narrow widths: a single row holding brand + 4 nav items + account will not fit a 360px
   phone, so the brand drops to just its 言 seal (still the link home) and the nav itself
   becomes the scrolling element. .header-nav gets min-width:0 + flex:1 so it can shrink
   below its content width instead of forcing the bar — and therefore the page — wider. */
@media (max-width: 860px) {
    .header {
        min-height: 56px;
        padding: 0 12px;
        gap: 8px;
    }

    .brand-text {
        display: none;
    }

    .header-nav {
        flex: 1 1 auto;
        min-width: 0;
        margin: 0;
        /* a little breathing room so a mid-scroll clipped label doesn't butt straight up
           against the account avatar */
        padding-right: 6px;
        overflow-x: auto;
        overflow-y: hidden;
        scrollbar-width: thin;
        scrollbar-color: var(--header-border) transparent;
        -webkit-overflow-scrolling: touch;
    }

    .header-nav::-webkit-scrollbar {
        height: 3px;
    }

    .header-nav::-webkit-scrollbar-track {
        background: transparent;
    }

    .header-nav::-webkit-scrollbar-thumb {
        background: var(--header-border);
    }

    .nav-trigger {
        padding: 0 10px;
        font-size: 0.84rem;
    }

    /* overflow-x:auto on the nav makes overflow-y compute to auto too, which would clip the
       dropdowns inside the scrolling strip. position:fixed takes them out of that clip
       entirely (no ancestor here creates a containing block for fixed elements) and turns
       them into full-width sheets pinned under the 56px bar. */
    .nav-dropdown {
        position: fixed;
        top: 56px;
        left: 0;
        right: 0;
        min-width: 0;
    }

    .site-footer {
        padding: 44px 20px 22px;
    }

    .footer-grid {
        grid-template-columns: 1fr 1fr;
        gap: 30px 24px;
    }
}

@media (max-width: 560px) {
    .footer-grid {
        grid-template-columns: 1fr;
        gap: 28px;
    }

    .footer-bar {
        flex-direction: column;
        align-items: flex-start;
    }

    /* Roomier tap targets once the links are the only thing in a column — 11px of padding
       around a ~19px line box clears the ~40px minimum. */
    .footer-list a,
    .site-footer .footer-links a {
        padding: 11px 0;
    }
}

/* ---------------------------------------------------------------------
   JLPT level color system — shared across every page that shows level
   cards (Word Match, Phonetics Family) or a level dropdown (the header
   nav), via [data-level] / [href*="level="] attributes set in each
   page's own JS/HTML rather than duplicating this block per stylesheet.
   Colors come from --jlpt-n5..--jlpt-n1 defined in :root above.
   --------------------------------------------------------------------- */
.level-card[data-level="N5"] .level-badge { background: var(--jlpt-n5-tint); color: var(--jlpt-n5); }
.level-card[data-level="N4"] .level-badge { background: var(--jlpt-n4-tint); color: var(--jlpt-n4); }
.level-card[data-level="N3"] .level-badge { background: var(--jlpt-n3-tint); color: var(--jlpt-n3); }
.level-card[data-level="N2"] .level-badge { background: var(--jlpt-n2-tint); color: var(--jlpt-n2); }
.level-card[data-level="N1"] .level-badge { background: var(--jlpt-n1-tint); color: var(--jlpt-n1); }

.level-card[data-level="N5"] { border-top: 3px solid var(--jlpt-n5); }
.level-card[data-level="N4"] { border-top: 3px solid var(--jlpt-n4); }
.level-card[data-level="N3"] { border-top: 3px solid var(--jlpt-n3); }
.level-card[data-level="N2"] { border-top: 3px solid var(--jlpt-n2); }
.level-card[data-level="N1"] { border-top: 3px solid var(--jlpt-n1); }

.level-card[data-level="N5"]:hover { border-color: var(--jlpt-n5); }
.level-card[data-level="N4"]:hover { border-color: var(--jlpt-n4); }
.level-card[data-level="N3"]:hover { border-color: var(--jlpt-n3); }
.level-card[data-level="N2"]:hover { border-color: var(--jlpt-n2); }
.level-card[data-level="N1"]:hover { border-color: var(--jlpt-n1); }

/* Header nav dropdown ("Word Game" -> N5..N1): a colored left rule per
   level link, matching the same spectrum, so the dropdown itself hints
   at difficulty before a card is ever opened. */
.nav-dropdown a[href*="level=1"] { border-left-color: var(--jlpt-n5); }
.nav-dropdown a[href*="level=2"] { border-left-color: var(--jlpt-n4); }
.nav-dropdown a[href*="level=3"] { border-left-color: var(--jlpt-n3); }
.nav-dropdown a[href*="level=4"] { border-left-color: var(--jlpt-n2); }
.nav-dropdown a[href*="level=5"] { border-left-color: var(--jlpt-n1); }

/* The light pastel --jlpt-*-tint backgrounds were designed for the site's light pages — on the
   header's own dark panel they'd read as a washed-out pale patch, so hover uses a low-opacity
   mix of the level's own hue against the dark panel instead, keeping the same per-level color
   language without fighting the masthead's own palette. */
.nav-dropdown a[href*="level=1"]:hover { background: color-mix(in srgb, var(--jlpt-n5) 22%, transparent); border-left-color: var(--jlpt-n5); color: var(--jlpt-n5); }
.nav-dropdown a[href*="level=2"]:hover { background: color-mix(in srgb, var(--jlpt-n4) 22%, transparent); border-left-color: var(--jlpt-n4); color: var(--jlpt-n4); }
.nav-dropdown a[href*="level=3"]:hover { background: color-mix(in srgb, var(--jlpt-n3) 22%, transparent); border-left-color: var(--jlpt-n3); color: var(--jlpt-n3); }
.nav-dropdown a[href*="level=4"]:hover { background: color-mix(in srgb, var(--jlpt-n2) 22%, transparent); border-left-color: var(--jlpt-n2); color: var(--jlpt-n2); }
.nav-dropdown a[href*="level=5"]:hover { background: color-mix(in srgb, var(--jlpt-n1) 22%, transparent); border-left-color: var(--jlpt-n1); color: var(--jlpt-n1); }
